mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
326 lines
7.6 KiB
Rust
326 lines
7.6 KiB
Rust
// skip-filecheck
|
|
// unit-test: GVN
|
|
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
|
|
// only-64bit
|
|
|
|
#![feature(raw_ref_op)]
|
|
#![feature(rustc_attrs)]
|
|
#![feature(custom_mir)]
|
|
#![feature(core_intrinsics)]
|
|
#![allow(unconditional_panic)]
|
|
|
|
use std::intrinsics::mir::*;
|
|
use std::mem::transmute;
|
|
|
|
struct S<T>(T);
|
|
|
|
fn subexpression_elimination(x: u64, y: u64, mut z: u64) {
|
|
opaque(x + y);
|
|
opaque(x * y);
|
|
opaque(x - y);
|
|
opaque(x / y);
|
|
opaque(x % y);
|
|
opaque(x & y);
|
|
opaque(x | y);
|
|
opaque(x ^ y);
|
|
opaque(x << y);
|
|
opaque(x >> y);
|
|
opaque(x as u32);
|
|
opaque(x as f32);
|
|
opaque(S(x));
|
|
opaque(S(x).0);
|
|
|
|
// Those are duplicates to substitute somehow.
|
|
opaque((x + y) + z);
|
|
opaque((x * y) + z);
|
|
opaque((x - y) + z);
|
|
opaque((x / y) + z);
|
|
opaque((x % y) + z);
|
|
opaque((x & y) + z);
|
|
opaque((x | y) + z);
|
|
opaque((x ^ y) + z);
|
|
opaque((x << y) + z);
|
|
opaque((x >> y) + z);
|
|
opaque(S(x));
|
|
opaque(S(x).0);
|
|
|
|
// We can substitute through an immutable reference too.
|
|
let a = &z;
|
|
opaque(*a + x);
|
|
opaque(*a + x);
|
|
|
|
// But not through a mutable reference or a pointer.
|
|
let b = &mut z;
|
|
opaque(*b + x);
|
|
opaque(*b + x);
|
|
unsafe {
|
|
let c = &raw const z;
|
|
opaque(*c + x);
|
|
opaque(*c + x);
|
|
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`!
|
|
let e = &z;
|
|
opaque(*e + x);
|
|
opaque(*e + x);
|
|
}
|
|
|
|
fn wrap_unwrap<T: Copy>(x: T) -> T {
|
|
match Some(x) {
|
|
Some(y) => y,
|
|
None => panic!(),
|
|
}
|
|
}
|
|
|
|
fn repeated_index<T: Copy, const N: usize>(x: T, idx: usize) {
|
|
let a = [x; N];
|
|
opaque(a[0]);
|
|
opaque(a[idx]);
|
|
}
|
|
|
|
fn arithmetic(x: u64) {
|
|
opaque(x + 0);
|
|
opaque(x - 0);
|
|
opaque(x * 0);
|
|
opaque(x * 1);
|
|
opaque(x / 0);
|
|
opaque(x / 1);
|
|
opaque(0 / x);
|
|
opaque(1 / x);
|
|
opaque(x % 0);
|
|
opaque(x % 1);
|
|
opaque(0 % x);
|
|
opaque(1 % x);
|
|
opaque(x & 0);
|
|
opaque(x | 0);
|
|
opaque(x ^ 0);
|
|
opaque(x >> 0);
|
|
opaque(x << 0);
|
|
}
|
|
|
|
#[rustc_inherit_overflow_checks]
|
|
fn arithmetic_checked(x: u64) {
|
|
opaque(x + 0);
|
|
opaque(x - 0);
|
|
opaque(x * 0);
|
|
opaque(x * 1);
|
|
opaque(x / 0);
|
|
opaque(x / 1);
|
|
opaque(0 / x);
|
|
opaque(1 / x);
|
|
opaque(x % 0);
|
|
opaque(x % 1);
|
|
opaque(0 % x);
|
|
opaque(1 % x);
|
|
opaque(x & 0);
|
|
opaque(x | 0);
|
|
opaque(x ^ 0);
|
|
opaque(x >> 0);
|
|
opaque(x << 0);
|
|
}
|
|
|
|
fn arithmetic_float(x: f64) {
|
|
opaque(x + 0.);
|
|
opaque(x - 0.);
|
|
opaque(x * 0.);
|
|
opaque(x / 0.);
|
|
opaque(0. / x);
|
|
opaque(x % 0.);
|
|
opaque(0. % x);
|
|
// Those are not simplifiable to `true`/`false`, thanks to NaNs.
|
|
opaque(x == x);
|
|
opaque(x != x);
|
|
}
|
|
|
|
fn cast() {
|
|
let i = 1_i64;
|
|
let u = 1_u64;
|
|
let f = 1_f64;
|
|
opaque(i as u8);
|
|
opaque(i as u16);
|
|
opaque(i as u32);
|
|
opaque(i as u64);
|
|
opaque(i as i8);
|
|
opaque(i as i16);
|
|
opaque(i as i32);
|
|
opaque(i as i64);
|
|
opaque(i as f32);
|
|
opaque(i as f64);
|
|
opaque(u as u8);
|
|
opaque(u as u16);
|
|
opaque(u as u32);
|
|
opaque(u as u64);
|
|
opaque(u as i8);
|
|
opaque(u as i16);
|
|
opaque(u as i32);
|
|
opaque(u as i64);
|
|
opaque(u as f32);
|
|
opaque(u as f64);
|
|
opaque(f as u8);
|
|
opaque(f as u16);
|
|
opaque(f as u32);
|
|
opaque(f as u64);
|
|
opaque(f as i8);
|
|
opaque(f as i16);
|
|
opaque(f as i32);
|
|
opaque(f as i64);
|
|
opaque(f as f32);
|
|
opaque(f as f64);
|
|
}
|
|
|
|
fn multiple_branches(t: bool, x: u8, y: u8) {
|
|
if t {
|
|
opaque(x + y); // a
|
|
opaque(x + y); // should reuse a
|
|
} else {
|
|
opaque(x + y); // b
|
|
opaque(x + y); // shoud reuse b
|
|
}
|
|
opaque(x + y); // c
|
|
if t {
|
|
opaque(x + y); // should reuse c
|
|
} else {
|
|
opaque(x + y); // should reuse c
|
|
}
|
|
}
|
|
|
|
fn references(mut x: impl Sized) {
|
|
opaque(&x);
|
|
opaque(&x); // should not reuse a
|
|
opaque(&mut x);
|
|
opaque(&mut x); // should not reuse a
|
|
opaque(&raw const x);
|
|
opaque(&raw const x); // should not reuse a
|
|
opaque(&raw mut x);
|
|
opaque(&raw mut x); // should not reuse a
|
|
|
|
let r = &mut x;
|
|
let s = S(r).0; // Obfuscate `r`.
|
|
opaque(&*s); // This is `&*r`.
|
|
opaque(&mut *s); // This is `&*r`.
|
|
opaque(&raw const *s); // This is `&*r`.
|
|
opaque(&raw mut *s); // This is `&*r`.
|
|
}
|
|
|
|
fn dereferences(t: &mut u32, u: &impl Copy, s: &S<u32>) {
|
|
opaque(*t);
|
|
opaque(*t); // this cannot reuse a, as x is &mut.
|
|
let z = &raw const *t;
|
|
unsafe { opaque(*z) };
|
|
unsafe { opaque(*z) }; // this cannot reuse a, as x is *const.
|
|
let z = &raw mut *t;
|
|
unsafe { opaque(*z) };
|
|
unsafe { opaque(*z) }; // this cannot reuse a, as x is *mut.
|
|
let z = &*t;
|
|
opaque(*z);
|
|
opaque(*z); // this can reuse, as `z` is immutable ref, Freeze and Copy.
|
|
opaque(&*z); // but not for a reborrow.
|
|
opaque(*u);
|
|
opaque(*u); // this cannot reuse, as `z` is not Freeze.
|
|
opaque(s.0);
|
|
opaque(s.0); // *s is not Copy, by (*s).0 is, so we can reuse.
|
|
}
|
|
|
|
fn slices() {
|
|
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) {
|
|
mir!(
|
|
let au: u128;
|
|
let bu: u128;
|
|
let cu: u128;
|
|
let du: u128;
|
|
let c: &str;
|
|
let d: &str;
|
|
{
|
|
let a = ("a",);
|
|
Call(au = transmute::<_, u128>(a.0), bb1)
|
|
}
|
|
bb1 = {
|
|
Call(c = identity(a.0), bb2)
|
|
}
|
|
bb2 = {
|
|
Call(cu = transmute::<_, u128>(c), bb3)
|
|
}
|
|
bb3 = {
|
|
let b = "a"; // This slice is different from `a.0`.
|
|
Call(bu = transmute::<_, u128>(b), bb4) // Hence `bu` is not `au`.
|
|
}
|
|
bb4 = {
|
|
Call(d = identity(b), bb5) // This returns a copy of `b`, which is not `a`.
|
|
}
|
|
bb5 = {
|
|
Call(du = transmute::<_, u128>(d), bb6)
|
|
}
|
|
bb6 = {
|
|
let direct = au == bu; // Must not fold to `true`...
|
|
let indirect = cu == du; // ...as this will not.
|
|
RET = (direct, indirect);
|
|
Return()
|
|
}
|
|
)
|
|
}
|
|
|
|
fn aggregates() {
|
|
let a_array: S<[u8; 0]> = S([]);
|
|
let b_array: S<[u16; 0]> = S([]); // This must not be merged with `a_array`.
|
|
|
|
let a_tuple: S<()> = S(());
|
|
let b_tuple: S<()> = S(()); // But this can be with `a_tuple`.
|
|
|
|
let val = 5;
|
|
let array = [val, val, val, val, val, val, val, val, val, val];
|
|
}
|
|
|
|
fn main() {
|
|
subexpression_elimination(2, 4, 5);
|
|
wrap_unwrap(5);
|
|
repeated_index::<u32, 7>(5, 3);
|
|
arithmetic(5);
|
|
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);
|
|
aggregates();
|
|
}
|
|
|
|
#[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.arithmetic.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.aggregates.GVN.diff
|