rust/tests/mir-opt/jump_threading.rs

565 lines
16 KiB
Rust
Raw Normal View History

//@ test-mir-pass: JumpThreading
//@ compile-flags: -Zmir-enable-passes=+Inline
2023-01-16 16:12:36 -06:00
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY
#![feature(control_flow_enum)]
#![feature(try_trait_v2)]
#![feature(custom_mir, core_intrinsics, rustc_attrs)]
use std::intrinsics::mir::*;
use std::ops::ControlFlow;
fn too_complex(x: Result<i32, usize>) -> Option<i32> {
2023-10-20 10:50:09 -05:00
// CHECK-LABEL: fn too_complex(
// CHECK: bb0: {
2024-02-11 21:56:03 -06:00
// CHECK: switchInt(move {{_.*}}) -> [0: bb3, 1: bb2, otherwise: bb1];
2023-10-20 10:50:09 -05:00
// CHECK: bb1: {
2024-02-11 21:56:03 -06:00
// CHECK: unreachable;
// CHECK: bb2: {
2023-10-20 10:50:09 -05:00
// CHECK: [[controlflow:_.*]] = ControlFlow::<usize, i32>::Break(
// CHECK: goto -> bb8;
// CHECK: bb3: {
// CHECK: [[controlflow]] = ControlFlow::<usize, i32>::Continue(
// CHECK: goto -> bb4;
// CHECK: bb4: {
// CHECK: goto -> bb6;
// CHECK: bb5: {
2024-08-18 17:51:53 -05:00
// CHECK: {{_.*}} = copy (([[controlflow]] as Break).0: usize);
2023-10-20 10:50:09 -05:00
// CHECK: _0 = Option::<i32>::None;
// CHECK: goto -> bb7;
// CHECK: bb6: {
2024-08-18 17:51:53 -05:00
// CHECK: {{_.*}} = copy (([[controlflow]] as Continue).0: i32);
2023-10-20 10:50:09 -05:00
// CHECK: _0 = Option::<i32>::Some(
// CHECK: goto -> bb7;
// CHECK: bb7: {
// CHECK: return;
// CHECK: bb8: {
// CHECK: goto -> bb5;
2023-01-16 16:12:36 -06:00
match {
match x {
Ok(v) => ControlFlow::Continue(v),
Err(r) => ControlFlow::Break(r),
}
} {
ControlFlow::Continue(v) => Some(v),
ControlFlow::Break(r) => None,
}
}
fn identity(x: Result<i32, i32>) -> Result<i32, i32> {
2023-10-20 10:50:09 -05:00
// CHECK-LABEL: fn identity(
// CHECK: bb0: {
2024-08-18 17:51:53 -05:00
// CHECK: [[x:_.*]] = copy _1;
2024-02-11 21:56:03 -06:00
// CHECK: switchInt(move {{_.*}}) -> [0: bb7, 1: bb6, otherwise: bb1];
2023-10-20 10:50:09 -05:00
// CHECK: bb1: {
2024-02-11 21:56:03 -06:00
// CHECK: unreachable;
// CHECK: bb2: {
2024-08-18 17:51:53 -05:00
// CHECK: {{_.*}} = copy (([[controlflow:_.*]] as Continue).0: i32);
2023-10-20 10:50:09 -05:00
// CHECK: _0 = Result::<i32, i32>::Ok(
// CHECK: goto -> bb4;
// CHECK: bb3: {
2024-08-18 17:51:53 -05:00
// CHECK: {{_.*}} = copy (([[controlflow]] as Break).0: std::result::Result<std::convert::Infallible, i32>);
2023-10-20 10:50:09 -05:00
// CHECK: _0 = Result::<i32, i32>::Err(
// CHECK: goto -> bb4;
// CHECK: bb4: {
2023-10-20 10:50:09 -05:00
// CHECK: return;
// CHECK: bb5: {
2024-02-11 21:56:03 -06:00
// CHECK: goto -> bb2;
2023-10-20 10:50:09 -05:00
// CHECK: bb6: {
// CHECK: {{_.*}} = move (([[x]] as Err).0: i32);
// CHECK: [[controlflow]] = ControlFlow::<Result<Infallible, i32>, i32>::Break(
// CHECK: goto -> bb8;
2023-10-20 10:50:09 -05:00
// CHECK: bb7: {
// CHECK: {{_.*}} = move (([[x]] as Ok).0: i32);
// CHECK: [[controlflow]] = ControlFlow::<Result<Infallible, i32>, i32>::Continue(
// CHECK: goto -> bb5;
// CHECK: bb8: {
// CHECK: goto -> bb3;
2023-01-16 16:12:36 -06:00
Ok(x?)
}
enum DFA {
A,
B,
C,
D,
}
2023-10-20 10:50:09 -05:00
/// Check that we do not thread through a loop header,
/// to avoid creating an irreducible CFG.
2023-01-16 16:12:36 -06:00
fn dfa() {
2023-10-20 10:50:09 -05:00
// CHECK-LABEL: fn dfa(
// CHECK: bb0: {
// CHECK: {{_.*}} = DFA::A;
// CHECK: goto -> bb1;
// CHECK: bb1: {
// CHECK: switchInt({{.*}}) -> [0: bb6, 1: bb5, 2: bb4, 3: bb3, otherwise: bb2];
2023-10-20 10:50:09 -05:00
// CHECK: bb2: {
// CHECK: unreachable;
2024-02-11 21:56:03 -06:00
// CHECK: bb3: {
// CHECK: return;
2023-10-20 10:50:09 -05:00
// CHECK: bb4: {
// CHECK: {{_.*}} = DFA::D;
2023-10-20 10:50:09 -05:00
// CHECK: goto -> bb1;
// CHECK: bb5: {
// CHECK: {{_.*}} = DFA::C;
// CHECK: goto -> bb1;
// CHECK: bb6: {
// CHECK: {{_.*}} = DFA::B;
2023-10-20 10:50:09 -05:00
// CHECK: goto -> bb1;
2023-01-16 16:12:36 -06:00
let mut state = DFA::A;
loop {
match state {
DFA::A => state = DFA::B,
DFA::B => state = DFA::C,
DFA::C => state = DFA::D,
DFA::D => return,
}
}
}
#[repr(u8)]
enum CustomDiscr {
A = 35,
B = 73,
C = 99,
}
2023-10-20 10:50:09 -05:00
/// Verify that we correctly match the discriminant value, and not its index.
2023-01-16 16:12:36 -06:00
fn custom_discr(x: bool) -> u8 {
2023-10-20 10:50:09 -05:00
// CHECK-LABEL: fn custom_discr(
// CHECK: bb0: {
// CHECK: switchInt({{.*}}) -> [0: bb2, otherwise: bb1];
// CHECK: bb1: {
// CHECK: {{_.*}} = CustomDiscr::A;
// CHECK: goto -> bb7;
// CHECK: bb2: {
// CHECK: {{_.*}} = CustomDiscr::B;
// CHECK: goto -> bb3;
// CHECK: bb3: {
// CHECK: goto -> bb4;
// CHECK: bb4: {
// CHECK: _0 = const 13_u8;
// CHECK: goto -> bb6;
// CHECK: bb5: {
// CHECK: _0 = const 5_u8;
// CHECK: goto -> bb6;
// CHECK: bb6: {
// CHECK: return;
// CHECK: bb7: {
// CHECK: goto -> bb5;
2023-01-16 16:12:36 -06:00
match if x { CustomDiscr::A } else { CustomDiscr::B } {
CustomDiscr::A => 5,
_ => 13,
}
}
#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
fn multiple_match(x: u8) -> u8 {
2023-10-20 10:50:09 -05:00
// CHECK-LABEL: fn multiple_match(
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-02 19:19:57 -05:00
mir! {
2023-01-16 16:12:36 -06:00
{
2023-10-20 10:50:09 -05:00
// CHECK: bb0: {
2024-08-18 17:51:53 -05:00
// CHECK: switchInt(copy [[x:_.*]]) -> [3: bb1, otherwise: bb2];
2023-01-16 16:12:36 -06:00
match x { 3 => bb1, _ => bb2 }
}
bb1 = {
// We know `x == 3`, so we can take `bb3`.
2023-10-20 10:50:09 -05:00
// CHECK: bb1: {
2024-08-18 17:51:53 -05:00
// CHECK: {{_.*}} = copy [[x]];
2023-10-20 10:50:09 -05:00
// CHECK: goto -> bb3;
2023-01-16 16:12:36 -06:00
let y = x;
match y { 3 => bb3, _ => bb4 }
}
bb2 = {
// We know `x != 3`, so we can take `bb6`.
2023-10-20 10:50:09 -05:00
// CHECK: bb2: {
2024-08-18 17:51:53 -05:00
// CHECK: [[z:_.*]] = copy [[x]];
2023-10-20 10:50:09 -05:00
// CHECK: goto -> bb6;
2023-01-16 16:12:36 -06:00
let z = x;
match z { 3 => bb5, _ => bb6 }
}
bb3 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb3: {
// CHECK: _0 = const 5_u8;
// CHECK: return;
2023-01-16 16:12:36 -06:00
RET = 5;
Return()
}
bb4 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb4: {
// CHECK: _0 = const 7_u8;
// CHECK: return;
2023-01-16 16:12:36 -06:00
RET = 7;
Return()
}
bb5 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb5: {
// CHECK: _0 = const 9_u8;
// CHECK: return;
2023-01-16 16:12:36 -06:00
RET = 9;
Return()
}
bb6 = {
// We know `z != 3`, so we CANNOT take `bb7`.
2023-10-20 10:50:09 -05:00
// CHECK: bb6: {
2024-08-18 17:51:53 -05:00
// CHECK: switchInt(copy [[z]]) -> [1: bb7, otherwise: bb8];
2023-01-16 16:12:36 -06:00
match z { 1 => bb7, _ => bb8 }
}
bb7 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb7: {
// CHECK: _0 = const 9_u8;
// CHECK: return;
2023-01-16 16:12:36 -06:00
RET = 9;
Return()
}
bb8 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb8: {
// CHECK: _0 = const 11_u8;
// CHECK: return;
2023-01-16 16:12:36 -06:00
RET = 11;
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-02 19:19:57 -05:00
}
2023-01-16 16:12:36 -06:00
}
2023-10-20 10:50:09 -05:00
/// Both 1-3-4 and 2-3-4 are threadable. As 1 and 2 are the only predecessors of 3,
/// verify that we only thread the 3-4 part.
2023-01-16 16:12:36 -06:00
#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
fn duplicate_chain(x: bool) -> u8 {
2023-10-20 10:50:09 -05:00
// CHECK-LABEL: fn duplicate_chain(
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-02 19:19:57 -05:00
mir! {
2023-01-16 16:12:36 -06:00
let a: u8;
{
2023-10-20 10:50:09 -05:00
// CHECK: bb0: {
// CHECK: switchInt({{.*}}) -> [1: bb1, otherwise: bb2];
2023-01-16 16:12:36 -06:00
match x { true => bb1, _ => bb2 }
}
bb1 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb1: {
// CHECK: [[a:_.*]] = const 5_u8;
// CHECK: goto -> bb3;
2023-01-16 16:12:36 -06:00
a = 5;
Goto(bb3)
}
bb2 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb2: {
// CHECK: [[a]] = const 5_u8;
// CHECK: goto -> bb3;
2023-01-16 16:12:36 -06:00
a = 5;
Goto(bb3)
}
bb3 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb3: {
// CHECK: {{_.*}} = const 13_i32;
// CHECK: goto -> bb4;
2023-01-16 16:12:36 -06:00
let b = 13;
Goto(bb4)
}
bb4 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb4: {
// CHECK: {{_.*}} = const 15_i32;
// CHECK-NOT: switchInt(
// CHECK: goto -> bb5;
2023-01-16 16:12:36 -06:00
let c = 15;
match a { 5 => bb5, _ => bb6 }
}
bb5 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb5: {
// CHECK: _0 = const 7_u8;
// CHECK: return;
2023-01-16 16:12:36 -06:00
RET = 7;
Return()
}
bb6 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb6: {
// CHECK: _0 = const 9_u8;
// CHECK: return;
2023-01-16 16:12:36 -06:00
RET = 9;
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-02 19:19:57 -05:00
}
2023-01-16 16:12:36 -06:00
}
#[rustc_layout_scalar_valid_range_start(1)]
#[rustc_nonnull_optimization_guaranteed]
struct NonZeroUsize(usize);
2023-10-20 10:50:09 -05:00
/// Verify that we correctly discard threads that may mutate a discriminant by aliasing.
2023-01-16 16:12:36 -06:00
#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
fn mutate_discriminant() -> u8 {
2023-10-20 10:50:09 -05:00
// CHECK-LABEL: fn mutate_discriminant(
// CHECK-NOT: goto -> {{bb.*}};
// CHECK: switchInt(
// CHECK-NOT: goto -> {{bb.*}};
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-02 19:19:57 -05:00
mir! {
2023-01-16 16:12:36 -06:00
let x: Option<NonZeroUsize>;
{
SetDiscriminant(x, 1);
// This assignment overwrites the niche in which the discriminant is stored.
place!(Field(Field(Variant(x, 1), 0), 0)) = 0_usize;
// So we cannot know the value of this discriminant.
let a = Discriminant(x);
match a {
0 => bb1,
_ => bad,
}
}
bb1 = {
RET = 1;
Return()
}
bad = {
RET = 2;
Unreachable()
}
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-02 19:19:57 -05:00
}
2023-01-16 16:12:36 -06:00
}
2023-10-20 10:50:09 -05:00
/// Verify that we do not try to reason when there are mutable pointers involved.
2023-01-16 16:12:36 -06:00
fn mutable_ref() -> bool {
2023-10-20 10:50:09 -05:00
// CHECK-LABEL: fn mutable_ref(
// CHECK-NOT: goto -> {{bb.*}};
// CHECK: switchInt(
// CHECK: goto -> [[bbret:bb.*]];
// CHECK: goto -> [[bbret]];
// CHECK: [[bbret]]: {
// CHECK-NOT: {{bb.*}}: {
// CHECK: return;
2023-01-16 16:12:36 -06:00
let mut x = 5;
let a = std::ptr::addr_of_mut!(x);
x = 7;
unsafe { *a = 8 };
if x == 7 { true } else { false }
2023-01-16 16:12:36 -06:00
}
2023-10-20 10:50:09 -05:00
/// This function has 2 TOs: 1-3-4 and 0-1-3-4-6.
/// We verify that the second TO does not modify 3 once the first has been applied.
2023-01-16 16:12:36 -06:00
#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
fn renumbered_bb(x: bool) -> u8 {
2023-10-20 10:50:09 -05:00
// CHECK-LABEL: fn renumbered_bb(
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-02 19:19:57 -05:00
mir! {
2023-01-16 16:12:36 -06:00
let a: bool;
let b: bool;
{
2023-10-20 10:50:09 -05:00
// CHECK: bb0: {
// CHECK: switchInt({{.*}}) -> [1: bb1, otherwise: bb2];
2023-01-16 16:12:36 -06:00
b = false;
match x { true => bb1, _ => bb2 }
}
bb1 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb1: {
// CHECK: goto -> bb8;
2023-01-16 16:12:36 -06:00
a = false;
Goto(bb3)
}
bb2 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb2: {
// CHECK: goto -> bb3;
2023-01-16 16:12:36 -06:00
a = x;
b = x;
Goto(bb3)
}
bb3 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb3: {
// CHECK: switchInt({{.*}}) -> [0: bb4, otherwise: bb5];
2023-01-16 16:12:36 -06:00
match a { false => bb4, _ => bb5 }
}
bb4 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb4: {
// CHECK: switchInt({{.*}}) -> [0: bb6, otherwise: bb7];
2023-01-16 16:12:36 -06:00
match b { false => bb6, _ => bb7 }
}
bb5 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb5: {
// CHECK: _0 = const 7_u8;
2023-01-16 16:12:36 -06:00
RET = 7;
Return()
}
bb6 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb6: {
// CHECK: _0 = const 9_u8;
2023-01-16 16:12:36 -06:00
RET = 9;
Return()
}
bb7 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb7: {
// CHECK: _0 = const 11_u8;
2023-01-16 16:12:36 -06:00
RET = 11;
Return()
}
2023-10-20 10:50:09 -05:00
// Duplicate of bb3.
// CHECK: bb8: {
// CHECK-NEXT: goto -> bb9;
// Duplicate of bb4.
// CHECK: bb9: {
// CHECK-NEXT: goto -> bb6;
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-02 19:19:57 -05:00
}
2023-01-16 16:12:36 -06:00
}
2023-10-20 10:50:09 -05:00
/// This function has 3 TOs: 1-4-5, 0-1-4-7-5-8 and 3-4-7-5-6
/// After applying the first TO, we create bb9 to replace 4, and rename 1-4 edge by 1-9. The
/// second TO may try to thread non-existing edge 9-4.
/// This test verifies that we preserve semantics by bailing out of this second TO.
2023-01-16 16:12:36 -06:00
#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
fn disappearing_bb(x: u8) -> u8 {
2023-10-20 10:50:09 -05:00
// CHECK-LABEL: fn disappearing_bb(
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-02 19:19:57 -05:00
mir! {
2023-10-20 10:50:09 -05:00
let a: bool;
let b: bool;
2023-01-16 16:12:36 -06:00
{
2023-10-20 10:50:09 -05:00
a = true;
b = true;
2023-01-16 16:12:36 -06:00
match x { 0 => bb3, 1 => bb3, 2 => bb1, _ => bb2 }
}
bb1 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb1: {
// CHECK: goto -> bb9;
b = false;
2023-01-16 16:12:36 -06:00
Goto(bb4)
}
bb2 = {
Unreachable()
}
bb3 = {
2023-10-20 10:50:09 -05:00
// CHECK: bb3: {
// CHECK: goto -> bb10;
a = false;
2023-01-16 16:12:36 -06:00
Goto(bb4)
}
bb4 = {
2023-10-20 10:50:09 -05:00
match b { false => bb5, _ => bb7 }
2023-01-16 16:12:36 -06:00
}
bb5 = {
2023-10-20 10:50:09 -05:00
match a { false => bb6, _ => bb8 }
2023-01-16 16:12:36 -06:00
}
bb6 = {
Return()
}
bb7 = {
Goto(bb5)
}
bb8 = {
Goto(bb6)
}
2023-10-20 10:50:09 -05:00
// CHECK: bb9: {
// CHECK: goto -> bb5;
// CHECK: bb10: {
// CHECK: goto -> bb6;
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-02 19:19:57 -05:00
}
2023-01-16 16:12:36 -06:00
}
2023-12-30 19:53:51 -06:00
/// Verify that we can thread jumps when we assign from an aggregate constant.
fn aggregate(x: u8) -> u8 {
// CHECK-LABEL: fn aggregate(
// CHECK-NOT: switchInt(
const FOO: (u8, u8) = (5, 13);
let (a, b) = FOO;
if a == 7 { b } else { a }
2023-12-30 19:53:51 -06:00
}
2024-01-20 13:11:45 -06:00
/// Verify that we can leverage the existence of an `Assume` terminator.
#[custom_mir(dialect = "runtime", phase = "post-cleanup")]
fn assume(a: u8, b: bool) -> u8 {
// CHECK-LABEL: fn assume(
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-02 19:19:57 -05:00
mir! {
2024-01-20 13:11:45 -06:00
{
// CHECK: bb0: {
2024-08-18 17:51:53 -05:00
// CHECK-NEXT: switchInt(copy _1) -> [7: bb1, otherwise: bb2]
2024-01-20 13:11:45 -06:00
match a { 7 => bb1, _ => bb2 }
}
bb1 = {
// CHECK: bb1: {
2024-08-18 17:51:53 -05:00
// CHECK-NEXT: assume(copy _2);
2024-01-20 13:11:45 -06:00
// CHECK-NEXT: goto -> bb6;
Assume(b);
Goto(bb3)
}
bb2 = {
// CHECK: bb2: {
// CHECK-NEXT: goto -> bb3;
Goto(bb3)
}
bb3 = {
// CHECK: bb3: {
2024-08-18 17:51:53 -05:00
// CHECK-NEXT: switchInt(copy _2) -> [0: bb4, otherwise: bb5];
2024-01-20 13:11:45 -06:00
match b { false => bb4, _ => bb5 }
}
bb4 = {
// CHECK: bb4: {
// CHECK-NEXT: _0 = const 4_u8;
// CHECK-NEXT: return;
RET = 4;
Return()
}
bb5 = {
// CHECK: bb5: {
// CHECK-NEXT: _0 = const 5_u8;
// CHECK-NEXT: return;
RET = 5;
Return()
}
// CHECK: bb6: {
// CHECK-NEXT: goto -> bb5;
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-02 19:19:57 -05:00
}
2024-01-20 13:11:45 -06:00
}
2024-06-28 08:01:27 -05:00
/// Verify that jump threading succeeds seeing through copies of aggregates.
fn aggregate_copy() -> u32 {
// CHECK-LABEL: fn aggregate_copy(
2024-06-28 08:02:08 -05:00
// CHECK-NOT: switchInt(
2024-06-28 08:01:27 -05:00
const Foo: (u32, u32) = (5, 3);
let a = Foo;
// This copies a tuple, we want to ensure that the threading condition on `b.1` propagates to a
// condition on `a.1`.
let b = a;
let c = b.1;
if c == 2 { b.0 } else { 13 }
}
fn floats() -> u32 {
// CHECK-LABEL: fn floats(
// CHECK: switchInt(
// Test for issue #128243, where float equality was assumed to be bitwise.
// When adding float support, it must be ensured that this continues working properly.
let x = if true { -0.0 } else { 1.0 };
if x == 0.0 { 0 } else { 1 }
}
2023-01-16 16:12:36 -06:00
fn main() {
2023-12-30 19:53:51 -06:00
// CHECK-LABEL: fn main(
2023-01-16 16:12:36 -06:00
too_complex(Ok(0));
identity(Ok(0));
custom_discr(false);
dfa();
multiple_match(5);
duplicate_chain(false);
mutate_discriminant();
mutable_ref();
renumbered_bb(true);
disappearing_bb(7);
2023-12-30 19:53:51 -06:00
aggregate(7);
2024-01-20 13:11:45 -06:00
assume(7, false);
floats();
2023-01-16 16:12:36 -06:00
}
// EMIT_MIR jump_threading.too_complex.JumpThreading.diff
// EMIT_MIR jump_threading.identity.JumpThreading.diff
// EMIT_MIR jump_threading.custom_discr.JumpThreading.diff
// EMIT_MIR jump_threading.dfa.JumpThreading.diff
// EMIT_MIR jump_threading.multiple_match.JumpThreading.diff
// EMIT_MIR jump_threading.duplicate_chain.JumpThreading.diff
// EMIT_MIR jump_threading.mutate_discriminant.JumpThreading.diff
// EMIT_MIR jump_threading.mutable_ref.JumpThreading.diff
// EMIT_MIR jump_threading.renumbered_bb.JumpThreading.diff
// EMIT_MIR jump_threading.disappearing_bb.JumpThreading.diff
2023-12-30 19:53:51 -06:00
// EMIT_MIR jump_threading.aggregate.JumpThreading.diff
2024-01-20 13:11:45 -06:00
// EMIT_MIR jump_threading.assume.JumpThreading.diff
2024-06-28 08:01:27 -05:00
// EMIT_MIR jump_threading.aggregate_copy.JumpThreading.diff
// EMIT_MIR jump_threading.floats.JumpThreading.diff