// skip-filecheck // unit-test: GVN // EMIT_MIR_FOR_EACH_PANIC_STRATEGY #![feature(raw_ref_op)] #![feature(rustc_attrs)] #![allow(unconditional_panic)] struct S(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(x: T) -> T { match Some(x) { Some(y) => y, None => panic!(), } } fn repeated_index(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 } fn dereferences(t: &mut u32, u: &impl Copy, s: &S) { 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 { std::mem::transmute::<&str, &[u8]>(s) }; opaque(u); assert_eq!(s.as_ptr(), u.as_ptr()); } fn main() { subexpression_elimination(2, 4, 5); wrap_unwrap(5); repeated_index::(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(); } #[inline(never)] fn opaque(_: impl Sized) {} // 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