-
-
Notifications
You must be signed in to change notification settings - Fork 14.7k
Open
Labels
A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-bugCategory: This is a bug.Category: This is a bug.I-heavyIssue: Problems and improvements with respect to binary size of generated code.Issue: Problems and improvements with respect to binary size of generated code.I-slowIssue: Problems and improvements with respect to performance of generated code.Issue: Problems and improvements with respect to performance of generated code.llvm-fixed-upstreamIssue expected to be fixed by the next major LLVM upgrade, or backported fixesIssue expected to be fixed by the next major LLVM upgrade, or backported fixes
Description
It seems that function inlining heuristics fail in the following use case and does not inline when it should. Given huge match statement:
pub enum XXX {
A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, K1, L1, M1, N1, O1, P1, Q1, R1, S1, T1, U1, V1, W1, X1, Y1, Z1,
A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, K2, L2, M2, N2, O2, P2, Q2, R2, S2, T2, U2, V2, W2, X2, Y2, Z2,
}
impl std::convert::TryFrom<u8> for XXX {
type Error = ();
fn try_from(x: u8) -> Result<Self, Self::Error> {
match () {
_ if x == XXX::A1 as u8 => Ok(XXX::A1),
_ if x == XXX::B1 as u8 => Ok(XXX::B1),
_ if x == XXX::C1 as u8 => Ok(XXX::C1),
_ if x == XXX::D1 as u8 => Ok(XXX::D1),
_ if x == XXX::E1 as u8 => Ok(XXX::E1),
_ if x == XXX::F1 as u8 => Ok(XXX::F1),
_ if x == XXX::G1 as u8 => Ok(XXX::G1),
_ if x == XXX::H1 as u8 => Ok(XXX::H1),
_ if x == XXX::I1 as u8 => Ok(XXX::I1),
_ if x == XXX::J1 as u8 => Ok(XXX::J1),
_ if x == XXX::K1 as u8 => Ok(XXX::K1),
_ if x == XXX::L1 as u8 => Ok(XXX::L1),
_ if x == XXX::M1 as u8 => Ok(XXX::M1),
_ if x == XXX::N1 as u8 => Ok(XXX::N1),
_ if x == XXX::O1 as u8 => Ok(XXX::O1),
_ if x == XXX::P1 as u8 => Ok(XXX::P1),
_ if x == XXX::Q1 as u8 => Ok(XXX::Q1),
_ if x == XXX::R1 as u8 => Ok(XXX::R1),
_ if x == XXX::S1 as u8 => Ok(XXX::S1),
_ if x == XXX::T1 as u8 => Ok(XXX::T1),
_ if x == XXX::U1 as u8 => Ok(XXX::U1),
_ if x == XXX::V1 as u8 => Ok(XXX::V1),
_ if x == XXX::W1 as u8 => Ok(XXX::W1),
_ if x == XXX::X1 as u8 => Ok(XXX::X1),
_ if x == XXX::Y1 as u8 => Ok(XXX::Y1),
_ if x == XXX::Z1 as u8 => Ok(XXX::Z1),
_ if x == XXX::A2 as u8 => Ok(XXX::A2),
_ if x == XXX::B2 as u8 => Ok(XXX::B2),
_ if x == XXX::C2 as u8 => Ok(XXX::C2),
_ if x == XXX::D2 as u8 => Ok(XXX::D2),
_ if x == XXX::E2 as u8 => Ok(XXX::E2),
_ if x == XXX::F2 as u8 => Ok(XXX::F2),
_ if x == XXX::G2 as u8 => Ok(XXX::G2),
_ if x == XXX::H2 as u8 => Ok(XXX::H2),
_ if x == XXX::I2 as u8 => Ok(XXX::I2),
_ if x == XXX::J2 as u8 => Ok(XXX::J2),
_ if x == XXX::K2 as u8 => Ok(XXX::K2),
_ if x == XXX::L2 as u8 => Ok(XXX::L2),
_ if x == XXX::M2 as u8 => Ok(XXX::M2),
_ if x == XXX::N2 as u8 => Ok(XXX::N2),
_ if x == XXX::O2 as u8 => Ok(XXX::O2),
_ if x == XXX::P2 as u8 => Ok(XXX::P2),
_ if x == XXX::Q2 as u8 => Ok(XXX::Q2),
_ if x == XXX::R2 as u8 => Ok(XXX::R2),
_ if x == XXX::S2 as u8 => Ok(XXX::S2),
_ if x == XXX::T2 as u8 => Ok(XXX::T2),
_ if x == XXX::U2 as u8 => Ok(XXX::U2),
_ if x == XXX::V2 as u8 => Ok(XXX::V2),
_ if x == XXX::W2 as u8 => Ok(XXX::W2),
_ if x == XXX::X2 as u8 => Ok(XXX::X2),
_ if x == XXX::Y2 as u8 => Ok(XXX::Y2),
_ if x == XXX::Z2 as u8 => Ok(XXX::Z2),
_ => Err(()),
}
}
}Rust does a great job of boiling it down:
<XXX as core::convert::TryFrom<u8>>::try_from:
cmp dil, 52
mov eax, 52
cmovb eax, edi
retBut it doesn't inline this properly when used in other functions:
impl XXX {
pub fn new(x: u8) -> Self {
Self::try_from(x).expect("bad num")
}
}generates:
XXX::new:
push rax
call qword ptr [rip + <XXX as core::convert::TryFrom<u8>>::try_from@GOTPCREL]
cmp al, 52
je .LBB139_1
pop rcx
retAn explicit #[inline] given to try_from results in this instead:
XXX::new:
cmp dil, 52
jae .LBB139_1
mov eax, edi
retrustc --version --verbose:
rustc 1.74.1 (a28077b28 2023-12-04)
binary: rustc
commit-hash: a28077b28a02b92985b3a3faecf92813155f1ea1
commit-date: 2023-12-04
host: x86_64-unknown-linux-gnu
release: 1.74.1
LLVM version: 17.0.4
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-bugCategory: This is a bug.Category: This is a bug.I-heavyIssue: Problems and improvements with respect to binary size of generated code.Issue: Problems and improvements with respect to binary size of generated code.I-slowIssue: Problems and improvements with respect to performance of generated code.Issue: Problems and improvements with respect to performance of generated code.llvm-fixed-upstreamIssue expected to be fixed by the next major LLVM upgrade, or backported fixesIssue expected to be fixed by the next major LLVM upgrade, or backported fixes
Type
Fields
Give feedbackNo fields configured for issues without a type.