mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-30 10:45:18 +00:00
79611d90b6
Added "copy" to Debug fmt for copy operands In MIR's debug mode (--emit mir) the printing for Operands is slightly inconsistent. The RValues - values on the right side of an Assign - are usually printed with their Operand when they are Places. Example: _2 = move _3 But for arguments, the operand is omitted. _2 = _1 I propose a change be made, to display the place with the operand. _2 = copy _1 Move and copy have different semantics, meaning this difference is important and helpful to the user. It also adds consistency to the pretty printing. -- EDIT -- Consider this example Rust program and its MIR output with the **updated pretty printer.** This was generated with the arguments --emit mir --crate-type lib -Zmir-opt-level=0 (Otherwise, it's optimised away since it's a junk program). ```rust fn main(foo: i32) { let v = 10; if v == 20 { foo; } else { v; } } ``` ```MIR // WARNING: This output format is intended for human consumers only // and is subject to change without notice. Knock yourself out. fn main(_1: i32) -> () { debug foo => _1; let mut _0: (); let _2: i32; let mut _3: bool; let mut _4: i32; let _5: i32; let _6: i32; scope 1 { debug v => _2; } bb0: { StorageLive(_2); _2 = const 10_i32; StorageLive(_3); StorageLive(_4); _4 = copy _2; _3 = Eq(move _4, const 20_i32); switchInt(move _3) -> [0: bb2, otherwise: bb1]; } bb1: { StorageDead(_4); StorageLive(_5); _5 = copy _1; StorageDead(_5); _0 = const (); goto -> bb3; } bb2: { StorageDead(_4); StorageLive(_6); _6 = copy _2; StorageDead(_6); _0 = const (); goto -> bb3; } bb3: { StorageDead(_3); StorageDead(_2); return; } } ``` In this example program, we can see that when we move a place, it is preceded by "move". e.g. ``` _3 = Eq(move _4, const 20_i32);```. However, when we copy a place such as ```_5 = _1;```, it is not preceded by the operand in the original printout. I propose to change the print to include the copy ```_5 = copy _1``` as in this example. Regarding the arguments part. When I originally submitted this PR, I was under the impression this only affected the print for arguments to a function, but actually, it affects anything that uses a copy. This is preferable anyway with regard to consistency. The PR is about making ```copy``` explicit.
1018 lines
33 KiB
Rust
1018 lines
33 KiB
Rust
//@ test-mir-pass: GVN
|
|
//@ compile-flags: -Zdump-mir-exclude-alloc-bytes
|
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
|
//@ only-64bit
|
|
|
|
#![feature(rustc_attrs)]
|
|
#![feature(custom_mir)]
|
|
#![feature(core_intrinsics)]
|
|
#![feature(freeze)]
|
|
#![allow(ambiguous_wide_pointer_comparisons)]
|
|
#![allow(unconditional_panic)]
|
|
#![allow(unused)]
|
|
|
|
use std::intrinsics::mir::*;
|
|
use std::marker::Freeze;
|
|
use std::mem::transmute;
|
|
|
|
struct S<T>(T);
|
|
|
|
fn subexpression_elimination(x: u64, y: u64, mut z: u64) {
|
|
// CHECK-LABEL: fn subexpression_elimination(
|
|
|
|
// CHECK: [[add:_.*]] = Add(copy _1, copy _2);
|
|
// CHECK: opaque::<u64>(copy [[add]])
|
|
opaque(x + y);
|
|
// CHECK: [[mul:_.*]] = Mul(copy _1, copy _2);
|
|
// CHECK: opaque::<u64>(copy [[mul]])
|
|
opaque(x * y);
|
|
// CHECK: [[sub:_.*]] = Sub(copy _1, copy _2);
|
|
// CHECK: opaque::<u64>(copy [[sub]])
|
|
opaque(x - y);
|
|
// CHECK: [[div:_.*]] = Div(copy _1, copy _2);
|
|
// CHECK: opaque::<u64>(copy [[div]])
|
|
opaque(x / y);
|
|
// CHECK: [[rem:_.*]] = Rem(copy _1, copy _2);
|
|
// CHECK: opaque::<u64>(copy [[rem]])
|
|
opaque(x % y);
|
|
// CHECK: [[and:_.*]] = BitAnd(copy _1, copy _2);
|
|
// CHECK: opaque::<u64>(copy [[and]])
|
|
opaque(x & y);
|
|
// CHECK: [[or:_.*]] = BitOr(copy _1, copy _2);
|
|
// CHECK: opaque::<u64>(copy [[or]])
|
|
opaque(x | y);
|
|
// CHECK: [[xor:_.*]] = BitXor(copy _1, copy _2);
|
|
// CHECK: opaque::<u64>(copy [[xor]])
|
|
opaque(x ^ y);
|
|
// CHECK: [[shl:_.*]] = Shl(copy _1, copy _2);
|
|
// CHECK: opaque::<u64>(copy [[shl]])
|
|
opaque(x << y);
|
|
// CHECK: [[shr:_.*]] = Shr(copy _1, copy _2);
|
|
// CHECK: opaque::<u64>(copy [[shr]])
|
|
opaque(x >> y);
|
|
// CHECK: [[int:_.*]] = copy _1 as u32 (IntToInt);
|
|
// CHECK: opaque::<u32>(copy [[int]])
|
|
opaque(x as u32);
|
|
// CHECK: [[float:_.*]] = copy _1 as f32 (IntToFloat);
|
|
// CHECK: opaque::<f32>(copy [[float]])
|
|
opaque(x as f32);
|
|
// CHECK: [[wrap:_.*]] = S::<u64>(copy _1);
|
|
// CHECK: opaque::<S<u64>>(copy [[wrap]])
|
|
opaque(S(x));
|
|
// CHECK: opaque::<u64>(copy _1)
|
|
opaque(S(x).0);
|
|
|
|
// Those are duplicates to substitute somehow.
|
|
// CHECK: opaque::<u64>(copy [[add]])
|
|
opaque(x + y);
|
|
// CHECK: opaque::<u64>(copy [[mul]])
|
|
opaque(x * y);
|
|
// CHECK: opaque::<u64>(copy [[sub]])
|
|
opaque(x - y);
|
|
// CHECK: opaque::<u64>(copy [[div]])
|
|
opaque(x / y);
|
|
// CHECK: opaque::<u64>(copy [[rem]])
|
|
opaque(x % y);
|
|
// CHECK: opaque::<u64>(copy [[and]])
|
|
opaque(x & y);
|
|
// CHECK: opaque::<u64>(copy [[or]])
|
|
opaque(x | y);
|
|
// CHECK: opaque::<u64>(copy [[xor]])
|
|
opaque(x ^ y);
|
|
// CHECK: opaque::<u64>(copy [[shl]])
|
|
opaque(x << y);
|
|
// CHECK: opaque::<u64>(copy [[shr]])
|
|
opaque(x >> y);
|
|
// CHECK: opaque::<u32>(copy [[int]])
|
|
opaque(x as u32);
|
|
// CHECK: opaque::<f32>(copy [[float]])
|
|
opaque(x as f32);
|
|
// CHECK: opaque::<S<u64>>(copy [[wrap]])
|
|
opaque(S(x));
|
|
// CHECK: opaque::<u64>(copy _1)
|
|
opaque(S(x).0);
|
|
|
|
// We can substitute through a complex expression.
|
|
// CHECK: [[compound:_.*]] = Sub(copy [[mul]], copy _2);
|
|
// CHECK: opaque::<u64>(copy [[compound]])
|
|
// CHECK: opaque::<u64>(copy [[compound]])
|
|
opaque((x * y) - y);
|
|
opaque((x * y) - y);
|
|
|
|
// We can substitute through an immutable reference too.
|
|
// CHECK: [[ref:_.*]] = &_3;
|
|
// CHECK: [[deref:_.*]] = copy (*[[ref]]);
|
|
// CHECK: [[addref:_.*]] = Add(copy [[deref]], copy _1);
|
|
// CHECK: opaque::<u64>(copy [[addref]])
|
|
// CHECK: opaque::<u64>(copy [[addref]])
|
|
let a = &z;
|
|
opaque(*a + x);
|
|
opaque(*a + x);
|
|
|
|
// But not through a mutable reference or a pointer.
|
|
// CHECK: [[mut:_.*]] = &mut _3;
|
|
// CHECK: [[addmut:_.*]] = Add(
|
|
// CHECK: opaque::<u64>(move [[addmut]])
|
|
// CHECK: [[addmut2:_.*]] = Add(
|
|
// CHECK: opaque::<u64>(move [[addmut2]])
|
|
let b = &mut z;
|
|
opaque(*b + x);
|
|
opaque(*b + x);
|
|
unsafe {
|
|
// CHECK: [[raw:_.*]] = &raw const _3;
|
|
// CHECK: [[addraw:_.*]] = Add(
|
|
// CHECK: opaque::<u64>(move [[addraw]])
|
|
// CHECK: [[addraw2:_.*]] = Add(
|
|
// CHECK: opaque::<u64>(move [[addraw2]])
|
|
let c = &raw const z;
|
|
opaque(*c + x);
|
|
opaque(*c + x);
|
|
// CHECK: [[ptr:_.*]] = &raw mut _3;
|
|
// CHECK: [[addptr:_.*]] = Add(
|
|
// CHECK: opaque::<u64>(move [[addptr]])
|
|
// CHECK: [[addptr2:_.*]] = Add(
|
|
// CHECK: opaque::<u64>(move [[addptr2]])
|
|
let d = &raw mut z;
|
|
opaque(*d + x);
|
|
opaque(*d + x);
|
|
}
|
|
|
|
// We can substitute again, but not with the earlier computations.
|
|
// Important: `e` is not `a`!
|
|
// CHECK: [[ref2:_.*]] = &_3;
|
|
// CHECK: [[deref2:_.*]] = copy (*[[ref2]]);
|
|
// CHECK: [[addref2:_.*]] = Add(copy [[deref2]], copy _1);
|
|
// CHECK: opaque::<u64>(copy [[addref2]])
|
|
// CHECK: opaque::<u64>(copy [[addref2]])
|
|
let e = &z;
|
|
opaque(*e + x);
|
|
opaque(*e + x);
|
|
}
|
|
|
|
fn wrap_unwrap<T: Copy>(x: T) -> T {
|
|
// CHECK-LABEL: fn wrap_unwrap(
|
|
// CHECK: [[some:_.*]] = Option::<T>::Some(copy _1);
|
|
// CHECK: switchInt(const 1_isize)
|
|
// CHECK: _0 = copy _1;
|
|
match Some(x) {
|
|
Some(y) => y,
|
|
None => panic!(),
|
|
}
|
|
}
|
|
|
|
fn repeated_index<T: Copy, const N: usize>(x: T, idx: usize) {
|
|
// CHECK-LABEL: fn repeated_index(
|
|
// CHECK: [[a:_.*]] = [copy _1; N];
|
|
let a = [x; N];
|
|
// CHECK: opaque::<T>(copy _1)
|
|
opaque(a[0]);
|
|
// CHECK: opaque::<T>(copy _1)
|
|
opaque(a[idx]);
|
|
}
|
|
|
|
fn unary(x: i64) {
|
|
// CHECK-LABEL: fn unary(
|
|
// CHECK: opaque::<i64>(copy _1)
|
|
opaque(--x); // This is `x`.
|
|
|
|
// CHECK: [[b:_.*]] = Lt(copy _1, const 13_i64);
|
|
// CHECK: opaque::<bool>(copy [[b]])
|
|
let b = x < 13;
|
|
opaque(!!b); // This is `b`.
|
|
|
|
// Both lines should test the same thing.
|
|
// CHECK: [[c:_.*]] = Ne(copy _1, const 15_i64);
|
|
// CHECK: opaque::<bool>(copy [[c]])
|
|
// CHECK: opaque::<bool>(copy [[c]])
|
|
opaque(x != 15);
|
|
opaque(!(x == 15));
|
|
|
|
// Both lines should test the same thing.
|
|
// CHECK: [[d:_.*]] = Eq(copy _1, const 35_i64);
|
|
// CHECK: opaque::<bool>(copy [[d]])
|
|
// CHECK: opaque::<bool>(copy [[d]])
|
|
opaque(x == 35);
|
|
opaque(!(x != 35));
|
|
}
|
|
|
|
/// Verify symbolic integer arithmetic simplifications.
|
|
fn arithmetic(x: u64) {
|
|
// CHECK-LABEL: fn arithmetic(
|
|
// CHECK: opaque::<u64>(copy _1)
|
|
opaque(x + 0);
|
|
// CHECK: opaque::<u64>(copy _1)
|
|
opaque(x - 0);
|
|
// CHECK: opaque::<u64>(const 0_u64)
|
|
opaque(x - x);
|
|
// CHECK: opaque::<u64>(const 0_u64)
|
|
opaque(x * 0);
|
|
// CHECK: opaque::<u64>(copy _1)
|
|
opaque(x * 1);
|
|
// CHECK: assert(!const true, "attempt to divide `{}` by zero",
|
|
// CHECK: [[div0:_.*]] = Div(copy _1, const 0_u64);
|
|
// CHECK: opaque::<u64>(move [[div0]])
|
|
opaque(x / 0);
|
|
// CHECK: opaque::<u64>(copy _1)
|
|
opaque(x / 1);
|
|
// CHECK: opaque::<u64>(const 0_u64)
|
|
opaque(0 / x);
|
|
// CHECK: [[odiv:_.*]] = Div(const 1_u64, copy _1);
|
|
// CHECK: opaque::<u64>(move [[odiv]])
|
|
opaque(1 / x);
|
|
// CHECK: assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero"
|
|
// CHECK: [[rem0:_.*]] = Rem(copy _1, const 0_u64);
|
|
// CHECK: opaque::<u64>(move [[rem0]])
|
|
opaque(x % 0);
|
|
// CHECK: opaque::<u64>(const 0_u64)
|
|
opaque(x % 1);
|
|
// CHECK: opaque::<u64>(const 0_u64)
|
|
opaque(0 % x);
|
|
// CHECK: [[orem:_.*]] = Rem(const 1_u64, copy _1);
|
|
// CHECK: opaque::<u64>(move [[orem]])
|
|
opaque(1 % x);
|
|
// CHECK: opaque::<u64>(const 0_u64)
|
|
opaque(x & 0);
|
|
// CHECK: opaque::<u64>(copy _1)
|
|
opaque(x & u64::MAX);
|
|
// CHECK: opaque::<u64>(copy _1)
|
|
opaque(x | 0);
|
|
// CHECK: opaque::<u64>(const u64::MAX)
|
|
opaque(x | u64::MAX);
|
|
// CHECK: opaque::<u64>(copy _1)
|
|
opaque(x ^ 0);
|
|
// CHECK: opaque::<u64>(const 0_u64)
|
|
opaque(x ^ x);
|
|
// CHECK: opaque::<u64>(copy _1)
|
|
opaque(x >> 0);
|
|
// CHECK: opaque::<u64>(copy _1)
|
|
opaque(x << 0);
|
|
}
|
|
|
|
fn comparison(x: u64, y: u64) {
|
|
// CHECK-LABEL: fn comparison(
|
|
// CHECK: opaque::<bool>(const true)
|
|
opaque(x == x);
|
|
// CHECK: opaque::<bool>(const false)
|
|
opaque(x != x);
|
|
// CHECK: [[eqxy:_.*]] = Eq(copy _1, copy _2);
|
|
// CHECK: opaque::<bool>(move [[eqxy]])
|
|
opaque(x == y);
|
|
// CHECK: [[nexy:_.*]] = Ne(copy _1, copy _2);
|
|
// CHECK: opaque::<bool>(move [[nexy]])
|
|
opaque(x != y);
|
|
}
|
|
|
|
/// Verify symbolic integer arithmetic simplifications on checked ops.
|
|
#[rustc_inherit_overflow_checks]
|
|
fn arithmetic_checked(x: u64) {
|
|
// CHECK-LABEL: fn arithmetic_checked(
|
|
// CHECK: assert(!const false,
|
|
// CHECK: opaque::<u64>(copy _1)
|
|
opaque(x + 0);
|
|
// CHECK: assert(!const false,
|
|
// CHECK: opaque::<u64>(copy _1)
|
|
opaque(x - 0);
|
|
// CHECK: assert(!const false,
|
|
// CHECK: opaque::<u64>(const 0_u64)
|
|
opaque(x - x);
|
|
// CHECK: assert(!const false,
|
|
// CHECK: opaque::<u64>(const 0_u64)
|
|
opaque(x * 0);
|
|
// CHECK: assert(!const false,
|
|
// CHECK: opaque::<u64>(copy _1)
|
|
opaque(x * 1);
|
|
}
|
|
|
|
/// Verify that we do not apply arithmetic simplifications on floats.
|
|
fn arithmetic_float(x: f64) {
|
|
// CHECK-LABEL: fn arithmetic_float(
|
|
// CHECK: [[add:_.*]] = Add(copy _1, const 0f64);
|
|
// CHECK: opaque::<f64>(move [[add]])
|
|
opaque(x + 0.);
|
|
// CHECK: [[sub:_.*]] = Sub(copy _1, const 0f64);
|
|
// CHECK: opaque::<f64>(move [[sub]])
|
|
opaque(x - 0.);
|
|
// CHECK: [[mul:_.*]] = Mul(copy _1, const 0f64);
|
|
// CHECK: opaque::<f64>(move [[mul]])
|
|
opaque(x * 0.);
|
|
// CHECK: [[div0:_.*]] = Div(copy _1, const 0f64);
|
|
// CHECK: opaque::<f64>(move [[div0]])
|
|
opaque(x / 0.);
|
|
// CHECK: [[zdiv:_.*]] = Div(const 0f64, copy _1);
|
|
// CHECK: opaque::<f64>(move [[zdiv]])
|
|
opaque(0. / x);
|
|
// CHECK: [[rem0:_.*]] = Rem(copy _1, const 0f64);
|
|
// CHECK: opaque::<f64>(move [[rem0]])
|
|
opaque(x % 0.);
|
|
// CHECK: [[zrem:_.*]] = Rem(const 0f64, copy _1);
|
|
// CHECK: opaque::<f64>(move [[zrem]])
|
|
opaque(0. % x);
|
|
// Those are not simplifiable to `true`/`false`, thanks to NaNs.
|
|
// CHECK: [[eq:_.*]] = Eq(copy _1, copy _1);
|
|
// CHECK: opaque::<bool>(move [[eq]])
|
|
opaque(x == x);
|
|
// CHECK: [[ne:_.*]] = Ne(copy _1, copy _1);
|
|
// CHECK: opaque::<bool>(move [[ne]])
|
|
opaque(x != x);
|
|
}
|
|
|
|
fn cast() {
|
|
// CHECK-LABEL: fn cast(
|
|
let i = 1_i64;
|
|
let u = 1_u64;
|
|
let f = 1_f64;
|
|
// CHECK: opaque::<u8>(const 1_u8)
|
|
opaque(i as u8);
|
|
// CHECK: opaque::<u16>(const 1_u16)
|
|
opaque(i as u16);
|
|
// CHECK: opaque::<u32>(const 1_u32)
|
|
opaque(i as u32);
|
|
// CHECK: opaque::<u64>(const 1_u64)
|
|
opaque(i as u64);
|
|
// CHECK: opaque::<i8>(const 1_i8)
|
|
opaque(i as i8);
|
|
// CHECK: opaque::<i16>(const 1_i16)
|
|
opaque(i as i16);
|
|
// CHECK: opaque::<i32>(const 1_i32)
|
|
opaque(i as i32);
|
|
// CHECK: opaque::<i64>(const 1_i64)
|
|
opaque(i as i64);
|
|
// CHECK: opaque::<f32>(const 1f32)
|
|
opaque(i as f32);
|
|
// CHECK: opaque::<f64>(const 1f64)
|
|
opaque(i as f64);
|
|
// CHECK: opaque::<u8>(const 1_u8)
|
|
opaque(u as u8);
|
|
// CHECK: opaque::<u16>(const 1_u16)
|
|
opaque(u as u16);
|
|
// CHECK: opaque::<u32>(const 1_u32)
|
|
opaque(u as u32);
|
|
// CHECK: opaque::<u64>(const 1_u64)
|
|
opaque(u as u64);
|
|
// CHECK: opaque::<i8>(const 1_i8)
|
|
opaque(u as i8);
|
|
// CHECK: opaque::<i16>(const 1_i16)
|
|
opaque(u as i16);
|
|
// CHECK: opaque::<i32>(const 1_i32)
|
|
opaque(u as i32);
|
|
// CHECK: opaque::<i64>(const 1_i64)
|
|
opaque(u as i64);
|
|
// CHECK: opaque::<f32>(const 1f32)
|
|
opaque(u as f32);
|
|
// CHECK: opaque::<f64>(const 1f64)
|
|
opaque(u as f64);
|
|
// CHECK: opaque::<u8>(const 1_u8)
|
|
opaque(f as u8);
|
|
// CHECK: opaque::<u16>(const 1_u16)
|
|
opaque(f as u16);
|
|
// CHECK: opaque::<u32>(const 1_u32)
|
|
opaque(f as u32);
|
|
// CHECK: opaque::<u64>(const 1_u64)
|
|
opaque(f as u64);
|
|
// CHECK: opaque::<i8>(const 1_i8)
|
|
opaque(f as i8);
|
|
// CHECK: opaque::<i16>(const 1_i16)
|
|
opaque(f as i16);
|
|
// CHECK: opaque::<i32>(const 1_i32)
|
|
opaque(f as i32);
|
|
// CHECK: opaque::<i64>(const 1_i64)
|
|
opaque(f as i64);
|
|
// CHECK: opaque::<f32>(const 1f32)
|
|
opaque(f as f32);
|
|
// CHECK: opaque::<f64>(const 1f64)
|
|
opaque(f as f64);
|
|
}
|
|
|
|
fn multiple_branches(t: bool, x: u8, y: u8) {
|
|
// CHECK-LABEL: fn multiple_branches(
|
|
// CHECK: switchInt(copy _1) -> [0: [[bbf:bb.*]], otherwise: [[bbt:bb.*]]];
|
|
if t {
|
|
// CHECK: [[bbt]]: {
|
|
// CHECK: [[a:_.*]] = Add(copy _2, copy _3);
|
|
// CHECK: opaque::<u8>(copy [[a]])
|
|
// CHECK: opaque::<u8>(copy [[a]])
|
|
// CHECK: goto -> [[bbc:bb.*]];
|
|
opaque(x + y);
|
|
opaque(x + y);
|
|
} else {
|
|
// CHECK: [[bbf]]: {
|
|
// CHECK: [[b:_.*]] = Add(copy _2, copy _3);
|
|
// CHECK: opaque::<u8>(copy [[b]])
|
|
// CHECK: opaque::<u8>(copy [[b]])
|
|
// CHECK: goto -> [[bbc:bb.*]];
|
|
opaque(x + y);
|
|
opaque(x + y);
|
|
}
|
|
// Neither `a` nor `b` dominate `c`, so we cannot reuse any of them.
|
|
// CHECK: [[bbc]]: {
|
|
// CHECK: [[c:_.*]] = Add(copy _2, copy _3);
|
|
// CHECK: opaque::<u8>(copy [[c]])
|
|
opaque(x + y);
|
|
|
|
// `c` dominates both calls, so we can reuse it.
|
|
if t {
|
|
// CHECK: opaque::<u8>(copy [[c]])
|
|
opaque(x + y);
|
|
} else {
|
|
// CHECK: opaque::<u8>(copy [[c]])
|
|
opaque(x + y);
|
|
}
|
|
}
|
|
|
|
/// Verify that we do not reuse a `&raw? mut?` rvalue.
|
|
fn references(mut x: impl Sized) {
|
|
// CHECK-LABEL: fn references(
|
|
// CHECK: [[ref1:_.*]] = &_1;
|
|
// CHECK: opaque::<&impl Sized>(move [[ref1]])
|
|
opaque(&x);
|
|
// CHECK: [[ref2:_.*]] = &_1;
|
|
// CHECK: opaque::<&impl Sized>(move [[ref2]])
|
|
opaque(&x);
|
|
// CHECK: [[ref3:_.*]] = &mut _1;
|
|
// CHECK: opaque::<&mut impl Sized>(move [[ref3]])
|
|
opaque(&mut x);
|
|
// CHECK: [[ref4:_.*]] = &mut _1;
|
|
// CHECK: opaque::<&mut impl Sized>(move [[ref4]])
|
|
opaque(&mut x);
|
|
// CHECK: [[ref5:_.*]] = &raw const _1;
|
|
// CHECK: opaque::<*const impl Sized>(move [[ref5]])
|
|
opaque(&raw const x);
|
|
// CHECK: [[ref6:_.*]] = &raw const _1;
|
|
// CHECK: opaque::<*const impl Sized>(move [[ref6]])
|
|
opaque(&raw const x);
|
|
// CHECK: [[ref7:_.*]] = &raw mut _1;
|
|
// CHECK: opaque::<*mut impl Sized>(move [[ref7]])
|
|
opaque(&raw mut x);
|
|
// CHECK: [[ref8:_.*]] = &raw mut _1;
|
|
// CHECK: opaque::<*mut impl Sized>(move [[ref8]])
|
|
opaque(&raw mut x);
|
|
|
|
let r = &mut x;
|
|
let s = S(r).0; // Obfuscate `r`. Following lines should still reborrow `r`.
|
|
// CHECK: [[ref9:_.*]] = &mut _1;
|
|
// CHECK: [[ref10:_.*]] = &(*[[ref9]]);
|
|
// CHECK: opaque::<&impl Sized>(move [[ref10]])
|
|
opaque(&*s);
|
|
// CHECK: [[ref11:_.*]] = &mut (*[[ref9]]);
|
|
// CHECK: opaque::<&mut impl Sized>(move [[ref11]])
|
|
opaque(&mut *s);
|
|
// CHECK: [[ref12:_.*]] = &raw const (*[[ref9]]);
|
|
// CHECK: opaque::<*const impl Sized>(move [[ref12]])
|
|
opaque(&raw const *s);
|
|
// CHECK: [[ref12:_.*]] = &raw mut (*[[ref9]]);
|
|
// CHECK: opaque::<*mut impl Sized>(move [[ref12]])
|
|
opaque(&raw mut *s);
|
|
}
|
|
|
|
fn dereferences(t: &mut u32, u: &impl Copy, s: &S<u32>) {
|
|
// CHECK-LABEL: fn dereferences(
|
|
|
|
// Do not reuse dereferences of `&mut`.
|
|
// CHECK: [[st1:_.*]] = copy (*_1);
|
|
// CHECK: opaque::<u32>(move [[st1]])
|
|
// CHECK: [[st2:_.*]] = copy (*_1);
|
|
// CHECK: opaque::<u32>(move [[st2]])
|
|
opaque(*t);
|
|
opaque(*t);
|
|
|
|
// Do not reuse dereferences of `*const`.
|
|
// CHECK: [[raw:_.*]] = &raw const (*_1);
|
|
// CHECK: [[st3:_.*]] = copy (*[[raw]]);
|
|
// CHECK: opaque::<u32>(move [[st3]])
|
|
// CHECK: [[st4:_.*]] = copy (*[[raw]]);
|
|
// CHECK: opaque::<u32>(move [[st4]])
|
|
let z = &raw const *t;
|
|
unsafe { opaque(*z) };
|
|
unsafe { opaque(*z) };
|
|
|
|
// Do not reuse dereferences of `*mut`.
|
|
// CHECK: [[ptr:_.*]] = &raw mut (*_1);
|
|
// CHECK: [[st5:_.*]] = copy (*[[ptr]]);
|
|
// CHECK: opaque::<u32>(move [[st5]])
|
|
// CHECK: [[st6:_.*]] = copy (*[[ptr]]);
|
|
// CHECK: opaque::<u32>(move [[st6]])
|
|
let z = &raw mut *t;
|
|
unsafe { opaque(*z) };
|
|
unsafe { opaque(*z) };
|
|
|
|
// We can reuse dereferences of `&Freeze`.
|
|
// CHECK: [[ref:_.*]] = &(*_1);
|
|
// CHECK: [[st7:_.*]] = copy (*[[ref]]);
|
|
// CHECK: opaque::<u32>(copy [[st7]])
|
|
// CHECK: opaque::<u32>(copy [[st7]])
|
|
let z = &*t;
|
|
opaque(*z);
|
|
opaque(*z);
|
|
// But not in reborrows.
|
|
// CHECK: [[reborrow:_.*]] = &(*[[ref]]);
|
|
// CHECK: opaque::<&u32>(move [[reborrow]])
|
|
opaque(&*z);
|
|
|
|
// `*u` is not Freeze, so we cannot reuse.
|
|
// CHECK: [[st8:_.*]] = copy (*_2);
|
|
// CHECK: opaque::<impl Copy>(move [[st8]])
|
|
// CHECK: [[st9:_.*]] = copy (*_2);
|
|
// CHECK: opaque::<impl Copy>(move [[st9]])
|
|
opaque(*u);
|
|
opaque(*u);
|
|
|
|
// `*s` is not Copy, but `(*s).0` is, so we can reuse.
|
|
// CHECK: [[st10:_.*]] = copy ((*_3).0: u32);
|
|
// CHECK: opaque::<u32>(copy [[st10]])
|
|
// CHECK: opaque::<u32>(copy [[st10]])
|
|
opaque(s.0);
|
|
opaque(s.0);
|
|
}
|
|
|
|
fn slices() {
|
|
// CHECK-LABEL: fn slices(
|
|
// CHECK: {{_.*}} = const "
|
|
// CHECK-NOT: {{_.*}} = const "
|
|
let s = "my favourite slice"; // This is a `Const::Slice` in MIR.
|
|
opaque(s);
|
|
let t = s; // This should be the same pointer, so cannot be a `Const::Slice`.
|
|
opaque(t);
|
|
assert_eq!(s.as_ptr(), t.as_ptr());
|
|
let u = unsafe { transmute::<&str, &[u8]>(s) };
|
|
opaque(u);
|
|
assert_eq!(s.as_ptr(), u.as_ptr());
|
|
}
|
|
|
|
#[custom_mir(dialect = "analysis")]
|
|
fn duplicate_slice() -> (bool, bool) {
|
|
// CHECK-LABEL: fn duplicate_slice(
|
|
mir! {
|
|
let au: u128;
|
|
let bu: u128;
|
|
let cu: u128;
|
|
let du: u128;
|
|
let c: &str;
|
|
let d: &str;
|
|
{
|
|
// CHECK: [[a:_.*]] = (const "a",);
|
|
// CHECK: [[au:_.*]] = copy ([[a]].0: &str) as u128 (Transmute);
|
|
let a = ("a",);
|
|
Call(au = transmute::<_, u128>(a.0), ReturnTo(bb1), UnwindContinue())
|
|
}
|
|
bb1 = {
|
|
// CHECK: [[c:_.*]] = identity::<&str>(copy ([[a]].0: &str))
|
|
Call(c = identity(a.0), ReturnTo(bb2), UnwindContinue())
|
|
}
|
|
bb2 = {
|
|
// CHECK: [[cu:_.*]] = copy [[c]] as u128 (Transmute);
|
|
Call(cu = transmute::<_, u128>(c), ReturnTo(bb3), UnwindContinue())
|
|
}
|
|
bb3 = {
|
|
// This slice is different from `a.0`. Hence `bu` is not `au`.
|
|
// CHECK: [[b:_.*]] = const "a";
|
|
// CHECK: [[bu:_.*]] = copy [[b]] as u128 (Transmute);
|
|
let b = "a";
|
|
Call(bu = transmute::<_, u128>(b), ReturnTo(bb4), UnwindContinue())
|
|
}
|
|
bb4 = {
|
|
// This returns a copy of `b`, which is not `a`.
|
|
// CHECK: [[d:_.*]] = identity::<&str>(copy [[b]])
|
|
Call(d = identity(b), ReturnTo(bb5), UnwindContinue())
|
|
}
|
|
bb5 = {
|
|
// CHECK: [[du:_.*]] = copy [[d]] as u128 (Transmute);
|
|
Call(du = transmute::<_, u128>(d), ReturnTo(bb6), UnwindContinue())
|
|
}
|
|
bb6 = {
|
|
// `direct` must not fold to `true`, as `indirect` will not.
|
|
// CHECK: = Eq(copy [[au]], copy [[bu]]);
|
|
// CHECK: = Eq(copy [[cu]], copy [[du]]);
|
|
let direct = au == bu;
|
|
let indirect = cu == du;
|
|
RET = (direct, indirect);
|
|
Return()
|
|
}
|
|
}
|
|
}
|
|
|
|
fn repeat() {
|
|
// CHECK-LABEL: fn repeat(
|
|
// CHECK: = [const 5_i32; 10];
|
|
let val = 5;
|
|
let array = [val, val, val, val, val, val, val, val, val, val];
|
|
}
|
|
|
|
/// Verify that we do not merge fn pointers created by casts.
|
|
fn fn_pointers() {
|
|
// CHECK-LABEL: fn fn_pointers(
|
|
// CHECK: [[f:_.*]] = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer
|
|
// CHECK: opaque::<fn(u8) -> u8>(copy [[f]])
|
|
let f = identity as fn(u8) -> u8;
|
|
opaque(f);
|
|
// CHECK: [[g:_.*]] = identity::<u8> as fn(u8) -> u8 (PointerCoercion(ReifyFnPointer
|
|
// CHECK: opaque::<fn(u8) -> u8>(copy [[g]])
|
|
let g = identity as fn(u8) -> u8;
|
|
opaque(g);
|
|
|
|
// CHECK: [[cf:_.*]] = const {{.*}} as fn() (PointerCoercion(ClosureFnPointer
|
|
// CHECK: opaque::<fn()>(copy [[cf]])
|
|
let closure = || {};
|
|
let cf = closure as fn();
|
|
opaque(cf);
|
|
// CHECK: [[cg:_.*]] = const {{.*}} as fn() (PointerCoercion(ClosureFnPointer
|
|
// CHECK: opaque::<fn()>(copy [[cg]])
|
|
let cg = closure as fn();
|
|
opaque(cg);
|
|
}
|
|
|
|
/// Verify that we do not create a `ConstValue::Indirect` backed by a static's AllocId.
|
|
#[custom_mir(dialect = "analysis")]
|
|
fn indirect_static() {
|
|
static A: Option<u8> = None;
|
|
|
|
mir! {
|
|
{
|
|
let ptr = Static(A);
|
|
let out = Field::<u8>(Variant(*ptr, 1), 0);
|
|
Return()
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Verify that having constant index `u64::MAX` does not yield to an overflow in rustc.
|
|
fn constant_index_overflow<T: Copy>(x: &[T]) {
|
|
// CHECK-LABEL: fn constant_index_overflow(
|
|
// CHECK: debug a => [[a:_.*]];
|
|
// CHECK: debug b => [[b:_.*]];
|
|
// CHECK: [[a]] = const usize::MAX;
|
|
// CHECK-NOT: = (*_1)[{{.*}} of 0];
|
|
// CHECK: [[b]] = copy (*_1)[[[a]]];
|
|
// CHECK-NOT: = (*_1)[{{.*}} of 0];
|
|
// CHECK: [[b]] = copy (*_1)[0 of 1];
|
|
// CHECK-NOT: = (*_1)[{{.*}} of 0];
|
|
let a = u64::MAX as usize;
|
|
let b = if a < x.len() { x[a] } else { x[0] };
|
|
opaque(b)
|
|
}
|
|
|
|
/// Check that we do not attempt to simplify anything when there is provenance.
|
|
fn wide_ptr_provenance() {
|
|
// CHECK-LABEL: fn wide_ptr_provenance(
|
|
let a: *const dyn Send = &1 as &dyn Send;
|
|
let b: *const dyn Send = &1 as &dyn Send;
|
|
|
|
// CHECK: [[eqp:_.*]] = Eq(copy [[a:_.*]], copy [[b:_.*]]);
|
|
// CHECK: opaque::<bool>(move [[eqp]])
|
|
opaque(a == b);
|
|
// CHECK: [[nep:_.*]] = Ne(copy [[a]], copy [[b]]);
|
|
// CHECK: opaque::<bool>(move [[nep]])
|
|
opaque(a != b);
|
|
// CHECK: [[ltp:_.*]] = Lt(copy [[a]], copy [[b]]);
|
|
// CHECK: opaque::<bool>(move [[ltp]])
|
|
opaque(a < b);
|
|
// CHECK: [[lep:_.*]] = Le(copy [[a]], copy [[b]]);
|
|
// CHECK: opaque::<bool>(move [[lep]])
|
|
opaque(a <= b);
|
|
// CHECK: [[gtp:_.*]] = Gt(copy [[a]], copy [[b]]);
|
|
// CHECK: opaque::<bool>(move [[gtp]])
|
|
opaque(a > b);
|
|
// CHECK: [[gep:_.*]] = Ge(copy [[a]], copy [[b]]);
|
|
// CHECK: opaque::<bool>(move [[gep]])
|
|
opaque(a >= b);
|
|
}
|
|
|
|
/// Both pointers come form the same allocation, so we could probably fold the comparisons.
|
|
fn wide_ptr_same_provenance() {
|
|
// CHECK-LABEL: fn wide_ptr_same_provenance(
|
|
let slice = &[1, 2];
|
|
let a: *const dyn Send = &slice[0] as &dyn Send;
|
|
let b: *const dyn Send = &slice[1] as &dyn Send;
|
|
|
|
// CHECK: [[eqp:_.*]] = Eq(copy [[a:_.*]], copy [[b:_.*]]);
|
|
// CHECK: opaque::<bool>(move [[eqp]])
|
|
opaque(a == b);
|
|
// CHECK: [[nep:_.*]] = Ne(copy [[a]], copy [[b]]);
|
|
// CHECK: opaque::<bool>(move [[nep]])
|
|
opaque(a != b);
|
|
// CHECK: [[ltp:_.*]] = Lt(copy [[a]], copy [[b]]);
|
|
// CHECK: opaque::<bool>(move [[ltp]])
|
|
opaque(a < b);
|
|
// CHECK: [[lep:_.*]] = Le(copy [[a]], copy [[b]]);
|
|
// CHECK: opaque::<bool>(move [[lep]])
|
|
opaque(a <= b);
|
|
// CHECK: [[gtp:_.*]] = Gt(copy [[a]], copy [[b]]);
|
|
// CHECK: opaque::<bool>(move [[gtp]])
|
|
opaque(a > b);
|
|
// CHECK: [[gep:_.*]] = Ge(copy [[a]], copy [[b]]);
|
|
// CHECK: opaque::<bool>(move [[gep]])
|
|
opaque(a >= b);
|
|
}
|
|
|
|
/// Check that we do simplify when there is no provenance, and do not ICE.
|
|
fn wide_ptr_integer() {
|
|
// CHECK-LABEL: fn wide_ptr_integer(
|
|
// CHECK: debug a => [[a:_.*]];
|
|
// CHECK: debug b => [[b:_.*]];
|
|
|
|
let a: *const [u8] = unsafe { transmute((1usize, 1usize)) };
|
|
let b: *const [u8] = unsafe { transmute((1usize, 2usize)) };
|
|
|
|
// CHECK: opaque::<bool>(const false)
|
|
opaque(a == b);
|
|
// CHECK: opaque::<bool>(const true)
|
|
opaque(a != b);
|
|
// CHECK: opaque::<bool>(const true)
|
|
opaque(a < b);
|
|
// CHECK: opaque::<bool>(const true)
|
|
opaque(a <= b);
|
|
// CHECK: opaque::<bool>(const false)
|
|
opaque(a > b);
|
|
// CHECK: opaque::<bool>(const false)
|
|
opaque(a >= b);
|
|
}
|
|
|
|
#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
|
|
fn borrowed<T: Copy + Freeze>(x: T) {
|
|
// CHECK-LABEL: fn borrowed(
|
|
// CHECK: bb0: {
|
|
// CHECK-NEXT: _2 = copy _1;
|
|
// CHECK-NEXT: _3 = &_1;
|
|
// CHECK-NEXT: _0 = opaque::<&T>(copy _3)
|
|
// CHECK: bb1: {
|
|
// CHECK-NEXT: _0 = opaque::<T>(copy _1)
|
|
// CHECK: bb2: {
|
|
// CHECK-NEXT: _0 = opaque::<T>(copy _1)
|
|
mir! {
|
|
{
|
|
let a = x;
|
|
let r1 = &x;
|
|
Call(RET = opaque(r1), ReturnTo(next), UnwindContinue())
|
|
}
|
|
next = {
|
|
Call(RET = opaque(a), ReturnTo(deref), UnwindContinue())
|
|
}
|
|
deref = {
|
|
Call(RET = opaque(*r1), ReturnTo(ret), UnwindContinue())
|
|
}
|
|
ret = {
|
|
Return()
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Generic type `T` is not known to be `Freeze`, so shared borrows may be mutable.
|
|
#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
|
|
fn non_freeze<T: Copy>(x: T) {
|
|
// CHECK-LABEL: fn non_freeze(
|
|
// CHECK: bb0: {
|
|
// CHECK-NEXT: _2 = copy _1;
|
|
// CHECK-NEXT: _3 = &_1;
|
|
// CHECK-NEXT: _0 = opaque::<&T>(copy _3)
|
|
// CHECK: bb1: {
|
|
// CHECK-NEXT: _0 = opaque::<T>(copy _2)
|
|
// CHECK: bb2: {
|
|
// CHECK-NEXT: _0 = opaque::<T>(copy (*_3))
|
|
mir! {
|
|
{
|
|
let a = x;
|
|
let r1 = &x;
|
|
Call(RET = opaque(r1), ReturnTo(next), UnwindContinue())
|
|
}
|
|
next = {
|
|
Call(RET = opaque(a), ReturnTo(deref), UnwindContinue())
|
|
}
|
|
deref = {
|
|
Call(RET = opaque(*r1), ReturnTo(ret), UnwindContinue())
|
|
}
|
|
ret = {
|
|
Return()
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check that we can const-prop into `from_raw_parts`
|
|
fn slice_const_length(x: &[i32]) -> *const [i32] {
|
|
// CHECK-LABEL: fn slice_const_length(
|
|
// CHECK: _0 = *const [i32] from (copy {{_[0-9]+}}, const 123_usize);
|
|
let ptr = x.as_ptr();
|
|
let len = 123;
|
|
std::intrinsics::aggregate_raw_ptr(ptr, len)
|
|
}
|
|
|
|
fn meta_of_ref_to_slice(x: *const i32) -> usize {
|
|
// CHECK-LABEL: fn meta_of_ref_to_slice
|
|
// CHECK: _0 = const 1_usize
|
|
let ptr: *const [i32] = std::intrinsics::aggregate_raw_ptr(x, 1);
|
|
std::intrinsics::ptr_metadata(ptr)
|
|
}
|
|
|
|
fn slice_from_raw_parts_as_ptr(x: *const u16, n: usize) -> (*const u16, *const f32) {
|
|
// CHECK-LABEL: fn slice_from_raw_parts_as_ptr
|
|
// CHECK: _8 = copy _1 as *const f32 (PtrToPtr);
|
|
// CHECK: _0 = (copy _1, move _8);
|
|
let ptr: *const [u16] = std::intrinsics::aggregate_raw_ptr(x, n);
|
|
(ptr as *const u16, ptr as *const f32)
|
|
}
|
|
|
|
fn casts_before_aggregate_raw_ptr(x: *const u32) -> *const [u8] {
|
|
// CHECK-LABEL: fn casts_before_aggregate_raw_ptr
|
|
// CHECK: _0 = *const [u8] from (copy _1, const 4_usize);
|
|
let x = x as *const [u8; 4];
|
|
let x = x as *const u8;
|
|
let x = x as *const ();
|
|
std::intrinsics::aggregate_raw_ptr(x, 4)
|
|
}
|
|
|
|
fn manual_slice_mut_len(x: &mut [i32]) -> usize {
|
|
// CHECK-LABEL: fn manual_slice_mut_len
|
|
// CHECK: _0 = PtrMetadata(copy _1);
|
|
let x: *mut [i32] = x;
|
|
let x: *const [i32] = x;
|
|
std::intrinsics::ptr_metadata(x)
|
|
}
|
|
|
|
// `.len()` on arrays ends up being something like this
|
|
fn array_len(x: &mut [i32; 42]) -> usize {
|
|
// CHECK-LABEL: fn array_len
|
|
// CHECK: _0 = const 42_usize;
|
|
let x: &[i32] = x;
|
|
std::intrinsics::ptr_metadata(x)
|
|
}
|
|
|
|
#[custom_mir(dialect = "runtime")]
|
|
fn generic_cast_metadata<T, A: ?Sized, B: ?Sized>(ps: *const [T], pa: *const A, pb: *const B) {
|
|
// CHECK-LABEL: fn generic_cast_metadata
|
|
mir! {
|
|
{
|
|
// These tests check that we correctly do or don't elide casts
|
|
// when the pointee metadata do or don't match, respectively.
|
|
|
|
// Metadata usize -> (), do not optimize.
|
|
// CHECK: [[T:_.+]] = copy _1 as
|
|
// CHECK-NEXT: PtrMetadata(copy [[T]])
|
|
let t1 = CastPtrToPtr::<_, *const T>(ps);
|
|
let m1 = PtrMetadata(t1);
|
|
|
|
// `(&A, [T])` has `usize` metadata, same as `[T]`, yes optimize.
|
|
// CHECK: [[T:_.+]] = copy _1 as
|
|
// CHECK-NEXT: PtrMetadata(copy _1)
|
|
let t2 = CastPtrToPtr::<_, *const (&A, [T])>(ps);
|
|
let m2 = PtrMetadata(t2);
|
|
|
|
// Tail `A` and tail `B`, do not optimize.
|
|
// CHECK: [[T:_.+]] = copy _2 as
|
|
// CHECK-NEXT: PtrMetadata(copy [[T]])
|
|
let t3 = CastPtrToPtr::<_, *const (T, B)>(pa);
|
|
let m3 = PtrMetadata(t3);
|
|
|
|
// Both have tail `A`, yes optimize.
|
|
// CHECK: [[T:_.+]] = copy _2 as
|
|
// CHECK-NEXT: PtrMetadata(copy _2)
|
|
let t4 = CastPtrToPtr::<_, *const (T, A)>(pa);
|
|
let m4 = PtrMetadata(t4);
|
|
|
|
// Tail `B` and tail `A`, do not optimize.
|
|
// CHECK: [[T:_.+]] = copy _3 as
|
|
// CHECK-NEXT: PtrMetadata(copy [[T]])
|
|
let t5 = CastPtrToPtr::<_, *mut A>(pb);
|
|
let m5 = PtrMetadata(t5);
|
|
|
|
// Both have tail `B`, yes optimize.
|
|
// CHECK: [[T:_.+]] = copy _3 as
|
|
// CHECK-NEXT: PtrMetadata(copy _3)
|
|
let t6 = CastPtrToPtr::<_, *mut B>(pb);
|
|
let m6 = PtrMetadata(t6);
|
|
|
|
Return()
|
|
}
|
|
}
|
|
}
|
|
|
|
fn cast_pointer_eq(p1: *mut u8, p2: *mut u32, p3: *mut u32, p4: *mut [u32]) {
|
|
// CHECK-LABEL: fn cast_pointer_eq
|
|
// CHECK: debug p1 => [[P1:_1]];
|
|
// CHECK: debug p2 => [[P2:_2]];
|
|
// CHECK: debug p3 => [[P3:_3]];
|
|
// CHECK: debug p4 => [[P4:_4]];
|
|
|
|
// CHECK: [[M1:_.+]] = copy [[P1]] as *const u32 (PtrToPtr);
|
|
// CHECK: [[M2:_.+]] = copy [[P2]] as *const u32 (PtrToPtr);
|
|
// CHECK: [[M3:_.+]] = copy [[P3]] as *const u32 (PtrToPtr);
|
|
// CHECK: [[M4:_.+]] = copy [[P4]] as *const u32 (PtrToPtr);
|
|
let m1 = p1 as *const u32;
|
|
let m2 = p2 as *const u32;
|
|
let m3 = p3 as *const u32;
|
|
let m4 = p4 as *const u32;
|
|
|
|
// CHECK-NOT: Eq
|
|
// CHECK: Eq(copy [[M1]], copy [[M2]])
|
|
// CHECK-NOT: Eq
|
|
// CHECK: Eq(copy [[P2]], copy [[P3]])
|
|
// CHECK-NOT: Eq
|
|
// CHECK: Eq(copy [[M3]], copy [[M4]])
|
|
// CHECK-NOT: Eq
|
|
let eq_different_thing = m1 == m2;
|
|
let eq_optimize = m2 == m3;
|
|
let eq_thin_fat = m3 == m4;
|
|
|
|
// CHECK: _0 = const ();
|
|
}
|
|
|
|
// Transmuting can skip a pointer cast so long as it wasn't a fat-to-thin cast.
|
|
unsafe fn cast_pointer_then_transmute(thin: *mut u32, fat: *mut [u8]) {
|
|
// CHECK-LABEL: fn cast_pointer_then_transmute
|
|
|
|
// CHECK: [[UNUSED:_.+]] = copy _1 as *const () (PtrToPtr);
|
|
// CHECK: = copy _1 as usize (Transmute);
|
|
let thin_addr: usize = std::intrinsics::transmute(thin as *const ());
|
|
|
|
// CHECK: [[TEMP2:_.+]] = copy _2 as *const () (PtrToPtr);
|
|
// CHECK: = move [[TEMP2]] as usize (Transmute);
|
|
let fat_addr: usize = std::intrinsics::transmute(fat as *const ());
|
|
}
|
|
|
|
#[custom_mir(dialect = "analysis")]
|
|
fn remove_casts_must_change_both_sides(mut_a: &*mut u8, mut_b: *mut u8) -> bool {
|
|
// CHECK-LABEL: fn remove_casts_must_change_both_sides(
|
|
mir! {
|
|
// We'd like to remove these casts, but we can't change *both* of them
|
|
// to be locals, so make sure we don't change one without the other, as
|
|
// that would be a type error.
|
|
{
|
|
// CHECK: [[A:_.+]] = copy (*_1) as *const u8 (PtrToPtr);
|
|
let a = *mut_a as *const u8;
|
|
// CHECK: [[B:_.+]] = copy _2 as *const u8 (PtrToPtr);
|
|
let b = mut_b as *const u8;
|
|
// CHECK: _0 = Eq(copy [[A]], copy [[B]]);
|
|
RET = a == b;
|
|
Return()
|
|
}
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
subexpression_elimination(2, 4, 5);
|
|
wrap_unwrap(5);
|
|
repeated_index::<u32, 7>(5, 3);
|
|
unary(i64::MIN);
|
|
arithmetic(5);
|
|
comparison(5, 6);
|
|
arithmetic_checked(5);
|
|
arithmetic_float(5.);
|
|
cast();
|
|
multiple_branches(true, 5, 9);
|
|
references(5);
|
|
dereferences(&mut 5, &6, &S(7));
|
|
slices();
|
|
let (direct, indirect) = duplicate_slice();
|
|
assert_eq!(direct, indirect);
|
|
repeat();
|
|
fn_pointers();
|
|
indirect_static();
|
|
constant_index_overflow(&[5, 3]);
|
|
wide_ptr_provenance();
|
|
wide_ptr_integer();
|
|
borrowed(5);
|
|
non_freeze(5);
|
|
slice_const_length(&[1]);
|
|
meta_of_ref_to_slice(&42);
|
|
slice_from_raw_parts_as_ptr(&123, 456);
|
|
}
|
|
|
|
#[inline(never)]
|
|
fn opaque(_: impl Sized) {}
|
|
|
|
#[inline(never)]
|
|
fn identity<T>(x: T) -> T {
|
|
x
|
|
}
|
|
|
|
// EMIT_MIR gvn.subexpression_elimination.GVN.diff
|
|
// EMIT_MIR gvn.wrap_unwrap.GVN.diff
|
|
// EMIT_MIR gvn.repeated_index.GVN.diff
|
|
// EMIT_MIR gvn.unary.GVN.diff
|
|
// EMIT_MIR gvn.arithmetic.GVN.diff
|
|
// EMIT_MIR gvn.comparison.GVN.diff
|
|
// EMIT_MIR gvn.arithmetic_checked.GVN.diff
|
|
// EMIT_MIR gvn.arithmetic_float.GVN.diff
|
|
// EMIT_MIR gvn.cast.GVN.diff
|
|
// EMIT_MIR gvn.multiple_branches.GVN.diff
|
|
// EMIT_MIR gvn.references.GVN.diff
|
|
// EMIT_MIR gvn.dereferences.GVN.diff
|
|
// EMIT_MIR gvn.slices.GVN.diff
|
|
// EMIT_MIR gvn.duplicate_slice.GVN.diff
|
|
// EMIT_MIR gvn.repeat.GVN.diff
|
|
// EMIT_MIR gvn.fn_pointers.GVN.diff
|
|
// EMIT_MIR gvn.indirect_static.GVN.diff
|
|
// EMIT_MIR gvn.constant_index_overflow.GVN.diff
|
|
// EMIT_MIR gvn.wide_ptr_provenance.GVN.diff
|
|
// EMIT_MIR gvn.wide_ptr_same_provenance.GVN.diff
|
|
// EMIT_MIR gvn.wide_ptr_integer.GVN.diff
|
|
// EMIT_MIR gvn.borrowed.GVN.diff
|
|
// EMIT_MIR gvn.non_freeze.GVN.diff
|
|
// EMIT_MIR gvn.slice_const_length.GVN.diff
|
|
// EMIT_MIR gvn.meta_of_ref_to_slice.GVN.diff
|
|
// EMIT_MIR gvn.slice_from_raw_parts_as_ptr.GVN.diff
|
|
// EMIT_MIR gvn.casts_before_aggregate_raw_ptr.GVN.diff
|
|
// EMIT_MIR gvn.manual_slice_mut_len.GVN.diff
|
|
// EMIT_MIR gvn.array_len.GVN.diff
|
|
// EMIT_MIR gvn.generic_cast_metadata.GVN.diff
|
|
// EMIT_MIR gvn.cast_pointer_eq.GVN.diff
|
|
// EMIT_MIR gvn.cast_pointer_then_transmute.GVN.diff
|
|
// EMIT_MIR gvn.remove_casts_must_change_both_sides.GVN.diff
|