rust/tests/mir-opt/gvn.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

883 lines
27 KiB
Rust
Raw Normal View History

//@ test-mir-pass: GVN
2023-03-20 18:05:07 +00:00
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
//@ only-64bit
2023-03-20 18:05:07 +00:00
#![feature(raw_ref_op)]
#![feature(rustc_attrs)]
#![feature(custom_mir)]
#![feature(core_intrinsics)]
2024-04-07 18:33:18 +00:00
#![feature(freeze)]
2023-03-20 18:05:07 +00:00
#![allow(unconditional_panic)]
use std::intrinsics::mir::*;
2024-04-07 18:33:18 +00:00
use std::marker::Freeze;
use std::mem::transmute;
2023-03-20 18:05:07 +00:00
struct S<T>(T);
fn subexpression_elimination(x: u64, y: u64, mut z: u64) {
2023-10-16 21:44:36 +00:00
// CHECK-LABEL: fn subexpression_elimination(
// CHECK: [[add:_.*]] = Add(_1, _2);
// CHECK: opaque::<u64>([[add]])
2023-03-20 18:05:07 +00:00
opaque(x + y);
2023-10-16 21:44:36 +00:00
// CHECK: [[mul:_.*]] = Mul(_1, _2);
// CHECK: opaque::<u64>([[mul]])
2023-03-20 18:05:07 +00:00
opaque(x * y);
2023-10-16 21:44:36 +00:00
// CHECK: [[sub:_.*]] = Sub(_1, _2);
// CHECK: opaque::<u64>([[sub]])
2023-03-20 18:05:07 +00:00
opaque(x - y);
2023-10-16 21:44:36 +00:00
// CHECK: [[div:_.*]] = Div(_1, _2);
// CHECK: opaque::<u64>([[div]])
2023-03-20 18:05:07 +00:00
opaque(x / y);
2023-10-16 21:44:36 +00:00
// CHECK: [[rem:_.*]] = Rem(_1, _2);
// CHECK: opaque::<u64>([[rem]])
2023-03-20 18:05:07 +00:00
opaque(x % y);
2023-10-16 21:44:36 +00:00
// CHECK: [[and:_.*]] = BitAnd(_1, _2);
// CHECK: opaque::<u64>([[and]])
2023-03-20 18:05:07 +00:00
opaque(x & y);
2023-10-16 21:44:36 +00:00
// CHECK: [[or:_.*]] = BitOr(_1, _2);
// CHECK: opaque::<u64>([[or]])
2023-03-20 18:05:07 +00:00
opaque(x | y);
2023-10-16 21:44:36 +00:00
// CHECK: [[xor:_.*]] = BitXor(_1, _2);
// CHECK: opaque::<u64>([[xor]])
2023-03-20 18:05:07 +00:00
opaque(x ^ y);
2023-10-16 21:44:36 +00:00
// CHECK: [[shl:_.*]] = Shl(_1, _2);
// CHECK: opaque::<u64>([[shl]])
2023-03-20 18:05:07 +00:00
opaque(x << y);
2023-10-16 21:44:36 +00:00
// CHECK: [[shr:_.*]] = Shr(_1, _2);
// CHECK: opaque::<u64>([[shr]])
2023-03-20 18:05:07 +00:00
opaque(x >> y);
2023-10-16 21:44:36 +00:00
// CHECK: [[int:_.*]] = _1 as u32 (IntToInt);
// CHECK: opaque::<u32>([[int]])
2023-03-20 18:05:07 +00:00
opaque(x as u32);
2023-10-16 21:44:36 +00:00
// CHECK: [[float:_.*]] = _1 as f32 (IntToFloat);
// CHECK: opaque::<f32>([[float]])
2023-03-20 18:05:07 +00:00
opaque(x as f32);
2023-10-16 21:44:36 +00:00
// CHECK: [[wrap:_.*]] = S::<u64>(_1);
// CHECK: opaque::<S<u64>>([[wrap]])
2023-03-20 18:05:07 +00:00
opaque(S(x));
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u64>(_1)
2023-03-20 18:05:07 +00:00
opaque(S(x).0);
// Those are duplicates to substitute somehow.
2023-10-16 21:44:36 +00:00
// 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]])
2023-05-01 09:59:00 +00:00
opaque(S(x));
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u64>(_1)
2023-05-01 09:59:00 +00:00
opaque(S(x).0);
2023-03-20 18:05:07 +00:00
2023-10-16 21:44:36 +00:00
// 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);
2023-03-20 18:05:07 +00:00
// We can substitute through an immutable reference too.
2023-10-16 21:44:36 +00:00
// CHECK: [[ref:_.*]] = &_3;
// CHECK: [[deref:_.*]] = (*[[ref]]);
// CHECK: [[addref:_.*]] = Add([[deref]], _1);
// CHECK: opaque::<u64>([[addref]])
// CHECK: opaque::<u64>([[addref]])
2023-03-20 18:05:07 +00:00
let a = &z;
opaque(*a + x);
opaque(*a + x);
// But not through a mutable reference or a pointer.
2023-10-16 21:44:36 +00:00
// CHECK: [[mut:_.*]] = &mut _3;
// CHECK: [[addmut:_.*]] = Add(
// CHECK: opaque::<u64>(move [[addmut]])
// CHECK: [[addmut2:_.*]] = Add(
// CHECK: opaque::<u64>(move [[addmut2]])
2023-03-20 18:05:07 +00:00
let b = &mut z;
opaque(*b + x);
opaque(*b + x);
unsafe {
2023-10-16 21:44:36 +00:00
// CHECK: [[raw:_.*]] = &raw const _3;
// CHECK: [[addraw:_.*]] = Add(
// CHECK: opaque::<u64>(move [[addraw]])
// CHECK: [[addraw2:_.*]] = Add(
// CHECK: opaque::<u64>(move [[addraw2]])
2023-03-20 18:05:07 +00:00
let c = &raw const z;
opaque(*c + x);
opaque(*c + x);
2023-10-16 21:44:36 +00:00
// CHECK: [[ptr:_.*]] = &raw mut _3;
// CHECK: [[addptr:_.*]] = Add(
// CHECK: opaque::<u64>(move [[addptr]])
// CHECK: [[addptr2:_.*]] = Add(
// CHECK: opaque::<u64>(move [[addptr2]])
2023-03-20 18:05:07 +00:00
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`!
2023-10-16 21:44:36 +00:00
// CHECK: [[ref2:_.*]] = &_3;
// CHECK: [[deref2:_.*]] = (*[[ref2]]);
// CHECK: [[addref2:_.*]] = Add([[deref2]], _1);
// CHECK: opaque::<u64>([[addref2]])
// CHECK: opaque::<u64>([[addref2]])
2023-03-20 18:05:07 +00:00
let e = &z;
opaque(*e + x);
opaque(*e + x);
}
fn wrap_unwrap<T: Copy>(x: T) -> T {
2023-10-16 21:44:36 +00:00
// CHECK-LABEL: fn wrap_unwrap(
// CHECK: [[some:_.*]] = Option::<T>::Some(_1);
// CHECK: switchInt(const 1_isize)
// CHECK: _0 = _1;
2023-03-20 18:05:07 +00:00
match Some(x) {
Some(y) => y,
None => panic!(),
}
}
fn repeated_index<T: Copy, const N: usize>(x: T, idx: usize) {
2023-10-16 21:44:36 +00:00
// CHECK-LABEL: fn repeated_index(
// CHECK: [[a:_.*]] = [_1; N];
2023-03-20 18:05:07 +00:00
let a = [x; N];
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<T>(_1)
2023-03-20 18:05:07 +00:00
opaque(a[0]);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<T>(_1)
2023-03-20 18:05:07 +00:00
opaque(a[idx]);
}
2023-03-25 22:33:35 +00:00
fn unary(x: i64) {
// CHECK-LABEL: fn unary(
// CHECK: opaque::<i64>(_1)
opaque(--x); // This is `x`.
// CHECK: [[b:_.*]] = Lt(_1, const 13_i64);
// CHECK: opaque::<bool>([[b]])
let b = x < 13;
opaque(!!b); // This is `b`.
// Both lines should test the same thing.
// CHECK: [[c:_.*]] = Ne(_1, const 15_i64);
// CHECK: opaque::<bool>([[c]])
// CHECK: opaque::<bool>([[c]])
opaque(x != 15);
opaque(!(x == 15));
// Both lines should test the same thing.
// CHECK: [[d:_.*]] = Eq(_1, const 35_i64);
// CHECK: opaque::<bool>([[d]])
// CHECK: opaque::<bool>([[d]])
opaque(x == 35);
opaque(!(x != 35));
}
2023-10-16 21:44:36 +00:00
/// Verify symbolic integer arithmetic simplifications.
2023-03-20 18:05:07 +00:00
fn arithmetic(x: u64) {
2023-10-16 21:44:36 +00:00
// CHECK-LABEL: fn arithmetic(
2023-03-20 21:37:36 +00:00
// CHECK: opaque::<u64>(_1)
2023-03-20 18:05:07 +00:00
opaque(x + 0);
2023-03-20 21:37:36 +00:00
// CHECK: opaque::<u64>(_1)
2023-03-20 18:05:07 +00:00
opaque(x - 0);
2023-03-20 21:37:36 +00:00
// CHECK: opaque::<u64>(const 0_u64)
opaque(x - x);
// CHECK: opaque::<u64>(const 0_u64)
2023-03-20 18:05:07 +00:00
opaque(x * 0);
2023-03-20 21:37:36 +00:00
// CHECK: opaque::<u64>(_1)
2023-03-20 18:05:07 +00:00
opaque(x * 1);
2023-03-20 21:37:36 +00:00
// CHECK: assert(!const true, "attempt to divide `{}` by zero",
2023-10-16 21:44:36 +00:00
// CHECK: [[div0:_.*]] = Div(_1, const 0_u64);
// CHECK: opaque::<u64>(move [[div0]])
2023-03-20 18:05:07 +00:00
opaque(x / 0);
2023-03-20 21:37:36 +00:00
// CHECK: opaque::<u64>(_1)
2023-03-20 18:05:07 +00:00
opaque(x / 1);
2023-03-20 21:37:36 +00:00
// CHECK: opaque::<u64>(const 0_u64)
2023-03-20 18:05:07 +00:00
opaque(0 / x);
2023-10-16 21:44:36 +00:00
// CHECK: [[odiv:_.*]] = Div(const 1_u64, _1);
// CHECK: opaque::<u64>(move [[odiv]])
2023-03-20 18:05:07 +00:00
opaque(1 / x);
2023-03-20 21:37:36 +00:00
// CHECK: assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero"
2023-10-16 21:44:36 +00:00
// CHECK: [[rem0:_.*]] = Rem(_1, const 0_u64);
// CHECK: opaque::<u64>(move [[rem0]])
2023-03-20 18:05:07 +00:00
opaque(x % 0);
2023-03-20 21:37:36 +00:00
// CHECK: opaque::<u64>(const 0_u64)
2023-03-20 18:05:07 +00:00
opaque(x % 1);
2023-03-20 21:37:36 +00:00
// CHECK: opaque::<u64>(const 0_u64)
2023-03-20 18:05:07 +00:00
opaque(0 % x);
2023-10-16 21:44:36 +00:00
// CHECK: [[orem:_.*]] = Rem(const 1_u64, _1);
// CHECK: opaque::<u64>(move [[orem]])
2023-03-20 18:05:07 +00:00
opaque(1 % x);
2023-03-20 21:37:36 +00:00
// CHECK: opaque::<u64>(const 0_u64)
2023-03-20 18:05:07 +00:00
opaque(x & 0);
2023-03-20 21:37:36 +00:00
// CHECK: opaque::<u64>(_1)
opaque(x & u64::MAX);
// CHECK: opaque::<u64>(_1)
2023-03-20 18:05:07 +00:00
opaque(x | 0);
2023-03-20 21:37:36 +00:00
// CHECK: opaque::<u64>(const u64::MAX)
opaque(x | u64::MAX);
// CHECK: opaque::<u64>(_1)
2023-03-20 18:05:07 +00:00
opaque(x ^ 0);
2023-03-20 21:37:36 +00:00
// CHECK: opaque::<u64>(const 0_u64)
opaque(x ^ x);
// CHECK: opaque::<u64>(_1)
2023-03-20 18:05:07 +00:00
opaque(x >> 0);
2023-03-20 21:37:36 +00:00
// CHECK: opaque::<u64>(_1)
2023-03-20 18:05:07 +00:00
opaque(x << 0);
}
2023-10-16 21:44:36 +00:00
fn comparison(x: u64, y: u64) {
// CHECK-LABEL: fn comparison(
2023-03-20 21:37:36 +00:00
// CHECK: opaque::<bool>(const true)
2023-10-16 21:44:36 +00:00
opaque(x == x);
2023-03-20 21:37:36 +00:00
// CHECK: opaque::<bool>(const false)
2023-10-16 21:44:36 +00:00
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.
2023-03-20 18:05:07 +00:00
#[rustc_inherit_overflow_checks]
fn arithmetic_checked(x: u64) {
2023-10-16 21:44:36 +00:00
// CHECK-LABEL: fn arithmetic_checked(
2023-03-20 21:37:36 +00:00
// CHECK: assert(!const false,
// CHECK: opaque::<u64>(_1)
2023-03-20 18:05:07 +00:00
opaque(x + 0);
2023-03-20 21:37:36 +00:00
// CHECK: assert(!const false,
// CHECK: opaque::<u64>(_1)
2023-03-20 18:05:07 +00:00
opaque(x - 0);
2023-03-20 21:37:36 +00:00
// CHECK: assert(!const false,
// CHECK: opaque::<u64>(const 0_u64)
opaque(x - x);
// CHECK: assert(!const false,
// CHECK: opaque::<u64>(const 0_u64)
2023-03-20 18:05:07 +00:00
opaque(x * 0);
2023-03-20 21:37:36 +00:00
// CHECK: assert(!const false,
// CHECK: opaque::<u64>(_1)
2023-03-20 18:05:07 +00:00
opaque(x * 1);
}
2023-10-16 21:44:36 +00:00
/// Verify that we do not apply arithmetic simplifications on floats.
2023-03-20 18:05:07 +00:00
fn arithmetic_float(x: f64) {
2023-10-16 21:44:36 +00:00
// CHECK-LABEL: fn arithmetic_float(
// CHECK: [[add:_.*]] = Add(_1, const 0f64);
// CHECK: opaque::<f64>(move [[add]])
2023-03-20 18:05:07 +00:00
opaque(x + 0.);
2023-10-16 21:44:36 +00:00
// CHECK: [[sub:_.*]] = Sub(_1, const 0f64);
// CHECK: opaque::<f64>(move [[sub]])
2023-03-20 18:05:07 +00:00
opaque(x - 0.);
2023-10-16 21:44:36 +00:00
// CHECK: [[mul:_.*]] = Mul(_1, const 0f64);
// CHECK: opaque::<f64>(move [[mul]])
2023-03-20 18:05:07 +00:00
opaque(x * 0.);
2023-10-16 21:44:36 +00:00
// CHECK: [[div0:_.*]] = Div(_1, const 0f64);
// CHECK: opaque::<f64>(move [[div0]])
2023-03-20 18:05:07 +00:00
opaque(x / 0.);
2023-10-16 21:44:36 +00:00
// CHECK: [[zdiv:_.*]] = Div(const 0f64, _1);
// CHECK: opaque::<f64>(move [[zdiv]])
2023-03-20 18:05:07 +00:00
opaque(0. / x);
2023-10-16 21:44:36 +00:00
// CHECK: [[rem0:_.*]] = Rem(_1, const 0f64);
// CHECK: opaque::<f64>(move [[rem0]])
2023-03-20 18:05:07 +00:00
opaque(x % 0.);
2023-10-16 21:44:36 +00:00
// CHECK: [[zrem:_.*]] = Rem(const 0f64, _1);
// CHECK: opaque::<f64>(move [[zrem]])
2023-03-20 18:05:07 +00:00
opaque(0. % x);
// Those are not simplifiable to `true`/`false`, thanks to NaNs.
2023-10-16 21:44:36 +00:00
// CHECK: [[eq:_.*]] = Eq(_1, _1);
// CHECK: opaque::<bool>(move [[eq]])
2023-03-20 18:05:07 +00:00
opaque(x == x);
2023-10-16 21:44:36 +00:00
// CHECK: [[ne:_.*]] = Ne(_1, _1);
// CHECK: opaque::<bool>(move [[ne]])
2023-03-20 18:05:07 +00:00
opaque(x != x);
}
fn cast() {
2023-10-16 21:44:36 +00:00
// CHECK-LABEL: fn cast(
2023-03-20 18:05:07 +00:00
let i = 1_i64;
let u = 1_u64;
let f = 1_f64;
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u8>(const 1_u8)
2023-03-20 18:05:07 +00:00
opaque(i as u8);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u16>(const 1_u16)
2023-03-20 18:05:07 +00:00
opaque(i as u16);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u32>(const 1_u32)
2023-03-20 18:05:07 +00:00
opaque(i as u32);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u64>(const 1_u64)
2023-03-20 18:05:07 +00:00
opaque(i as u64);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<i8>(const 1_i8)
2023-03-20 18:05:07 +00:00
opaque(i as i8);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<i16>(const 1_i16)
2023-03-20 18:05:07 +00:00
opaque(i as i16);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<i32>(const 1_i32)
2023-03-20 18:05:07 +00:00
opaque(i as i32);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<i64>(const 1_i64)
2023-03-20 18:05:07 +00:00
opaque(i as i64);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<f32>(const 1f32)
2023-03-20 18:05:07 +00:00
opaque(i as f32);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<f64>(const 1f64)
2023-03-20 18:05:07 +00:00
opaque(i as f64);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u8>(const 1_u8)
2023-03-20 18:05:07 +00:00
opaque(u as u8);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u16>(const 1_u16)
2023-03-20 18:05:07 +00:00
opaque(u as u16);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u32>(const 1_u32)
2023-03-20 18:05:07 +00:00
opaque(u as u32);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u64>(const 1_u64)
2023-03-20 18:05:07 +00:00
opaque(u as u64);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<i8>(const 1_i8)
2023-03-20 18:05:07 +00:00
opaque(u as i8);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<i16>(const 1_i16)
2023-03-20 18:05:07 +00:00
opaque(u as i16);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<i32>(const 1_i32)
2023-03-20 18:05:07 +00:00
opaque(u as i32);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<i64>(const 1_i64)
2023-03-20 18:05:07 +00:00
opaque(u as i64);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<f32>(const 1f32)
2023-03-20 18:05:07 +00:00
opaque(u as f32);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<f64>(const 1f64)
2023-03-20 18:05:07 +00:00
opaque(u as f64);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u8>(const 1_u8)
2023-03-20 18:05:07 +00:00
opaque(f as u8);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u16>(const 1_u16)
2023-03-20 18:05:07 +00:00
opaque(f as u16);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u32>(const 1_u32)
2023-03-20 18:05:07 +00:00
opaque(f as u32);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u64>(const 1_u64)
2023-03-20 18:05:07 +00:00
opaque(f as u64);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<i8>(const 1_i8)
2023-03-20 18:05:07 +00:00
opaque(f as i8);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<i16>(const 1_i16)
2023-03-20 18:05:07 +00:00
opaque(f as i16);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<i32>(const 1_i32)
2023-03-20 18:05:07 +00:00
opaque(f as i32);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<i64>(const 1_i64)
2023-03-20 18:05:07 +00:00
opaque(f as i64);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<f32>(const 1f32)
2023-03-20 18:05:07 +00:00
opaque(f as f32);
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<f64>(const 1f64)
2023-03-20 18:05:07 +00:00
opaque(f as f64);
}
fn multiple_branches(t: bool, x: u8, y: u8) {
2023-10-16 21:44:36 +00:00
// CHECK-LABEL: fn multiple_branches(
// CHECK: switchInt(_1) -> [0: [[bbf:bb.*]], otherwise: [[bbt:bb.*]]];
2023-03-20 18:05:07 +00:00
if t {
2023-10-16 21:44:36 +00:00
// 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);
2023-03-20 18:05:07 +00:00
} else {
2023-10-16 21:44:36 +00:00
// 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);
2023-03-20 18:05:07 +00:00
}
2023-10-16 21:44:36 +00:00
// 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.
2023-03-20 18:05:07 +00:00
if t {
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u8>([[c]])
opaque(x + y);
2023-03-20 18:05:07 +00:00
} else {
2023-10-16 21:44:36 +00:00
// CHECK: opaque::<u8>([[c]])
opaque(x + y);
2023-03-20 18:05:07 +00:00
}
}
2023-10-16 21:44:36 +00:00
/// Verify that we do not reuse a `&raw? mut?` rvalue.
2023-03-20 18:05:07 +00:00
fn references(mut x: impl Sized) {
2023-10-16 21:44:36 +00:00
// CHECK-LABEL: fn references(
// CHECK: [[ref1:_.*]] = &_1;
// CHECK: opaque::<&impl Sized>(move [[ref1]])
2023-03-20 18:05:07 +00:00
opaque(&x);
2023-10-16 21:44:36 +00:00
// 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]])
2023-03-20 18:05:07 +00:00
opaque(&mut x);
2023-10-16 21:44:36 +00:00
// CHECK: [[ref5:_.*]] = &raw const _1;
// CHECK: opaque::<*const impl Sized>(move [[ref5]])
opaque(&raw const x);
// CHECK: [[ref6:_.*]] = &raw const _1;
// CHECK: opaque::<*const impl Sized>(move [[ref6]])
2023-03-20 18:05:07 +00:00
opaque(&raw const x);
2023-10-16 21:44:36 +00:00
// 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]])
2023-03-20 18:05:07 +00:00
opaque(&raw mut x);
2023-09-16 09:16:04 +00:00
let r = &mut x;
2023-10-16 21:44:36 +00:00
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);
2023-03-20 18:05:07 +00:00
}
fn dereferences(t: &mut u32, u: &impl Copy, s: &S<u32>) {
2023-10-16 21:44:36 +00:00
// 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);
2023-03-20 18:05:07 +00:00
opaque(*t);
2023-10-16 21:44:36 +00:00
// 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]])
2023-03-20 18:05:07 +00:00
let z = &raw const *t;
unsafe { opaque(*z) };
2023-10-16 21:44:36 +00:00
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]])
2023-03-20 18:05:07 +00:00
let z = &raw mut *t;
unsafe { opaque(*z) };
2023-10-16 21:44:36 +00:00
unsafe { opaque(*z) };
// We can reuse dereferences of `&Freeze`.
// CHECK: [[ref:_.*]] = &(*_1);
// CHECK: [[st7:_.*]] = (*[[ref]]);
// CHECK: opaque::<u32>([[st7]])
// CHECK: opaque::<u32>([[st7]])
2023-03-20 18:05:07 +00:00
let z = &*t;
opaque(*z);
2023-10-16 21:44:36 +00:00
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);
2023-03-20 18:05:07 +00:00
opaque(*u);
2023-10-16 21:44:36 +00:00
// `*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);
2023-03-20 18:05:07 +00:00
opaque(s.0);
}
fn slices() {
2023-10-16 21:44:36 +00:00
// 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 { transmute::<&str, &[u8]>(s) };
opaque(u);
assert_eq!(s.as_ptr(), u.as_ptr());
}
#[custom_mir(dialect = "analysis")]
fn duplicate_slice() -> (bool, bool) {
2023-10-16 21:44:36 +00:00
// CHECK-LABEL: fn duplicate_slice(
Reformat `mir!` macro invocations to use braces. The `mir!` macro has multiple parts: - An optional return type annotation. - A sequence of zero or more local declarations. - A mandatory starting anonymous basic block, which is brace-delimited. - A sequence of zero of more additional named basic blocks. Some `mir!` invocations use braces with a "block" style, like so: ``` mir! { let _unit: (); { let non_copy = S(42); let ptr = std::ptr::addr_of_mut!(non_copy); // Inside `callee`, the first argument and `*ptr` are basically // aliasing places! Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) } after_call = { Return() } } ``` Some invocations use parens with a "block" style, like so: ``` mir!( let x: [i32; 2]; let one: i32; { x = [42, 43]; one = 1; x = [one, 2]; RET = Move(x); Return() } ) ``` And some invocations uses parens with a "tighter" style, like so: ``` mir!({ SetDiscriminant(*b, 0); Return() }) ``` This last style is generally used for cases where just the mandatory starting basic block is present. Its braces are placed next to the parens. This commit changes all `mir!` invocations to use braces with a "block" style. Why? - Consistency is good. - The contents of the invocation is a block of code, so it's odd to use parens. They are more normally used for function-like macros. - Most importantly, the next commit will enable rustfmt for `tests/mir-opt/`. rustfmt is more aggressive about formatting macros that use parens than macros that use braces. Without this commit's changes, rustfmt would break a couple of `mir!` macro invocations that use braces within `tests/mir-opt` by inserting an extraneous comma. E.g.: ``` mir!(type RET = (i32, bool);, { // extraneous comma after ';' RET.0 = 1; RET.1 = true; Return() }) ``` Switching those `mir!` invocations to use braces avoids that problem, resulting in this, which is nicer to read as well as being valid syntax: ``` mir! { type RET = (i32, bool); { RET.0 = 1; RET.1 = true; Return() } } ```
2024-06-03 00:19:57 +00:00
mir! {
let au: u128;
let bu: u128;
let cu: u128;
let du: u128;
let c: &str;
let d: &str;
{
2023-10-16 21:44:36 +00:00
// CHECK: [[a:_.*]] = (const "a",);
// CHECK: [[au:_.*]] = ([[a]].0: &str) as u128 (Transmute);
let a = ("a",);
Call(au = transmute::<_, u128>(a.0), ReturnTo(bb1), UnwindContinue())
}
bb1 = {
2023-10-16 21:44:36 +00:00
// CHECK: [[c:_.*]] = identity::<&str>(([[a]].0: &str))
Call(c = identity(a.0), ReturnTo(bb2), UnwindContinue())
}
bb2 = {
2023-10-16 21:44:36 +00:00
// CHECK: [[cu:_.*]] = [[c]] as u128 (Transmute);
Call(cu = transmute::<_, u128>(c), ReturnTo(bb3), UnwindContinue())
}
bb3 = {
2023-10-16 21:44:36 +00:00
// 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), ReturnTo(bb4), UnwindContinue())
}
bb4 = {
2023-10-16 21:44:36 +00:00
// This returns a copy of `b`, which is not `a`.
// CHECK: [[d:_.*]] = identity::<&str>([[b]])
Call(d = identity(b), ReturnTo(bb5), UnwindContinue())
}
bb5 = {
2023-10-16 21:44:36 +00:00
// CHECK: [[du:_.*]] = [[d]] as u128 (Transmute);
Call(du = transmute::<_, u128>(d), ReturnTo(bb6), UnwindContinue())
}
bb6 = {
2023-10-16 21:44:36 +00:00
// `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()
}
Reformat `mir!` macro invocations to use braces. The `mir!` macro has multiple parts: - An optional return type annotation. - A sequence of zero or more local declarations. - A mandatory starting anonymous basic block, which is brace-delimited. - A sequence of zero of more additional named basic blocks. Some `mir!` invocations use braces with a "block" style, like so: ``` mir! { let _unit: (); { let non_copy = S(42); let ptr = std::ptr::addr_of_mut!(non_copy); // Inside `callee`, the first argument and `*ptr` are basically // aliasing places! Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) } after_call = { Return() } } ``` Some invocations use parens with a "block" style, like so: ``` mir!( let x: [i32; 2]; let one: i32; { x = [42, 43]; one = 1; x = [one, 2]; RET = Move(x); Return() } ) ``` And some invocations uses parens with a "tighter" style, like so: ``` mir!({ SetDiscriminant(*b, 0); Return() }) ``` This last style is generally used for cases where just the mandatory starting basic block is present. Its braces are placed next to the parens. This commit changes all `mir!` invocations to use braces with a "block" style. Why? - Consistency is good. - The contents of the invocation is a block of code, so it's odd to use parens. They are more normally used for function-like macros. - Most importantly, the next commit will enable rustfmt for `tests/mir-opt/`. rustfmt is more aggressive about formatting macros that use parens than macros that use braces. Without this commit's changes, rustfmt would break a couple of `mir!` macro invocations that use braces within `tests/mir-opt` by inserting an extraneous comma. E.g.: ``` mir!(type RET = (i32, bool);, { // extraneous comma after ';' RET.0 = 1; RET.1 = true; Return() }) ``` Switching those `mir!` invocations to use braces avoids that problem, resulting in this, which is nicer to read as well as being valid syntax: ``` mir! { type RET = (i32, bool); { RET.0 = 1; RET.1 = true; Return() } } ```
2024-06-03 00:19:57 +00:00
}
}
2023-10-16 21:44:36 +00:00
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];
2023-05-21 12:59:38 +00:00
}
2023-10-21 09:59:03 +00:00
/// 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);
}
2023-10-22 14:49:00 +00:00
/// 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;
Reformat `mir!` macro invocations to use braces. The `mir!` macro has multiple parts: - An optional return type annotation. - A sequence of zero or more local declarations. - A mandatory starting anonymous basic block, which is brace-delimited. - A sequence of zero of more additional named basic blocks. Some `mir!` invocations use braces with a "block" style, like so: ``` mir! { let _unit: (); { let non_copy = S(42); let ptr = std::ptr::addr_of_mut!(non_copy); // Inside `callee`, the first argument and `*ptr` are basically // aliasing places! Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) } after_call = { Return() } } ``` Some invocations use parens with a "block" style, like so: ``` mir!( let x: [i32; 2]; let one: i32; { x = [42, 43]; one = 1; x = [one, 2]; RET = Move(x); Return() } ) ``` And some invocations uses parens with a "tighter" style, like so: ``` mir!({ SetDiscriminant(*b, 0); Return() }) ``` This last style is generally used for cases where just the mandatory starting basic block is present. Its braces are placed next to the parens. This commit changes all `mir!` invocations to use braces with a "block" style. Why? - Consistency is good. - The contents of the invocation is a block of code, so it's odd to use parens. They are more normally used for function-like macros. - Most importantly, the next commit will enable rustfmt for `tests/mir-opt/`. rustfmt is more aggressive about formatting macros that use parens than macros that use braces. Without this commit's changes, rustfmt would break a couple of `mir!` macro invocations that use braces within `tests/mir-opt` by inserting an extraneous comma. E.g.: ``` mir!(type RET = (i32, bool);, { // extraneous comma after ';' RET.0 = 1; RET.1 = true; Return() }) ``` Switching those `mir!` invocations to use braces avoids that problem, resulting in this, which is nicer to read as well as being valid syntax: ``` mir! { type RET = (i32, bool); { RET.0 = 1; RET.1 = true; Return() } } ```
2024-06-03 00:19:57 +00:00
mir! {
{
let ptr = Static(A);
let out = Field::<u8>(Variant(*ptr, 1), 0);
Return()
}
}
2023-10-22 14:49:00 +00:00
}
/// Verify that having constant index `u64::MAX` does not yield to an overflow in rustc.
fn constant_index_overflow<T: Copy>(x: &[T]) {
// CHECK-LABEL: fn constant_index_overflow(
// CHECK: debug a => [[a:_.*]];
// CHECK: debug b => [[b:_.*]];
// CHECK: [[a]] = const usize::MAX;
// CHECK-NOT: = (*_1)[{{.*}} of 0];
// CHECK: [[b]] = (*_1)[[[a]]];
// CHECK-NOT: = (*_1)[{{.*}} of 0];
// CHECK: [[b]] = (*_1)[0 of 1];
// CHECK-NOT: = (*_1)[{{.*}} of 0];
let a = u64::MAX as usize;
let b = if a < x.len() { x[a] } else { x[0] };
opaque(b)
}
2023-12-30 23:37:50 +00:00
/// Check that we do not attempt to simplify anything when there is provenance.
fn wide_ptr_provenance() {
// CHECK-LABEL: fn wide_ptr_provenance(
let a: *const dyn Send = &1 as &dyn Send;
let b: *const dyn Send = &1 as &dyn Send;
2023-12-30 23:37:50 +00:00
// CHECK: [[eqp:_.*]] = Eq([[a:_.*]], [[b:_.*]]);
// CHECK: opaque::<bool>(move [[eqp]])
opaque(a == b);
// CHECK: [[nep:_.*]] = Ne([[a]], [[b]]);
// CHECK: opaque::<bool>(move [[nep]])
opaque(a != b);
// CHECK: [[ltp:_.*]] = Lt([[a]], [[b]]);
// CHECK: opaque::<bool>(move [[ltp]])
opaque(a < b);
// CHECK: [[lep:_.*]] = Le([[a]], [[b]]);
// CHECK: opaque::<bool>(move [[lep]])
opaque(a <= b);
// CHECK: [[gtp:_.*]] = Gt([[a]], [[b]]);
// CHECK: opaque::<bool>(move [[gtp]])
opaque(a > b);
// CHECK: [[gep:_.*]] = Ge([[a]], [[b]]);
// CHECK: opaque::<bool>(move [[gep]])
opaque(a >= b);
}
/// Both pointers come form the same allocation, so we could probably fold the comparisons.
fn wide_ptr_same_provenance() {
// CHECK-LABEL: fn wide_ptr_same_provenance(
let slice = &[1, 2];
let a: *const dyn Send = &slice[0] as &dyn Send;
let b: *const dyn Send = &slice[1] as &dyn Send;
// CHECK: [[eqp:_.*]] = Eq([[a:_.*]], [[b:_.*]]);
// CHECK: opaque::<bool>(move [[eqp]])
opaque(a == b);
// CHECK: [[nep:_.*]] = Ne([[a]], [[b]]);
// CHECK: opaque::<bool>(move [[nep]])
opaque(a != b);
// CHECK: [[ltp:_.*]] = Lt([[a]], [[b]]);
// CHECK: opaque::<bool>(move [[ltp]])
opaque(a < b);
// CHECK: [[lep:_.*]] = Le([[a]], [[b]]);
// CHECK: opaque::<bool>(move [[lep]])
opaque(a <= b);
// CHECK: [[gtp:_.*]] = Gt([[a]], [[b]]);
// CHECK: opaque::<bool>(move [[gtp]])
opaque(a > b);
// CHECK: [[gep:_.*]] = Ge([[a]], [[b]]);
// CHECK: opaque::<bool>(move [[gep]])
opaque(a >= b);
}
2023-12-30 23:37:50 +00:00
/// Check that we do simplify when there is no provenance, and do not ICE.
fn wide_ptr_integer() {
// CHECK-LABEL: fn wide_ptr_integer(
// CHECK: debug a => [[a:_.*]];
// CHECK: debug b => [[b:_.*]];
let a: *const [u8] = unsafe { transmute((1usize, 1usize)) };
let b: *const [u8] = unsafe { transmute((1usize, 2usize)) };
2023-12-30 23:37:50 +00:00
// CHECK: opaque::<bool>(const false)
opaque(a == b);
// CHECK: opaque::<bool>(const true)
opaque(a != b);
2023-12-30 23:37:50 +00:00
// CHECK: opaque::<bool>(const true)
opaque(a < b);
2023-12-30 23:37:50 +00:00
// CHECK: opaque::<bool>(const true)
opaque(a <= b);
// CHECK: opaque::<bool>(const false)
opaque(a > b);
// CHECK: opaque::<bool>(const false)
opaque(a >= b);
}
2024-04-07 16:23:16 +00:00
#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
2024-04-07 18:33:18 +00:00
fn borrowed<T: Copy + Freeze>(x: T) {
2024-04-07 16:23:16 +00:00
// CHECK-LABEL: fn borrowed(
// CHECK: bb0: {
// CHECK-NEXT: _2 = _1;
// CHECK-NEXT: _3 = &_1;
2024-04-07 18:33:18 +00:00
// CHECK-NEXT: _0 = opaque::<&T>(_3)
2024-04-07 16:23:16 +00:00
// CHECK: bb1: {
2024-04-07 18:33:18 +00:00
// CHECK-NEXT: _0 = opaque::<T>(_1)
2024-04-07 16:23:16 +00:00
// CHECK: bb2: {
2024-04-07 18:33:18 +00:00
// CHECK-NEXT: _0 = opaque::<T>(_1)
Reformat `mir!` macro invocations to use braces. The `mir!` macro has multiple parts: - An optional return type annotation. - A sequence of zero or more local declarations. - A mandatory starting anonymous basic block, which is brace-delimited. - A sequence of zero of more additional named basic blocks. Some `mir!` invocations use braces with a "block" style, like so: ``` mir! { let _unit: (); { let non_copy = S(42); let ptr = std::ptr::addr_of_mut!(non_copy); // Inside `callee`, the first argument and `*ptr` are basically // aliasing places! Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) } after_call = { Return() } } ``` Some invocations use parens with a "block" style, like so: ``` mir!( let x: [i32; 2]; let one: i32; { x = [42, 43]; one = 1; x = [one, 2]; RET = Move(x); Return() } ) ``` And some invocations uses parens with a "tighter" style, like so: ``` mir!({ SetDiscriminant(*b, 0); Return() }) ``` This last style is generally used for cases where just the mandatory starting basic block is present. Its braces are placed next to the parens. This commit changes all `mir!` invocations to use braces with a "block" style. Why? - Consistency is good. - The contents of the invocation is a block of code, so it's odd to use parens. They are more normally used for function-like macros. - Most importantly, the next commit will enable rustfmt for `tests/mir-opt/`. rustfmt is more aggressive about formatting macros that use parens than macros that use braces. Without this commit's changes, rustfmt would break a couple of `mir!` macro invocations that use braces within `tests/mir-opt` by inserting an extraneous comma. E.g.: ``` mir!(type RET = (i32, bool);, { // extraneous comma after ';' RET.0 = 1; RET.1 = true; Return() }) ``` Switching those `mir!` invocations to use braces avoids that problem, resulting in this, which is nicer to read as well as being valid syntax: ``` mir! { type RET = (i32, bool); { RET.0 = 1; RET.1 = true; Return() } } ```
2024-06-03 00:19:57 +00:00
mir! {
2024-04-07 16:23:16 +00:00
{
let a = x;
let r1 = &x;
Call(RET = opaque(r1), ReturnTo(next), UnwindContinue())
}
next = {
Call(RET = opaque(a), ReturnTo(deref), UnwindContinue())
}
deref = {
Call(RET = opaque(*r1), ReturnTo(ret), UnwindContinue())
}
ret = {
Return()
}
Reformat `mir!` macro invocations to use braces. The `mir!` macro has multiple parts: - An optional return type annotation. - A sequence of zero or more local declarations. - A mandatory starting anonymous basic block, which is brace-delimited. - A sequence of zero of more additional named basic blocks. Some `mir!` invocations use braces with a "block" style, like so: ``` mir! { let _unit: (); { let non_copy = S(42); let ptr = std::ptr::addr_of_mut!(non_copy); // Inside `callee`, the first argument and `*ptr` are basically // aliasing places! Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) } after_call = { Return() } } ``` Some invocations use parens with a "block" style, like so: ``` mir!( let x: [i32; 2]; let one: i32; { x = [42, 43]; one = 1; x = [one, 2]; RET = Move(x); Return() } ) ``` And some invocations uses parens with a "tighter" style, like so: ``` mir!({ SetDiscriminant(*b, 0); Return() }) ``` This last style is generally used for cases where just the mandatory starting basic block is present. Its braces are placed next to the parens. This commit changes all `mir!` invocations to use braces with a "block" style. Why? - Consistency is good. - The contents of the invocation is a block of code, so it's odd to use parens. They are more normally used for function-like macros. - Most importantly, the next commit will enable rustfmt for `tests/mir-opt/`. rustfmt is more aggressive about formatting macros that use parens than macros that use braces. Without this commit's changes, rustfmt would break a couple of `mir!` macro invocations that use braces within `tests/mir-opt` by inserting an extraneous comma. E.g.: ``` mir!(type RET = (i32, bool);, { // extraneous comma after ';' RET.0 = 1; RET.1 = true; Return() }) ``` Switching those `mir!` invocations to use braces avoids that problem, resulting in this, which is nicer to read as well as being valid syntax: ``` mir! { type RET = (i32, bool); { RET.0 = 1; RET.1 = true; Return() } } ```
2024-06-03 00:19:57 +00:00
}
2024-04-07 16:23:16 +00:00
}
/// Generic type `T` is not known to be `Freeze`, so shared borrows may be mutable.
#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
fn non_freeze<T: Copy>(x: T) {
// CHECK-LABEL: fn non_freeze(
// CHECK: bb0: {
// CHECK-NEXT: _2 = _1;
// CHECK-NEXT: _3 = &_1;
// CHECK-NEXT: _0 = opaque::<&T>(_3)
// CHECK: bb1: {
// CHECK-NEXT: _0 = opaque::<T>(_2)
// CHECK: bb2: {
// CHECK-NEXT: _0 = opaque::<T>((*_3))
Reformat `mir!` macro invocations to use braces. The `mir!` macro has multiple parts: - An optional return type annotation. - A sequence of zero or more local declarations. - A mandatory starting anonymous basic block, which is brace-delimited. - A sequence of zero of more additional named basic blocks. Some `mir!` invocations use braces with a "block" style, like so: ``` mir! { let _unit: (); { let non_copy = S(42); let ptr = std::ptr::addr_of_mut!(non_copy); // Inside `callee`, the first argument and `*ptr` are basically // aliasing places! Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) } after_call = { Return() } } ``` Some invocations use parens with a "block" style, like so: ``` mir!( let x: [i32; 2]; let one: i32; { x = [42, 43]; one = 1; x = [one, 2]; RET = Move(x); Return() } ) ``` And some invocations uses parens with a "tighter" style, like so: ``` mir!({ SetDiscriminant(*b, 0); Return() }) ``` This last style is generally used for cases where just the mandatory starting basic block is present. Its braces are placed next to the parens. This commit changes all `mir!` invocations to use braces with a "block" style. Why? - Consistency is good. - The contents of the invocation is a block of code, so it's odd to use parens. They are more normally used for function-like macros. - Most importantly, the next commit will enable rustfmt for `tests/mir-opt/`. rustfmt is more aggressive about formatting macros that use parens than macros that use braces. Without this commit's changes, rustfmt would break a couple of `mir!` macro invocations that use braces within `tests/mir-opt` by inserting an extraneous comma. E.g.: ``` mir!(type RET = (i32, bool);, { // extraneous comma after ';' RET.0 = 1; RET.1 = true; Return() }) ``` Switching those `mir!` invocations to use braces avoids that problem, resulting in this, which is nicer to read as well as being valid syntax: ``` mir! { type RET = (i32, bool); { RET.0 = 1; RET.1 = true; Return() } } ```
2024-06-03 00:19:57 +00:00
mir! {
2024-04-07 16:23:16 +00:00
{
let a = x;
let r1 = &x;
Call(RET = opaque(r1), ReturnTo(next), UnwindContinue())
}
next = {
Call(RET = opaque(a), ReturnTo(deref), UnwindContinue())
}
deref = {
Call(RET = opaque(*r1), ReturnTo(ret), UnwindContinue())
}
ret = {
Return()
}
Reformat `mir!` macro invocations to use braces. The `mir!` macro has multiple parts: - An optional return type annotation. - A sequence of zero or more local declarations. - A mandatory starting anonymous basic block, which is brace-delimited. - A sequence of zero of more additional named basic blocks. Some `mir!` invocations use braces with a "block" style, like so: ``` mir! { let _unit: (); { let non_copy = S(42); let ptr = std::ptr::addr_of_mut!(non_copy); // Inside `callee`, the first argument and `*ptr` are basically // aliasing places! Call(_unit = callee(Move(*ptr), ptr), ReturnTo(after_call), UnwindContinue()) } after_call = { Return() } } ``` Some invocations use parens with a "block" style, like so: ``` mir!( let x: [i32; 2]; let one: i32; { x = [42, 43]; one = 1; x = [one, 2]; RET = Move(x); Return() } ) ``` And some invocations uses parens with a "tighter" style, like so: ``` mir!({ SetDiscriminant(*b, 0); Return() }) ``` This last style is generally used for cases where just the mandatory starting basic block is present. Its braces are placed next to the parens. This commit changes all `mir!` invocations to use braces with a "block" style. Why? - Consistency is good. - The contents of the invocation is a block of code, so it's odd to use parens. They are more normally used for function-like macros. - Most importantly, the next commit will enable rustfmt for `tests/mir-opt/`. rustfmt is more aggressive about formatting macros that use parens than macros that use braces. Without this commit's changes, rustfmt would break a couple of `mir!` macro invocations that use braces within `tests/mir-opt` by inserting an extraneous comma. E.g.: ``` mir!(type RET = (i32, bool);, { // extraneous comma after ';' RET.0 = 1; RET.1 = true; Return() }) ``` Switching those `mir!` invocations to use braces avoids that problem, resulting in this, which is nicer to read as well as being valid syntax: ``` mir! { type RET = (i32, bool); { RET.0 = 1; RET.1 = true; Return() } } ```
2024-06-03 00:19:57 +00:00
}
2024-04-07 16:23:16 +00:00
}
// Check that we can const-prop into `from_raw_parts`
fn slice_const_length(x: &[i32]) -> *const [i32] {
// CHECK-LABEL: fn slice_const_length(
// CHECK: _0 = *const [i32] from ({{_[0-9]+}}, const 123_usize);
let ptr = x.as_ptr();
let len = 123;
std::intrinsics::aggregate_raw_ptr(ptr, len)
}
fn meta_of_ref_to_slice(x: *const i32) -> usize {
// CHECK-LABEL: fn meta_of_ref_to_slice
// CHECK: _0 = const 1_usize
let ptr: *const [i32] = std::intrinsics::aggregate_raw_ptr(x, 1);
std::intrinsics::ptr_metadata(ptr)
}
fn slice_from_raw_parts_as_ptr(x: *const u16, n: usize) -> (*const u16, *const f32) {
// CHECK-LABEL: fn slice_from_raw_parts_as_ptr
// CHECK: _8 = _1 as *const f32 (PtrToPtr);
// CHECK: _0 = (_1, move _8);
let ptr: *const [u16] = std::intrinsics::aggregate_raw_ptr(x, n);
(ptr as *const u16, ptr as *const f32)
}
fn casts_before_aggregate_raw_ptr(x: *const u32) -> *const [u8] {
// CHECK-LABEL: fn casts_before_aggregate_raw_ptr
// CHECK: _0 = *const [u8] from (_1, const 4_usize);
let x = x as *const [u8; 4];
let x = x as *const u8;
let x = x as *const ();
std::intrinsics::aggregate_raw_ptr(x, 4)
}
2023-03-20 18:05:07 +00:00
fn main() {
subexpression_elimination(2, 4, 5);
wrap_unwrap(5);
repeated_index::<u32, 7>(5, 3);
2023-03-25 22:33:35 +00:00
unary(i64::MIN);
2023-03-20 18:05:07 +00:00
arithmetic(5);
2023-10-16 21:44:36 +00:00
comparison(5, 6);
2023-03-20 18:05:07 +00:00
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);
2023-10-16 21:44:36 +00:00
repeat();
2023-10-21 09:59:03 +00:00
fn_pointers();
2023-10-22 14:49:00 +00:00
indirect_static();
constant_index_overflow(&[5, 3]);
2023-12-30 23:37:50 +00:00
wide_ptr_provenance();
wide_ptr_integer();
2024-04-07 16:23:16 +00:00
borrowed(5);
non_freeze(5);
slice_const_length(&[1]);
meta_of_ref_to_slice(&42);
slice_from_raw_parts_as_ptr(&123, 456);
2023-03-20 18:05:07 +00:00
}
#[inline(never)]
fn opaque(_: impl Sized) {}
#[inline(never)]
fn identity<T>(x: T) -> T {
x
}
2023-03-20 18:05:07 +00:00
// EMIT_MIR gvn.subexpression_elimination.GVN.diff
// EMIT_MIR gvn.wrap_unwrap.GVN.diff
// EMIT_MIR gvn.repeated_index.GVN.diff
2023-03-25 22:33:35 +00:00
// EMIT_MIR gvn.unary.GVN.diff
2023-03-20 18:05:07 +00:00
// EMIT_MIR gvn.arithmetic.GVN.diff
2023-10-16 21:44:36 +00:00
// EMIT_MIR gvn.comparison.GVN.diff
2023-03-20 18:05:07 +00:00
// 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
2023-10-16 21:44:36 +00:00
// EMIT_MIR gvn.repeat.GVN.diff
2023-10-21 09:59:03 +00:00
// EMIT_MIR gvn.fn_pointers.GVN.diff
2023-10-22 14:49:00 +00:00
// EMIT_MIR gvn.indirect_static.GVN.diff
// EMIT_MIR gvn.constant_index_overflow.GVN.diff
2023-12-30 23:37:50 +00:00
// EMIT_MIR gvn.wide_ptr_provenance.GVN.diff
// EMIT_MIR gvn.wide_ptr_same_provenance.GVN.diff
2023-12-30 23:37:50 +00:00
// EMIT_MIR gvn.wide_ptr_integer.GVN.diff
2024-04-07 16:23:16 +00:00
// EMIT_MIR gvn.borrowed.GVN.diff
// EMIT_MIR gvn.non_freeze.GVN.diff
// EMIT_MIR gvn.slice_const_length.GVN.diff
// EMIT_MIR gvn.meta_of_ref_to_slice.GVN.diff
// EMIT_MIR gvn.slice_from_raw_parts_as_ptr.GVN.diff
// EMIT_MIR gvn.casts_before_aggregate_raw_ptr.GVN.diff