-
Notifications
You must be signed in to change notification settings - Fork 13.5k
Open
Labels
A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlA-mir-optArea: MIR optimizationsArea: MIR optimizationsC-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchCategory: An issue highlighting optimization opportunities or PRs implementing suchT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.WG-mir-optWorking group: MIR optimizationsWorking group: MIR optimizations
Description
Follow-along at https://rust.godbolt.org/z/Trzrobvo5
Consider these two functions that ought to be equivalent:
use std::cmp::Ordering;
#[no_mangle]
pub fn direct(e: Option<Ordering>) -> bool {
e == Some(Ordering::Equal)
}
#[no_mangle]
pub fn with_let(e: Option<Ordering>) -> bool {
let eq = Ordering::Equal;
e == Some(eq)
}
The latter ends up with about the MIR you'd expect: it checks for Some
, then for Equal
bb0: {
StorageLive(_2);
_2 = discriminant(_1);
switchInt(move _2) -> [0: bb1, 1: bb2, otherwise: bb4];
}
bb1: {
_0 = const false;
goto -> bb3;
}
bb2: {
StorageLive(_3);
_3 = discriminant(((_1 as Some).0: std::cmp::Ordering));
_0 = Eq(copy _3, const 0_i8);
StorageDead(_3);
goto -> bb3;
}
bb3: {
StorageDead(_2);
return;
}
bb4: {
unreachable;
}
The former, though, ends up with way more MIR because of the promoted const:
bb0: {
_2 = const direct::promoted[0];
StorageLive(_5);
StorageLive(_4);
StorageLive(_3);
_3 = discriminant(_1);
switchInt(move _3) -> [0: bb1, 1: bb2, otherwise: bb6];
}
bb1: {
_4 = discriminant((*_2));
_0 = Eq(copy _4, const 0_isize);
goto -> bb5;
}
bb2: {
_5 = discriminant((*_2));
switchInt(move _5) -> [0: bb3, 1: bb4, otherwise: bb6];
}
bb3: {
_0 = const false;
goto -> bb5;
}
bb4: {
StorageLive(_6);
StorageLive(_7);
_6 = discriminant(((_1 as Some).0: std::cmp::Ordering));
_7 = discriminant((((*_2) as Some).0: std::cmp::Ordering));
_0 = Eq(copy _6, copy _7);
StorageDead(_7);
StorageDead(_6);
goto -> bb5;
}
bb5: {
StorageDead(_3);
StorageDead(_4);
StorageDead(_5);
return;
}
bb6: {
unreachable;
}
Apparently we can't even tell what the discriminant is of that const direct::promoted[0]
, so we end up emitting even LLVM IR checks on the value of the constant, which it then has to turn around and optimize away again.
Can we maybe just unilaterally un-promote simple (Copy
+ NoCell
+ Scalar
/ScalarPair
) constants like this?
Metadata
Metadata
Assignees
Labels
A-MIRArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlArea: Mid-level IR (MIR) - https://blog.rust-lang.org/2016/04/19/MIR.htmlA-mir-optArea: MIR optimizationsArea: MIR optimizationsC-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchCategory: An issue highlighting optimization opportunities or PRs implementing suchT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.WG-mir-optWorking group: MIR optimizationsWorking group: MIR optimizations