summaryrefslogtreecommitdiffstats
path: root/tests/mir-opt/gvn.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /tests/mir-opt/gvn.rs
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--tests/mir-opt/gvn.rs488
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