Skip to content

Commit 532ade3

Browse files
committed
Merge branch 'gvn-borrowed'
2 parents 0b3a2e8 + f5def50 commit 532ade3

File tree

50 files changed

+1787
-1461
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1787
-1461
lines changed

compiler/rustc_const_eval/src/interpret/cast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
416416
}
417417
}
418418

419-
fn unsize_into(
419+
pub fn unsize_into(
420420
&mut self,
421421
src: &OpTy<'tcx, M::Provenance>,
422422
cast_ty: TyAndLayout<'tcx>,

compiler/rustc_mir_transform/src/copy_prop.rs

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,9 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
112112

113113
fn visit_local(&mut self, local: &mut Local, ctxt: PlaceContext, _: Location) {
114114
let new_local = self.copy_classes[*local];
115+
if self.borrowed_locals.contains(*local) {
116+
return;
117+
}
115118
match ctxt {
116119
// Do not modify the local in storage statements.
117120
PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) => {}
@@ -122,32 +125,16 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
122125
}
123126
}
124127

125-
fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) {
128+
fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, loc: Location) {
126129
if let Some(new_projection) = self.process_projection(place.projection, loc) {
127130
place.projection = self.tcx().mk_place_elems(&new_projection);
128131
}
129132

130-
let observes_address = match ctxt {
131-
PlaceContext::NonMutatingUse(
132-
NonMutatingUseContext::SharedBorrow
133-
| NonMutatingUseContext::FakeBorrow
134-
| NonMutatingUseContext::AddressOf,
135-
) => true,
136-
// For debuginfo, merging locals is ok.
137-
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {
138-
self.borrowed_locals.contains(place.local)
139-
}
140-
_ => false,
141-
};
142-
if observes_address && !place.is_indirect() {
143-
// We observe the address of `place.local`. Do not replace it.
144-
} else {
145-
self.visit_local(
146-
&mut place.local,
147-
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
148-
loc,
149-
)
150-
}
133+
self.visit_local(
134+
&mut place.local,
135+
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
136+
loc,
137+
)
151138
}
152139

153140
fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {

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(

compiler/rustc_mir_transform/src/gvn.rs

Lines changed: 139 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ use rustc_index::IndexVec;
9393
use rustc_middle::mir::interpret::GlobalAlloc;
9494
use rustc_middle::mir::visit::*;
9595
use rustc_middle::mir::*;
96-
use rustc_middle::ty::adjustment::PointerCoercion;
9796
use rustc_middle::ty::layout::LayoutOf;
9897
use rustc_middle::ty::{self, Ty, TyCtxt, TypeAndMut};
9998
use rustc_span::def_id::DefId;
@@ -154,6 +153,9 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
154153
state.next_opaque = None;
155154

156155
let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec();
156+
for dbg in body.var_debug_info.iter_mut() {
157+
state.visit_var_debug_info(dbg);
158+
}
157159
for bb in reverse_postorder {
158160
let data = &mut body.basic_blocks.as_mut_preserves_cfg()[bb];
159161
state.visit_basic_block_data(bb, data);
@@ -551,6 +553,29 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
551553
}
552554
value.offset(Size::ZERO, to, &self.ecx).ok()?
553555
}
556+
CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) => {
557+
let src = self.evaluated[value].as_ref()?;
558+
let to = self.ecx.layout_of(to).ok()?;
559+
let dest = self.ecx.allocate(to, MemoryKind::Stack).ok()?;
560+
self.ecx.unsize_into(src, to, &dest.clone().into()).ok()?;
561+
self.ecx
562+
.alloc_mark_immutable(dest.ptr().provenance.unwrap().alloc_id())
563+
.ok()?;
564+
dest.into()
565+
}
566+
CastKind::FnPtrToPtr
567+
| CastKind::PtrToPtr
568+
| CastKind::PointerCoercion(
569+
ty::adjustment::PointerCoercion::MutToConstPointer
570+
| ty::adjustment::PointerCoercion::ArrayToPointer
571+
| ty::adjustment::PointerCoercion::UnsafeFnPointer,
572+
) => {
573+
let src = self.evaluated[value].as_ref()?;
574+
let src = self.ecx.read_immediate(src).ok()?;
575+
let to = self.ecx.layout_of(to).ok()?;
576+
let ret = self.ecx.ptr_to_ptr(&src, to).ok()?;
577+
ret.into()
578+
}
554579
_ => return None,
555580
},
556581
};
@@ -698,6 +723,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
698723
// Invariant: `value` holds the value up-to the `index`th projection excluded.
699724
let mut value = self.locals[place.local]?;
700725
for (index, proj) in place.projection.iter().enumerate() {
726+
if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value)
727+
&& let Value::Address { place: mut pointee, kind, .. } = *self.get(pointer)
728+
&& let AddressKind::Ref(BorrowKind::Shared) = kind
729+
&& let Some(v) = self.simplify_place_value(&mut pointee, location)
730+
{
731+
value = v;
732+
place_ref = pointee.project_deeper(&place.projection[index..], self.tcx).as_ref();
733+
}
701734
if let Some(local) = self.try_as_local(value, location) {
702735
// Both `local` and `Place { local: place.local, projection: projection[..index] }`
703736
// hold the same value. Therefore, following place holds the value in the original
@@ -709,6 +742,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
709742
value = self.project(base, value, proj)?;
710743
}
711744

745+
if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value)
746+
&& let Value::Address { place: mut pointee, kind, .. } = *self.get(pointer)
747+
&& let AddressKind::Ref(BorrowKind::Shared) = kind
748+
&& let Some(v) = self.simplify_place_value(&mut pointee, location)
749+
{
750+
value = v;
751+
place_ref = pointee.project_deeper(&[], self.tcx).as_ref();
752+
}
712753
if let Some(new_local) = self.try_as_local(value, location) {
713754
place_ref = PlaceRef { local: new_local, projection: &[] };
714755
}
@@ -777,18 +818,8 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
777818

778819
// Operations.
779820
Rvalue::Len(ref mut place) => return self.simplify_len(place, location),
780-
Rvalue::Cast(kind, ref mut value, to) => {
781-
let from = value.ty(self.local_decls, self.tcx);
782-
let value = self.simplify_operand(value, location)?;
783-
if let CastKind::PointerCoercion(
784-
PointerCoercion::ReifyFnPointer | PointerCoercion::ClosureFnPointer(_),
785-
) = kind
786-
{
787-
// Each reification of a generic fn may get a different pointer.
788-
// Do not try to merge them.
789-
return self.new_opaque();
790-
}
791-
Value::Cast { kind, value, from, to }
821+
Rvalue::Cast(ref mut kind, ref mut value, to) => {
822+
return self.simplify_cast(kind, value, to, location);
792823
}
793824
Rvalue::BinaryOp(op, box (ref mut lhs, ref mut rhs)) => {
794825
let ty = lhs.ty(self.local_decls, self.tcx);
@@ -876,6 +907,12 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
876907
}
877908
}
878909

910+
let fields: Option<Vec<_>> = fields
911+
.iter_mut()
912+
.map(|op| self.simplify_operand(op, location).or_else(|| self.new_opaque()))
913+
.collect();
914+
let fields = fields?;
915+
879916
let (ty, variant_index) = match *kind {
880917
AggregateKind::Array(..) => {
881918
assert!(!fields.is_empty());
@@ -895,12 +932,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
895932
AggregateKind::Adt(_, _, _, _, Some(_)) => return None,
896933
};
897934

898-
let fields: Option<Vec<_>> = fields
899-
.iter_mut()
900-
.map(|op| self.simplify_operand(op, location).or_else(|| self.new_opaque()))
901-
.collect();
902-
let fields = fields?;
903-
904935
if let AggregateTy::Array = ty
905936
&& fields.len() > 4
906937
{
@@ -1031,6 +1062,50 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
10311062
}
10321063
}
10331064

1065+
fn simplify_cast(
1066+
&mut self,
1067+
kind: &mut CastKind,
1068+
operand: &mut Operand<'tcx>,
1069+
to: Ty<'tcx>,
1070+
location: Location,
1071+
) -> Option<VnIndex> {
1072+
use rustc_middle::ty::adjustment::PointerCoercion::*;
1073+
use CastKind::*;
1074+
1075+
let mut from = operand.ty(self.local_decls, self.tcx);
1076+
let mut value = self.simplify_operand(operand, location)?;
1077+
if from == to {
1078+
return Some(value);
1079+
}
1080+
1081+
if let CastKind::PointerCoercion(ReifyFnPointer | ClosureFnPointer(_)) = kind {
1082+
// Each reification of a generic fn may get a different pointer.
1083+
// Do not try to merge them.
1084+
return self.new_opaque();
1085+
}
1086+
1087+
if let PtrToPtr | PointerCoercion(MutToConstPointer) = kind
1088+
&& let Value::Cast { kind: inner_kind, value: inner_value, from: inner_from, to: _ } =
1089+
*self.get(value)
1090+
&& let PtrToPtr | PointerCoercion(MutToConstPointer) = inner_kind
1091+
{
1092+
from = inner_from;
1093+
value = inner_value;
1094+
*kind = PtrToPtr;
1095+
if inner_from == to {
1096+
return Some(inner_value);
1097+
}
1098+
if let Some(const_) = self.try_as_constant(value) {
1099+
*operand = Operand::Constant(Box::new(const_));
1100+
} else if let Some(local) = self.try_as_local(value, location) {
1101+
*operand = Operand::Copy(local.into());
1102+
self.reused_locals.insert(local);
1103+
}
1104+
}
1105+
1106+
Some(self.insert(Value::Cast { kind: *kind, value, from, to }))
1107+
}
1108+
10341109
fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option<VnIndex> {
10351110
// Trivial case: we are fetching a statically known length.
10361111
let place_ty = place.ty(self.local_decls, self.tcx).ty;
@@ -1178,6 +1253,51 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
11781253
self.tcx
11791254
}
11801255

1256+
fn visit_var_debug_info(&mut self, var_debug_info: &mut VarDebugInfo<'tcx>) {
1257+
let mut replace_dereffed = |place: &mut Place<'tcx>| -> Option<!> {
1258+
let last_deref = place.projection.iter().rposition(|e| e == PlaceElem::Deref)?;
1259+
1260+
// Another place that holds the same value.
1261+
let mut place_ref = place.as_ref();
1262+
let mut value = self.locals[place.local]?;
1263+
1264+
for (index, &proj) in place.projection[..last_deref].iter().enumerate() {
1265+
if let Some(candidates) = self.rev_locals.get(value)
1266+
&& let Some(&local) = candidates.first()
1267+
{
1268+
place_ref = PlaceRef { local, projection: &place.projection[index..] };
1269+
}
1270+
1271+
let place_upto =
1272+
PlaceRef { local: place.local, projection: &place.projection[..index] };
1273+
if let Some(projected) = self.project(place_upto, value, proj) {
1274+
value = projected;
1275+
} else {
1276+
if place_ref.projection.len() < place.projection.len() {
1277+
*place = place_ref.project_deeper(&[], self.tcx);
1278+
}
1279+
return None;
1280+
}
1281+
}
1282+
1283+
if let Some(candidates) = self.rev_locals.get(value)
1284+
&& let Some(&local) = candidates.first()
1285+
{
1286+
let place_ref = PlaceRef { local, projection: &place.projection[last_deref..] };
1287+
*place = place_ref.project_deeper(&[], self.tcx);
1288+
}
1289+
1290+
return None;
1291+
};
1292+
1293+
match &mut var_debug_info.value {
1294+
VarDebugInfoContents::Const(_) => {}
1295+
VarDebugInfoContents::Place(place) => {
1296+
replace_dereffed(place);
1297+
}
1298+
}
1299+
}
1300+
11811301
fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, location: Location) {
11821302
self.simplify_place_projection(place, location);
11831303
}

compiler/rustc_mir_transform/src/ssa.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,7 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'tcx, '_> {
235235
// Anything can happen with raw pointers, so remove them.
236236
// We do not verify that all uses of the borrow dominate the assignment to `local`,
237237
// so we have to remove them too.
238-
PlaceContext::NonMutatingUse(
239-
NonMutatingUseContext::SharedBorrow
240-
| NonMutatingUseContext::FakeBorrow
241-
| NonMutatingUseContext::AddressOf,
242-
)
238+
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
243239
| PlaceContext::MutatingUse(_) => {
244240
self.assignments[local] = Set1::Many;
245241
}

tests/coverage/issue-83601.cov-map

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@ Number of file 0 mappings: 1
1515
- Code(Counter(0)) at (prev + 3, 10) to (start + 0, 15)
1616

1717
Function name: issue_83601::main
18-
Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 06, 01, 02, 1c, 05, 03, 09, 01, 1c, 02, 02, 05, 03, 02]
18+
Raw bytes (21): 0x[01, 01, 01, 05, 00, 03, 01, 06, 01, 02, 1c, 05, 03, 09, 01, 1c, 02, 02, 05, 03, 02]
1919
Number of files: 1
2020
- file 0 => global file 1
2121
Number of expressions: 1
22-
- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
22+
- expression 0 operands: lhs = Counter(1), rhs = Zero
2323
Number of file 0 mappings: 3
2424
- Code(Counter(0)) at (prev + 6, 1) to (start + 2, 28)
2525
- Code(Counter(1)) at (prev + 3, 9) to (start + 1, 28)
2626
- Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 3, 2)
27-
= (c1 - c2)
27+
= (c1 - Zero)
2828

0 commit comments

Comments
 (0)