| //@ compile-flags: -Zlint-mir=no |
| //@ test-mir-pass: ReferencePropagation |
| //@ needs-unwind |
| |
| #![feature(core_intrinsics, custom_mir)] |
| |
| #[inline(never)] |
| fn opaque(_: impl Sized) {} |
| |
| fn reference_propagation<'a, T: Copy>(single: &'a T, mut multiple: &'a T) { |
| // CHECK-LABEL: fn reference_propagation( |
| |
| // Propagation through a reference. |
| { |
| // CHECK: bb0: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &[[a]]; |
| // CHECK: [[c:_.*]] = copy [[a]]; |
| |
| let a = 5_usize; |
| let b = &a; // This borrow is only used once. |
| let c = *b; // This should be optimized. |
| opaque(()); // We use opaque to separate cases into basic blocks in the MIR. |
| } |
| |
| // Propagation through two references. |
| { |
| // CHECK: bb1: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[a2:_.*]] = const 7_usize; |
| // CHECK: [[b:_.*]] = &[[a]]; |
| // CHECK: [[btmp:_.*]] = &[[a2]]; |
| // CHECK: [[b]] = move [[btmp]]; |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let a = 5_usize; |
| let a2 = 7_usize; |
| let mut b = &a; |
| b = &a2; |
| // `b` is assigned twice, so we cannot propagate it. |
| let c = *b; |
| opaque(()); |
| } |
| |
| // Propagation through a borrowed reference. |
| { |
| // CHECK: bb2: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &[[a]]; |
| // CHECK: [[d:_.*]] = &[[b]]; |
| // CHECK: [[c:_.*]] = copy [[a]]; |
| |
| let a = 5_usize; |
| let b = &a; |
| let d = &b; |
| let c = *b; // `b` is immutably borrowed, we know its value, but do not propagate it |
| opaque(d); // prevent `d` from being removed. |
| } |
| |
| // Propagation through a mutably borrowed reference. |
| { |
| // CHECK: bb3: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &[[a]]; |
| // CHECK: [[d:_.*]] = &raw mut [[b]]; |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let a = 5_usize; |
| let mut b = &a; |
| let d = &raw mut b; |
| let c = *b; // `b` is mutably borrowed, we cannot know its value. |
| opaque(d); // prevent `d` from being removed. |
| } |
| |
| // Propagation through an escaping borrow. |
| { |
| // CHECK: bb4: { |
| // CHECK: [[a:_.*]] = const 7_usize; |
| // CHECK: [[b:_.*]] = &[[a]]; |
| // CHECK: [[c:_.*]] = copy [[a]]; |
| |
| let a = 7_usize; |
| let b = &a; |
| let c = *b; |
| opaque(b); // `b` escapes here, but we can still replace immutable borrow |
| } |
| |
| // Propagation through a transitively escaping borrow. |
| { |
| // CHECK: bb5: { |
| // CHECK: [[a:_.*]] = const 7_usize; |
| // CHECK: [[b1:_.*]] = &[[a]]; |
| // CHECK: [[c:_.*]] = copy [[a]]; |
| // CHECK: [[b2:_.*]] = copy [[b1]]; |
| // CHECK: [[c2:_.*]] = copy [[a]]; |
| // CHECK: [[b3:_.*]] = copy [[b2]]; |
| |
| let a = 7_usize; |
| let b1 = &a; |
| let c = *b1; |
| let b2 = b1; |
| let c2 = *b2; |
| let b3 = b2; |
| // `b3` escapes here, so we can only replace immutable borrow, |
| // for either `b`, `b2` or `b3`. |
| opaque(b3); |
| } |
| |
| // Propagation a reborrow of an argument. |
| { |
| // CHECK: bb6: { |
| // CHECK-NOT: {{_.*}} = &(*_1); |
| // CHECK: [[b:_.*]] = copy (*_1); |
| |
| let a = &*single; |
| let b = *a; // This should be optimized as `*single`. |
| opaque(()); |
| } |
| |
| // Propagation a reborrow of a mutated argument. |
| { |
| // CHECK: bb7: { |
| // CHECK: [[a:_.*]] = &(*_2); |
| // CHECK: [[tmp:_.*]] = &(*_1); |
| // CHECK: _2 = move [[tmp]]; |
| // CHECK: [[b:_.*]] = copy (*[[a]]); |
| |
| let a = &*multiple; |
| multiple = &*single; |
| let b = *a; // This should not be optimized. |
| opaque(()); |
| } |
| |
| // Fixed-point propagation through a borrowed reference. |
| { |
| // CHECK: bb8: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &[[a]]; |
| // CHECK: [[d:_.*]] = &[[b]]; |
| // CHECK: [[c:_.*]] = copy [[a]]; |
| |
| let a = 5_usize; |
| let b = &a; |
| let d = &b; // first round promotes debuginfo for `d` |
| let c = *b; // second round propagates this dereference |
| opaque(()); |
| } |
| |
| // Fixed-point propagation through a mutably borrowed reference. |
| { |
| // CHECK: bb9: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &[[a]]; |
| // CHECK: [[d:_.*]] = &mut [[b]]; |
| // FIXME this could be [[a]] |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let a = 5_usize; |
| let mut b = &a; |
| let d = &mut b; // first round promotes debuginfo for `d` |
| let c = *b; // second round propagates this dereference |
| opaque(()); |
| } |
| } |
| |
| fn reference_propagation_mut<'a, T: Copy>(single: &'a mut T, mut multiple: &'a mut T) { |
| // CHECK-LABEL: fn reference_propagation_mut( |
| |
| // Propagation through a reference. |
| { |
| // CHECK: bb0: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &mut [[a]]; |
| // CHECK: [[c:_.*]] = copy [[a]]; |
| |
| let mut a = 5_usize; |
| let b = &mut a; // This borrow is only used once. |
| let c = *b; // This should be optimized. |
| opaque(()); |
| } |
| |
| // Propagation through two references. |
| { |
| // CHECK: bb1: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[a2:_.*]] = const 7_usize; |
| // CHECK: [[b:_.*]] = &mut [[a]]; |
| // CHECK: [[btmp:_.*]] = &mut [[a2]]; |
| // CHECK: [[b]] = move [[btmp]]; |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let mut a = 5_usize; |
| let mut a2 = 7_usize; |
| let mut b = &mut a; |
| b = &mut a2; |
| // `b` is assigned twice, so we cannot propagate it. |
| let c = *b; |
| opaque(()); |
| } |
| |
| // Propagation through a borrowed reference. |
| { |
| // CHECK: bb2: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &mut [[a]]; |
| // CHECK: [[d:_.*]] = &[[b]]; |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let mut a = 5_usize; |
| let b = &mut a; |
| let d = &b; |
| let c = *b; // `b` is immutably borrowed, we know its value, but cannot be removed. |
| opaque(d); // prevent `d` from being removed. |
| } |
| |
| // Propagation through a mutably borrowed reference. |
| { |
| // CHECK: bb3: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &mut [[a]]; |
| // CHECK: [[d:_.*]] = &raw mut [[b]]; |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let mut a = 5_usize; |
| let mut b = &mut a; |
| let d = &raw mut b; |
| let c = *b; // `b` is mutably borrowed, we cannot know its value. |
| opaque(d); // prevent `d` from being removed. |
| } |
| |
| // Propagation through an escaping borrow. |
| { |
| // CHECK: bb4: { |
| // CHECK: [[a:_.*]] = const 7_usize; |
| // CHECK: [[b:_.*]] = &mut [[a]]; |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let mut a = 7_usize; |
| let b = &mut a; |
| let c = *b; |
| opaque(b); // `b` escapes here, so we can only replace immutable borrow |
| } |
| |
| // Propagation through a transitively escaping borrow. |
| { |
| // CHECK: bb5: { |
| // CHECK: [[a:_.*]] = const 7_usize; |
| // CHECK: [[b1:_.*]] = &mut [[a]]; |
| // CHECK: [[c:_.*]] = copy (*[[b1]]); |
| // CHECK: [[b2:_.*]] = move [[b1]]; |
| // CHECK: [[c2:_.*]] = copy (*[[b2]]); |
| // CHECK: [[b3:_.*]] = move [[b2]]; |
| |
| let mut a = 7_usize; |
| let b1 = &mut a; |
| let c = *b1; |
| let b2 = b1; |
| let c2 = *b2; |
| let b3 = b2; |
| // `b3` escapes here, so we can only replace immutable borrow, |
| // for either `b`, `b2` or `b3`. |
| opaque(b3); |
| } |
| |
| // Propagation a reborrow of an argument. |
| { |
| // CHECK: bb6: { |
| // CHECK-NOT: {{_.*}} = &(*_1); |
| // CHECK: [[b:_.*]] = copy (*_1); |
| |
| let a = &mut *single; |
| let b = *a; // This should be optimized as `*single`. |
| opaque(()); |
| } |
| |
| // Propagation a reborrow of a mutated argument. |
| { |
| // CHECK: bb7: { |
| // CHECK: [[a:_.*]] = &mut (*_2); |
| // CHECK: [[tmp:_.*]] = &mut (*_1); |
| // CHECK: _2 = move [[tmp]]; |
| // CHECK: [[b:_.*]] = copy (*[[a]]); |
| |
| let a = &mut *multiple; |
| multiple = &mut *single; |
| let b = *a; // This should not be optimized. |
| opaque(()); |
| } |
| |
| // Fixed-point propagation through a borrowed reference. |
| { |
| // CHECK: bb8: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &mut [[a]]; |
| // CHECK: [[d:_.*]] = &[[b]]; |
| // FIXME this could be [[a]] |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let mut a = 5_usize; |
| let b = &mut a; |
| let d = &b; // first round promotes debuginfo for `d` |
| let c = *b; // second round propagates this dereference |
| opaque(()); |
| } |
| |
| // Fixed-point propagation through a mutably borrowed reference. |
| { |
| // CHECK: bb9: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &mut [[a]]; |
| // CHECK: [[d:_.*]] = &mut [[b]]; |
| // FIXME this could be [[a]] |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let mut a = 5_usize; |
| let mut b = &mut a; |
| let d = &mut b; // first round promotes debuginfo for `d` |
| let c = *b; // second round propagates this dereference |
| opaque(()); |
| } |
| } |
| |
| fn reference_propagation_const_ptr<T: Copy>(single: *const T, mut multiple: *const T) { |
| // CHECK-LABEL: fn reference_propagation_const_ptr( |
| |
| // Propagation through a reference. |
| unsafe { |
| // CHECK: bb0: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &raw const [[a]]; |
| // CHECK: [[c:_.*]] = copy [[a]]; |
| |
| let a = 5_usize; |
| let b = &raw const a; // This borrow is only used once. |
| let c = *b; // This should be optimized. |
| opaque(()); |
| } |
| |
| // Propagation through two references. |
| unsafe { |
| // CHECK: bb1: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[a2:_.*]] = const 7_usize; |
| // CHECK: [[b:_.*]] = &raw const [[a]]; |
| // CHECK: [[btmp:_.*]] = &raw const [[a2]]; |
| // CHECK: [[b]] = move [[btmp]]; |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let a = 5_usize; |
| let a2 = 7_usize; |
| let mut b = &raw const a; |
| b = &raw const a2; |
| // `b` is assigned twice, so we cannot propagate it. |
| let c = *b; |
| opaque(()); |
| } |
| |
| // Propagation through a borrowed reference. |
| unsafe { |
| // CHECK: bb2: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &raw const [[a]]; |
| // CHECK: [[d:_.*]] = &[[b]]; |
| // CHECK: [[c:_.*]] = copy [[a]]; |
| |
| let a = 5_usize; |
| let b = &raw const a; |
| let d = &b; |
| let c = *b; // `b` is immutably borrowed, we know its value, but cannot be removed. |
| opaque(d); // prevent `d` from being removed. |
| } |
| |
| // Propagation through a mutably borrowed reference. |
| unsafe { |
| // CHECK: bb3: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &raw const [[a]]; |
| // CHECK: [[d:_.*]] = &raw mut [[b]]; |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let a = 5_usize; |
| let mut b = &raw const a; |
| let d = &raw mut b; |
| let c = *b; // `b` is mutably borrowed, we cannot know its value. |
| opaque(d); // prevent `d` from being removed. |
| } |
| |
| // Propagation through an escaping borrow. |
| unsafe { |
| // CHECK: bb4: { |
| // CHECK: [[a:_.*]] = const 7_usize; |
| // CHECK: [[b:_.*]] = &raw const [[a]]; |
| // CHECK: [[c:_.*]] = copy [[a]]; |
| |
| let a = 7_usize; |
| let b = &raw const a; |
| let c = *b; |
| opaque(b); // `b` escapes here, so we can only replace immutable borrow |
| } |
| |
| // Propagation through a transitively escaping borrow. |
| unsafe { |
| // CHECK: bb5: { |
| // CHECK: [[a:_.*]] = const 7_usize; |
| // CHECK: [[b1:_.*]] = &raw const [[a]]; |
| // CHECK: [[c:_.*]] = copy [[a]]; |
| // CHECK: [[b2:_.*]] = copy [[b1]]; |
| // CHECK: [[c2:_.*]] = copy [[a]]; |
| // CHECK: [[b3:_.*]] = copy [[b2]]; |
| |
| let a = 7_usize; |
| let b1 = &raw const a; |
| let c = *b1; |
| let b2 = b1; |
| let c2 = *b2; |
| let b3 = b2; |
| // `b3` escapes here, so we can only replace immutable borrow, |
| // for either `b`, `b2` or `b3`. |
| opaque(b3); |
| } |
| |
| // Propagation a reborrow of an argument. |
| unsafe { |
| // CHECK: bb6: { |
| // CHECK-NOT: {{_.*}} = &(*_1); |
| // CHECK: [[b:_.*]] = copy (*_1); |
| |
| let a = &raw const *single; |
| let b = *a; // This should be optimized as `*single`. |
| opaque(()); |
| } |
| |
| // Propagation a reborrow of a mutated argument. |
| unsafe { |
| // CHECK: bb7: { |
| // CHECK: [[a:_.*]] = &raw const (*_2); |
| // CHECK: [[tmp:_.*]] = &raw const (*_1); |
| // CHECK: _2 = move [[tmp]]; |
| // CHECK: [[b:_.*]] = copy (*[[a]]); |
| |
| let a = &raw const *multiple; |
| multiple = &raw const *single; |
| let b = *a; // This should not be optimized. |
| opaque(()); |
| } |
| |
| // Propagation through a reborrow. |
| unsafe { |
| // CHECK: bb8: { |
| // CHECK: [[a:_.*]] = const 13_usize; |
| // CHECK: [[b:_.*]] = &raw const [[a]]; |
| // CHECK: [[d:_.*]] = &raw const [[a]]; |
| // CHECK: [[c:_.*]] = copy [[a]]; |
| |
| let a = 13_usize; |
| let b = &raw const a; |
| let c = &raw const *b; |
| let e = *c; |
| opaque(()); |
| } |
| |
| // Fixed-point propagation through a borrowed reference. |
| unsafe { |
| // CHECK: bb9: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &raw const [[a]]; |
| // CHECK: [[d:_.*]] = &[[b]]; |
| // CHECK: [[c:_.*]] = copy [[a]]; |
| |
| let a = 5_usize; |
| let b = &raw const a; |
| let d = &b; // first round promotes debuginfo for `d` |
| let c = *b; // second round propagates this dereference |
| opaque(()); |
| } |
| |
| // Fixed-point propagation through a borrowed reference. |
| unsafe { |
| // CHECK: bb10: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &raw const [[a]]; |
| // CHECK: [[d:_.*]] = &mut [[b]]; |
| // FIXME this could be [[a]] |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let a = 5_usize; |
| let mut b = &raw const a; |
| let d = &mut b; // first round promotes debuginfo for `d` |
| let c = *b; // second round propagates this dereference |
| opaque(()); |
| } |
| } |
| |
| fn reference_propagation_mut_ptr<T: Copy>(single: *mut T, mut multiple: *mut T) { |
| // CHECK-LABEL: fn reference_propagation_mut_ptr( |
| |
| // Propagation through a reference. |
| unsafe { |
| // CHECK: bb0: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &raw mut [[a]]; |
| // CHECK: [[c:_.*]] = copy [[a]]; |
| |
| let mut a = 5_usize; |
| let b = &raw mut a; // This borrow is only used once. |
| let c = *b; // This should be optimized. |
| opaque(()); |
| } |
| |
| // Propagation through two references. |
| unsafe { |
| // CHECK: bb1: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[a2:_.*]] = const 7_usize; |
| // CHECK: [[b:_.*]] = &raw mut [[a]]; |
| // CHECK: [[btmp:_.*]] = &raw mut [[a2]]; |
| // CHECK: [[b]] = move [[btmp]]; |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let mut a = 5_usize; |
| let mut a2 = 7_usize; |
| let mut b = &raw mut a; |
| b = &raw mut a2; |
| // `b` is assigned twice, so we cannot propagate it. |
| let c = *b; |
| opaque(()); |
| } |
| |
| // Propagation through a borrowed reference. |
| unsafe { |
| // CHECK: bb2: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &raw mut [[a]]; |
| // CHECK: [[d:_.*]] = &[[b]]; |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let mut a = 5_usize; |
| let b = &raw mut a; |
| let d = &b; |
| let c = *b; // `b` is immutably borrowed, we know its value, but cannot be removed. |
| opaque(d); // prevent `d` from being removed. |
| } |
| |
| // Propagation through a mutably borrowed reference. |
| unsafe { |
| // CHECK: bb3: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &raw mut [[a]]; |
| // CHECK: [[d:_.*]] = &raw mut [[b]]; |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let mut a = 5_usize; |
| let mut b = &raw mut a; |
| let d = &raw mut b; |
| let c = *b; // `b` is mutably borrowed, we cannot know its value. |
| opaque(d); // prevent `d` from being removed. |
| } |
| |
| // Propagation through an escaping borrow. |
| unsafe { |
| // CHECK: bb4: { |
| // CHECK: [[a:_.*]] = const 7_usize; |
| // CHECK: [[b:_.*]] = &raw mut [[a]]; |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let mut a = 7_usize; |
| let b = &raw mut a; |
| let c = *b; |
| opaque(b); // `b` escapes here, so we can only replace immutable borrow |
| } |
| |
| // Propagation through a transitively escaping borrow. |
| unsafe { |
| // CHECK: bb5: { |
| // CHECK: [[a:_.*]] = const 7_usize; |
| // CHECK: [[b1:_.*]] = &raw mut [[a]]; |
| // CHECK: [[c:_.*]] = copy (*[[b1]]); |
| // CHECK: [[b2:_.*]] = copy [[b1]]; |
| // CHECK: [[c2:_.*]] = copy (*[[b2]]); |
| // CHECK: [[b3:_.*]] = copy [[b2]]; |
| |
| let mut a = 7_usize; |
| let b1 = &raw mut a; |
| let c = *b1; |
| let b2 = b1; |
| let c2 = *b2; |
| let b3 = b2; |
| // `b3` escapes here, so we can only replace immutable borrow, |
| // for either `b`, `b2` or `b3`. |
| opaque(b3); |
| } |
| |
| // Propagation a reborrow of an argument. |
| unsafe { |
| // CHECK: bb6: { |
| // CHECK-NOT: {{_.*}} = &(*_1); |
| // CHECK: [[b:_.*]] = copy (*_1); |
| |
| let a = &raw mut *single; |
| let b = *a; // This should be optimized as `*single`. |
| opaque(()); |
| } |
| |
| // Propagation a reborrow of a mutated argument. |
| unsafe { |
| // CHECK: bb7: { |
| // CHECK: [[a:_.*]] = &raw mut (*_2); |
| // CHECK: [[tmp:_.*]] = &raw mut (*_1); |
| // CHECK: _2 = move [[tmp]]; |
| // CHECK: [[b:_.*]] = copy (*[[a]]); |
| |
| let a = &raw mut *multiple; |
| multiple = &raw mut *single; |
| let b = *a; // This should not be optimized. |
| opaque(()); |
| } |
| |
| // Fixed-point propagation through a borrowed reference. |
| unsafe { |
| // CHECK: bb8: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &raw mut [[a]]; |
| // CHECK: [[d:_.*]] = &[[b]]; |
| // FIXME this could be [[a]] |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let mut a = 5_usize; |
| let b = &raw mut a; |
| let d = &b; // first round promotes debuginfo for `d` |
| let c = *b; // second round propagates this dereference |
| opaque(()); |
| } |
| |
| // Fixed-point propagation through a mutably borrowed reference. |
| unsafe { |
| // CHECK: bb9: { |
| // CHECK: [[a:_.*]] = const 5_usize; |
| // CHECK: [[b:_.*]] = &raw mut [[a]]; |
| // CHECK: [[d:_.*]] = &mut [[b]]; |
| // FIXME this could be [[a]] |
| // CHECK: [[c:_.*]] = copy (*[[b]]); |
| |
| let mut a = 5_usize; |
| let mut b = &raw mut a; |
| let d = &mut b; // first round promotes debuginfo for `d` |
| let c = *b; // second round propagates this dereference |
| opaque(()); |
| } |
| } |
| |
| #[custom_mir(dialect = "runtime", phase = "post-cleanup")] |
| fn read_through_raw(x: &mut usize) -> usize { |
| // CHECK-LABEL: read_through_raw |
| // CHECK: bb0: { |
| // CHECK-NEXT: _0 = copy (*_1); |
| // CHECK-NEXT: _0 = copy (*_1); |
| // CHECK-NEXT: return; |
| |
| use std::intrinsics::mir::*; |
| mir! { |
| let r1: &mut usize; |
| let r2: &mut usize; |
| let p1: *mut usize; |
| let p2: *mut usize; |
| |
| { |
| r1 = &mut *x; |
| r2 = &mut *r1; |
| p1 = &raw mut *r1; |
| p2 = &raw mut *r2; |
| |
| RET = *p1; |
| RET = *p2; |
| Return() |
| } |
| } |
| } |
| |
| #[custom_mir(dialect = "runtime", phase = "post-cleanup")] |
| fn multiple_storage() { |
| // CHECK-LABEL: multiple_storage |
| // CHECK: _3 = copy (*_2); |
| |
| use std::intrinsics::mir::*; |
| mir! { |
| let x: i32; |
| { |
| StorageLive(x); |
| x = 5; |
| let z = &x; |
| StorageDead(x); |
| StorageLive(x); |
| // As there are multiple `StorageLive` statements for `x`, we cannot know if this `z`'s |
| // pointer address is the address of `x`, so do nothing. |
| let y = *z; |
| Call(RET = opaque(y), ReturnTo(retblock), UnwindContinue()) |
| } |
| |
| retblock = { |
| Return() |
| } |
| } |
| } |
| |
| #[custom_mir(dialect = "runtime", phase = "post-cleanup")] |
| fn dominate_storage() { |
| // CHECK-LABEL: dominate_storage |
| // CHECK: _5 = copy (*_2); |
| |
| use std::intrinsics::mir::*; |
| mir! { |
| let x: i32; |
| let r: &i32; |
| let c: i32; |
| let d: bool; |
| { Goto(bb0) } |
| bb0 = { |
| x = 5; |
| r = &x; |
| Goto(bb1) |
| } |
| bb1 = { |
| let c = *r; |
| Call(RET = opaque(c), ReturnTo(bb2), UnwindContinue()) |
| } |
| bb2 = { |
| StorageDead(x); |
| StorageLive(x); |
| let d = true; |
| match d { false => bb2, _ => bb0 } |
| } |
| } |
| } |
| |
| #[custom_mir(dialect = "runtime", phase = "post-cleanup")] |
| fn maybe_dead(m: bool) { |
| // CHECK-LABEL: fn maybe_dead( |
| // CHECK: (*_5) = const 7_i32; |
| |
| use std::intrinsics::mir::*; |
| mir! { |
| let x: i32; |
| let y: i32; |
| { |
| StorageLive(x); |
| StorageLive(y); |
| x = 5; |
| y = 5; |
| let a = &x; |
| let b = &mut y; |
| // As we don't replace `b` in `bb2`, we cannot replace it here either. |
| *b = 7; |
| // But this can still be replaced. |
| let u = *a; |
| match m { true => bb1, _ => bb2 } |
| } |
| bb1 = { |
| StorageDead(x); |
| StorageDead(y); |
| Call(RET = opaque(u), ReturnTo(bb2), UnwindContinue()) |
| } |
| bb2 = { |
| // As `x` may be `StorageDead`, `a` may be dangling, so we do nothing. |
| let z = *a; |
| Call(RET = opaque(z), ReturnTo(bb3), UnwindContinue()) |
| } |
| bb3 = { |
| // As `y` may be `StorageDead`, `b` may be dangling, so we do nothing. |
| // This implies that we also do not substitute `b` in `bb0`. |
| let t = *b; |
| Call(RET = opaque(t), ReturnTo(retblock), UnwindContinue()) |
| } |
| retblock = { |
| Return() |
| } |
| } |
| } |
| |
| fn mut_raw_then_mut_shr() -> (i32, i32) { |
| // CHECK-LABEL: fn mut_raw_then_mut_shr( |
| // CHECK-NOT: (*{{_.*}}) |
| |
| let mut x = 2; |
| let xref = &mut x; |
| let xraw = &mut *xref as *mut _; |
| let xshr = &*xref; |
| // Verify that we completely replace with `x` in both cases. |
| let a = *xshr; |
| unsafe { |
| *xraw = 4; |
| } |
| (a, x) |
| } |
| |
| fn unique_with_copies() { |
| // CHECK-LABEL: fn unique_with_copies( |
| // CHECK: [[a:_.*]] = const 0_i32; |
| // CHECK: [[x:_.*]] = &raw mut [[a]]; |
| // CHECK-NOT: [[a]] |
| // CHECK: [[tmp:_.*]] = copy (*[[x]]); |
| // CHECK-NEXT: opaque::<i32>(move [[tmp]]) |
| // CHECK-NOT: [[a]] |
| // CHECK: StorageDead([[a]]); |
| // CHECK-NOT: [[a]] |
| // CHECK: [[tmp:_.*]] = copy (*[[x]]); |
| // CHECK-NEXT: opaque::<i32>(move [[tmp]]) |
| |
| let y = { |
| let mut a = 0; |
| let x = &raw mut a; |
| // `*y` is not replacable below, so we must not replace `*x`. |
| unsafe { opaque(*x) }; |
| x |
| }; |
| // But rewriting as `*x` is ok. |
| unsafe { opaque(*y) }; |
| } |
| |
| fn debuginfo() { |
| // CHECK-LABEL: fn debuginfo( |
| // FIXME: This features waits for DWARF implicit pointers in LLVM. |
| // CHECK: debug ref_mut_u8 => _{{.*}}; |
| // CHECK: debug field => _{{.*}}; |
| // CHECK: debug reborrow => _{{.*}}; |
| // CHECK: debug variant_field => _{{.*}}; |
| // CHECK: debug constant_index => _{{.*}}; |
| // CHECK: debug subslice => _{{.*}}; |
| // CHECK: debug constant_index_from_end => _{{.*}}; |
| // CHECK: debug multiple_borrow => _{{.*}}; |
| |
| struct T(u8); |
| |
| let ref_mut_u8 = &mut 5_u8; |
| let field = &T(0).0; |
| |
| // Verify that we don't emit `&*` in debuginfo. |
| let reborrow = &*ref_mut_u8; |
| |
| match Some(0) { |
| None => {} |
| Some(ref variant_field) => {} |
| } |
| |
| // `constant_index_from_end` and `subslice` should not be promoted, as their value depends |
| // on the slice length. |
| if let [_, ref constant_index, subslice @ .., ref constant_index_from_end] = &[6; 10][..] {} |
| |
| let multiple_borrow = &&&mut T(6).0; |
| } |
| |
| fn many_debuginfo() { |
| // CHECK-LABEL: fn many_debuginfo( |
| // FIXME: This features waits for DWARF implicit pointers in LLVM. |
| // CHECK: debug many_borrow => _{{.*}}; |
| |
| let a = 0; |
| |
| // Verify that we do not ICE on deeply nested borrows. |
| let many_borrow = |
| &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& |
| &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& |
| &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& |
| &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& |
| &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&a; |
| } |
| |
| fn main() { |
| let mut x = 5_usize; |
| let mut y = 7_usize; |
| reference_propagation(&x, &y); |
| reference_propagation_mut(&mut x, &mut y); |
| reference_propagation_const_ptr(&raw const x, &raw const y); |
| reference_propagation_mut_ptr(&raw mut x, &raw mut y); |
| read_through_raw(&mut x); |
| multiple_storage(); |
| dominate_storage(); |
| maybe_dead(true); |
| mut_raw_then_mut_shr(); |
| unique_with_copies(); |
| debuginfo(); |
| many_debuginfo(); |
| } |
| |
| // EMIT_MIR reference_prop.reference_propagation.ReferencePropagation.diff |
| // EMIT_MIR reference_prop.reference_propagation_mut.ReferencePropagation.diff |
| // EMIT_MIR reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff |
| // EMIT_MIR reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff |
| // EMIT_MIR reference_prop.read_through_raw.ReferencePropagation.diff |
| // EMIT_MIR reference_prop.multiple_storage.ReferencePropagation.diff |
| // EMIT_MIR reference_prop.dominate_storage.ReferencePropagation.diff |
| // EMIT_MIR reference_prop.maybe_dead.ReferencePropagation.diff |
| // EMIT_MIR reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff |
| // EMIT_MIR reference_prop.unique_with_copies.ReferencePropagation.diff |
| // EMIT_MIR reference_prop.debuginfo.ReferencePropagation.diff |