Open
Description
All Rust programs have reducible control flow -- except if we write them with custom MIR:
#![feature(custom_mir, core_intrinsics)]
extern crate core;
use core::intrinsics::mir::*;
#[custom_mir(dialect = "built")]
pub fn irreducible(x: bool) { mir! (
// start block jumps to one of two different blocks inside the below loop
{
match x {
true => bb1,
_ => bb2
}
}
// bb1, bb2 form a loop
bb1 = {
Goto(bb2)
}
bb2 = {
Goto(bb1)
}
)}
Here is a more complicated example that doesn't get optimized away immediately:
#![feature(custom_mir, core_intrinsics)]
extern crate core;
use core::intrinsics::mir::*;
#[inline(never)]
pub fn black_box() -> i32 {
std::hint::black_box(42)
}
#[custom_mir(dialect = "built")]
pub fn irreducible(x: bool) { mir! (
let y: i32;
// start block jumps to one of two different blocks inside the below loop
{
match x {
true => bb1,
_ => bb3
}
}
// bb1, bb2, bb3, bb4 form a loop (with some early exit points)
bb1 = {
Call(y, bb2, black_box())
}
bb2 = {
match y {
1 => bb3,
_ => ret
}
}
bb3 = {
Call(y, bb4, black_box())
}
bb4 = {
match y {
1 => bb1,
_ => ret
}
}
ret = {
Return()
}
)}
This should probably be rejected right after Custom MIR building? At least I assume later MIR passes can generally assume reducible control flow.
Thanks to @cbeuw for the examples.
Cc @JakobDegen