diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:42 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:42 +0000 |
commit | cec1877e180393eba0f6ddb0cf97bf3a791631c7 (patch) | |
tree | 47b4dac2a9dd9a40c30c251b4d4a72d7ccf77e9f /tests/mir-opt/gvn.rs | |
parent | Adding debian version 1.74.1+dfsg1-1. (diff) | |
download | rustc-cec1877e180393eba0f6ddb0cf97bf3a791631c7.tar.xz rustc-cec1877e180393eba0f6ddb0cf97bf3a791631c7.zip |
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/mir-opt/gvn.rs')
-rw-r--r-- | tests/mir-opt/gvn.rs | 488 |
1 files changed, 445 insertions, 43 deletions
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index a85e2ae36..10a66ced0 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -1,55 +1,133 @@ // 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) { + // CHECK-LABEL: fn subexpression_elimination( + + // CHECK: [[add:_.*]] = Add(_1, _2); + // CHECK: opaque::<u64>([[add]]) opaque(x + y); + // CHECK: [[mul:_.*]] = Mul(_1, _2); + // CHECK: opaque::<u64>([[mul]]) opaque(x * y); + // CHECK: [[sub:_.*]] = Sub(_1, _2); + // CHECK: opaque::<u64>([[sub]]) opaque(x - y); + // CHECK: [[div:_.*]] = Div(_1, _2); + // CHECK: opaque::<u64>([[div]]) opaque(x / y); + // CHECK: [[rem:_.*]] = Rem(_1, _2); + // CHECK: opaque::<u64>([[rem]]) opaque(x % y); + // CHECK: [[and:_.*]] = BitAnd(_1, _2); + // CHECK: opaque::<u64>([[and]]) opaque(x & y); + // CHECK: [[or:_.*]] = BitOr(_1, _2); + // CHECK: opaque::<u64>([[or]]) opaque(x | y); + // CHECK: [[xor:_.*]] = BitXor(_1, _2); + // CHECK: opaque::<u64>([[xor]]) opaque(x ^ y); + // CHECK: [[shl:_.*]] = Shl(_1, _2); + // CHECK: opaque::<u64>([[shl]]) opaque(x << y); + // CHECK: [[shr:_.*]] = Shr(_1, _2); + // CHECK: opaque::<u64>([[shr]]) opaque(x >> y); + // CHECK: [[int:_.*]] = _1 as u32 (IntToInt); + // CHECK: opaque::<u32>([[int]]) opaque(x as u32); + // CHECK: [[float:_.*]] = _1 as f32 (IntToFloat); + // CHECK: opaque::<f32>([[float]]) opaque(x as f32); + // CHECK: [[wrap:_.*]] = S::<u64>(_1); + // CHECK: opaque::<S<u64>>([[wrap]]) opaque(S(x)); + // CHECK: opaque::<u64>(_1) 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); + // CHECK: opaque::<u64>([[add]]) + opaque(x + y); + // CHECK: opaque::<u64>([[mul]]) + opaque(x * y); + // CHECK: opaque::<u64>([[sub]]) + opaque(x - y); + // CHECK: opaque::<u64>([[div]]) + opaque(x / y); + // CHECK: opaque::<u64>([[rem]]) + opaque(x % y); + // CHECK: opaque::<u64>([[and]]) + opaque(x & y); + // CHECK: opaque::<u64>([[or]]) + opaque(x | y); + // CHECK: opaque::<u64>([[xor]]) + opaque(x ^ y); + // CHECK: opaque::<u64>([[shl]]) + opaque(x << y); + // CHECK: opaque::<u64>([[shr]]) + opaque(x >> y); + // CHECK: opaque::<u32>([[int]]) + opaque(x as u32); + // CHECK: opaque::<f32>([[float]]) + opaque(x as f32); + // CHECK: opaque::<S<u64>>([[wrap]]) opaque(S(x)); + // CHECK: opaque::<u64>(_1) opaque(S(x).0); + // We can substitute through a complex expression. + // CHECK: [[compound:_.*]] = Sub([[mul]], _2); + // CHECK: opaque::<u64>([[compound]]) + // CHECK: opaque::<u64>([[compound]]) + opaque((x * y) - y); + opaque((x * y) - y); + // We can substitute through an immutable reference too. + // CHECK: [[ref:_.*]] = &_3; + // CHECK: [[deref:_.*]] = (*[[ref]]); + // CHECK: [[addref:_.*]] = Add([[deref]], _1); + // CHECK: opaque::<u64>([[addref]]) + // CHECK: opaque::<u64>([[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); @@ -57,13 +135,21 @@ fn subexpression_elimination(x: u64, y: u64, mut z: u64) { // We can substitute again, but not with the earlier computations. // Important: `e` is not `a`! + // CHECK: [[ref2:_.*]] = &_3; + // CHECK: [[deref2:_.*]] = (*[[ref2]]); + // CHECK: [[addref2:_.*]] = Add([[deref2]], _1); + // CHECK: opaque::<u64>([[addref2]]) + // CHECK: opaque::<u64>([[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(_1); + // CHECK: switchInt(const 1_isize) + // CHECK: _0 = _1; match Some(x) { Some(y) => y, None => panic!(), @@ -71,163 +157,464 @@ fn wrap_unwrap<T: Copy>(x: T) -> T { } fn repeated_index<T: Copy, const N: usize>(x: T, idx: usize) { + // CHECK-LABEL: fn repeated_index( + // CHECK: [[a:_.*]] = [_1; N]; let a = [x; N]; + // CHECK: opaque::<T>(_1) opaque(a[0]); + // CHECK: opaque::<T>(_1) opaque(a[idx]); } +/// Verify symbolic integer arithmetic simplifications. fn arithmetic(x: u64) { + // CHECK-LABEL: fn arithmetic( + // CHECK: [[add:_.*]] = Add(_1, const 0_u64); + // CHECK: opaque::<u64>(move [[add]]) opaque(x + 0); + // CHECK: [[sub:_.*]] = Sub(_1, const 0_u64); + // CHECK: opaque::<u64>(move [[sub]]) opaque(x - 0); + // CHECK: [[mul0:_.*]] = Mul(_1, const 0_u64); + // CHECK: opaque::<u64>(move [[mul0]]) opaque(x * 0); + // CHECK: [[mul1:_.*]] = Mul(_1, const 1_u64); + // CHECK: opaque::<u64>(move [[mul1]]) opaque(x * 1); + // CHECK: [[div0:_.*]] = Div(_1, const 0_u64); + // CHECK: opaque::<u64>(move [[div0]]) opaque(x / 0); + // CHECK: [[div1:_.*]] = Div(_1, const 1_u64); + // CHECK: opaque::<u64>(move [[div1]]) opaque(x / 1); + // CHECK: [[zdiv:_.*]] = Div(const 0_u64, _1); + // CHECK: opaque::<u64>(move [[zdiv]]) opaque(0 / x); + // CHECK: [[odiv:_.*]] = Div(const 1_u64, _1); + // CHECK: opaque::<u64>(move [[odiv]]) opaque(1 / x); + // CHECK: [[rem0:_.*]] = Rem(_1, const 0_u64); + // CHECK: opaque::<u64>(move [[rem0]]) opaque(x % 0); + // CHECK: [[rem1:_.*]] = Rem(_1, const 1_u64); + // CHECK: opaque::<u64>(move [[rem1]]) opaque(x % 1); + // CHECK: [[zrem:_.*]] = Rem(const 0_u64, _1); + // CHECK: opaque::<u64>(move [[zrem]]) opaque(0 % x); + // CHECK: [[orem:_.*]] = Rem(const 1_u64, _1); + // CHECK: opaque::<u64>(move [[orem]]) opaque(1 % x); + // CHECK: [[and:_.*]] = BitAnd(_1, const 0_u64); + // CHECK: opaque::<u64>(move [[and]]) opaque(x & 0); + // CHECK: [[or:_.*]] = BitOr(_1, const 0_u64); + // CHECK: opaque::<u64>(move [[or]]) opaque(x | 0); + // CHECK: [[xor:_.*]] = BitXor(_1, const 0_u64); + // CHECK: opaque::<u64>(move [[xor]]) opaque(x ^ 0); + // CHECK: [[shr:_.*]] = Shr(_1, const 0_i32); + // CHECK: opaque::<u64>(move [[shr]]) opaque(x >> 0); + // CHECK: [[shl:_.*]] = Shl(_1, const 0_i32); + // CHECK: opaque::<u64>(move [[shl]]) opaque(x << 0); } +fn comparison(x: u64, y: u64) { + // CHECK-LABEL: fn comparison( + // CHECK: [[eqxx:_.*]] = Eq(_1, _1); + // CHECK: opaque::<bool>(move [[eqxx]]) + opaque(x == x); + // CHECK: [[nexx:_.*]] = Ne(_1, _1); + // CHECK: opaque::<bool>(move [[nexx]]) + opaque(x != x); + // CHECK: [[eqxy:_.*]] = Eq(_1, _2); + // CHECK: opaque::<bool>(move [[eqxy]]) + opaque(x == y); + // CHECK: [[nexy:_.*]] = Ne(_1, _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: [[cadd:_.*]] = CheckedAdd(_1, const 0_u64); + // CHECK: [[add:_.*]] = move ([[cadd]].0: u64); + // CHECK: opaque::<u64>(move [[add]]) opaque(x + 0); + // CHECK: [[csub:_.*]] = CheckedSub(_1, const 0_u64); + // CHECK: [[sub:_.*]] = move ([[csub]].0: u64); + // CHECK: opaque::<u64>(move [[sub]]) opaque(x - 0); + // CHECK: [[cmul0:_.*]] = CheckedMul(_1, const 0_u64); + // CHECK: [[mul0:_.*]] = move ([[cmul0]].0: u64); + // CHECK: opaque::<u64>(move [[mul0]]) opaque(x * 0); + // CHECK: [[cmul1:_.*]] = CheckedMul(_1, const 1_u64); + // CHECK: [[mul1:_.*]] = move ([[cmul1]].0: u64); + // CHECK: opaque::<u64>(move [[mul1]]) 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); } +/// Verify that we do not apply arithmetic simplifications on floats. fn arithmetic_float(x: f64) { + // CHECK-LABEL: fn arithmetic_float( + // CHECK: [[add:_.*]] = Add(_1, const 0f64); + // CHECK: opaque::<f64>(move [[add]]) opaque(x + 0.); + // CHECK: [[sub:_.*]] = Sub(_1, const 0f64); + // CHECK: opaque::<f64>(move [[sub]]) opaque(x - 0.); + // CHECK: [[mul:_.*]] = Mul(_1, const 0f64); + // CHECK: opaque::<f64>(move [[mul]]) opaque(x * 0.); + // CHECK: [[div0:_.*]] = Div(_1, const 0f64); + // CHECK: opaque::<f64>(move [[div0]]) opaque(x / 0.); + // CHECK: [[zdiv:_.*]] = Div(const 0f64, _1); + // CHECK: opaque::<f64>(move [[zdiv]]) opaque(0. / x); + // CHECK: [[rem0:_.*]] = Rem(_1, const 0f64); + // CHECK: opaque::<f64>(move [[rem0]]) opaque(x % 0.); + // CHECK: [[zrem:_.*]] = Rem(const 0f64, _1); + // CHECK: opaque::<f64>(move [[zrem]]) opaque(0. % x); // Those are not simplifiable to `true`/`false`, thanks to NaNs. + // CHECK: [[eq:_.*]] = Eq(_1, _1); + // CHECK: opaque::<bool>(move [[eq]]) opaque(x == x); + // CHECK: [[ne:_.*]] = Ne(_1, _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(_1) -> [0: [[bbf:bb.*]], otherwise: [[bbt:bb.*]]]; if t { - opaque(x + y); // a - opaque(x + y); // should reuse a + // CHECK: [[bbt]]: { + // CHECK: [[a:_.*]] = Add(_2, _3); + // CHECK: opaque::<u8>([[a]]) + // CHECK: opaque::<u8>([[a]]) + // CHECK: goto -> [[bbc:bb.*]]; + opaque(x + y); + opaque(x + y); } else { - opaque(x + y); // b - opaque(x + y); // shoud reuse b + // CHECK: [[bbf]]: { + // CHECK: [[b:_.*]] = Add(_2, _3); + // CHECK: opaque::<u8>([[b]]) + // CHECK: opaque::<u8>([[b]]) + // CHECK: goto -> [[bbc:bb.*]]; + opaque(x + y); + opaque(x + y); } - opaque(x + y); // c + // Neither `a` nor `b` dominate `c`, so we cannot reuse any of them. + // CHECK: [[bbc]]: { + // CHECK: [[c:_.*]] = Add(_2, _3); + // CHECK: opaque::<u8>([[c]]) + opaque(x + y); + + // `c` dominates both calls, so we can reuse it. if t { - opaque(x + y); // should reuse c + // CHECK: opaque::<u8>([[c]]) + opaque(x + y); } else { - opaque(x + y); // should reuse c + // CHECK: opaque::<u8>([[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); - opaque(&x); // should not reuse a + // 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); - opaque(&mut x); // should not reuse a + // CHECK: [[ref5:_.*]] = &raw const _1; + // CHECK: opaque::<*const impl Sized>(move [[ref5]]) opaque(&raw const x); - opaque(&raw const x); // should not reuse a + // 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); - opaque(&raw mut x); // should not reuse a + + 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:_.*]] = (*_1); + // CHECK: opaque::<u32>(move [[st1]]) + // CHECK: [[st2:_.*]] = (*_1); + // CHECK: opaque::<u32>(move [[st2]]) opaque(*t); - opaque(*t); // this cannot reuse a, as x is &mut. + opaque(*t); + + // Do not reuse dereferences of `*const`. + // CHECK: [[raw:_.*]] = &raw const (*_1); + // CHECK: [[st3:_.*]] = (*[[raw]]); + // CHECK: opaque::<u32>(move [[st3]]) + // CHECK: [[st4:_.*]] = (*[[raw]]); + // CHECK: opaque::<u32>(move [[st4]]) let z = &raw const *t; unsafe { opaque(*z) }; - unsafe { opaque(*z) }; // this cannot reuse a, as x is *const. + unsafe { opaque(*z) }; + + // Do not reuse dereferences of `*mut`. + // CHECK: [[ptr:_.*]] = &raw mut (*_1); + // CHECK: [[st5:_.*]] = (*[[ptr]]); + // CHECK: opaque::<u32>(move [[st5]]) + // CHECK: [[st6:_.*]] = (*[[ptr]]); + // CHECK: opaque::<u32>(move [[st6]]) let z = &raw mut *t; unsafe { opaque(*z) }; - unsafe { opaque(*z) }; // this cannot reuse a, as x is *mut. + unsafe { opaque(*z) }; + + // We can reuse dereferences of `&Freeze`. + // CHECK: [[ref:_.*]] = &(*_1); + // CHECK: [[st7:_.*]] = (*[[ref]]); + // CHECK: opaque::<u32>([[st7]]) + // CHECK: opaque::<u32>([[st7]]) 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(*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:_.*]] = (*_2); + // CHECK: opaque::<impl Copy>(move [[st8]]) + // CHECK: [[st9:_.*]] = (*_2); + // CHECK: opaque::<impl Copy>(move [[st9]]) opaque(*u); - opaque(*u); // this cannot reuse, as `z` is not Freeze. + opaque(*u); + + // `*s` is not Copy, by `(*s).0` is, so we can reuse. + // CHECK: [[st10:_.*]] = ((*_3).0: u32); + // CHECK: opaque::<u32>([[st10]]) + // CHECK: opaque::<u32>([[st10]]) + opaque(s.0); opaque(s.0); - opaque(s.0); // *s is not Copy, by (*s).0 is, so we can reuse. } 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 { std::mem::transmute::<&str, &[u8]>(s) }; + 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:_.*]] = ([[a]].0: &str) as u128 (Transmute); + let a = ("a",); + Call(au = transmute::<_, u128>(a.0), bb1) + } + bb1 = { + // CHECK: [[c:_.*]] = identity::<&str>(([[a]].0: &str)) + Call(c = identity(a.0), bb2) + } + bb2 = { + // CHECK: [[cu:_.*]] = [[c]] as u128 (Transmute); + Call(cu = transmute::<_, u128>(c), bb3) + } + bb3 = { + // This slice is different from `a.0`. Hence `bu` is not `au`. + // CHECK: [[b:_.*]] = const "a"; + // CHECK: [[bu:_.*]] = [[b]] as u128 (Transmute); + let b = "a"; + Call(bu = transmute::<_, u128>(b), bb4) + } + bb4 = { + // This returns a copy of `b`, which is not `a`. + // CHECK: [[d:_.*]] = identity::<&str>([[b]]) + Call(d = identity(b), bb5) + } + bb5 = { + // CHECK: [[du:_.*]] = [[d]] as u128 (Transmute); + Call(du = transmute::<_, u128>(d), bb6) + } + bb6 = { + // `direct` must not fold to `true`, as `indirect` will not. + // CHECK: = Eq([[au]], [[bu]]); + // CHECK: = Eq([[cu]], [[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>([[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>([[g]]) + let g = identity as fn(u8) -> u8; + opaque(g); + + // CHECK: [[cf:_.*]] = const {{.*}} as fn() (PointerCoercion(ClosureFnPointer + // CHECK: opaque::<fn()>([[cf]]) + let closure = || {}; + let cf = closure as fn(); + opaque(cf); + // CHECK: [[cg:_.*]] = const {{.*}} as fn() (PointerCoercion(ClosureFnPointer + // CHECK: opaque::<fn()>([[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() + }) +} + fn main() { subexpression_elimination(2, 4, 5); wrap_unwrap(5); repeated_index::<u32, 7>(5, 3); arithmetic(5); + comparison(5, 6); arithmetic_checked(5); arithmetic_float(5.); cast(); @@ -235,15 +622,26 @@ fn main() { references(5); dereferences(&mut 5, &6, &S(7)); slices(); + let (direct, indirect) = duplicate_slice(); + assert_eq!(direct, indirect); + repeat(); + fn_pointers(); + indirect_static(); } #[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.comparison.GVN.diff // EMIT_MIR gvn.arithmetic_checked.GVN.diff // EMIT_MIR gvn.arithmetic_float.GVN.diff // EMIT_MIR gvn.cast.GVN.diff @@ -251,3 +649,7 @@ fn opaque(_: impl Sized) {} // 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 |