Description
This is how a typical state machine might look in Rust:
#[inline(never)]
fn print(s: &str) {
println!("{}", s);
}
#[inline(never)]
fn exec(mut s: i32) {
loop {
match s {
0 => { print("0"); s = 2; },
1 => { print("1"); s = 3; },
2 => { print("2"); s = 1; },
_ => return
}
}
}
fn main() {
exec(0);
}
One would expect that the first jump from function start into one of the states (0, 1, 2 or _) would be compiled as a jumptable or a series of cmp/conditional jump instructions and once the execution is in one of the states the remaining jumps would be deterministic (non-conditional) jumps.
And this is how equivalent code in gcc is optimized.
However Rust/LLVM at the end of each state performs needless comparisons to determine to which label to jump to next, even though the jump target can be computed statically. You can inspect the generated assembly in Rust Playground.
This is probably more of a LLVM issue rather than Rust directly, but it's important to get this fixed/optimized, because now it's impossible to efficiently write such state machines in Rust (because there is no goto
)
Meta
Tested with all versions available in Rust playground: