diff options
Diffstat (limited to '')
-rw-r--r-- | tests/mir-opt/gvn.rs | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs new file mode 100644 index 000000000..a85e2ae36 --- /dev/null +++ b/tests/mir-opt/gvn.rs @@ -0,0 +1,253 @@ +// unit-test: GVN +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY + +#![feature(raw_ref_op)] +#![feature(rustc_attrs)] +#![allow(unconditional_panic)] + +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 +} + +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 { 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::<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(); +} + +#[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 |