Repository navigation
code less optimized when accessing a specific array element, only on nightly #111508
Copy link
Copy link
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.C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchCategory: An issue highlighting optimization opportunities or PRs implementing suchE-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.Call for participation: An issue has been fixed and does not reproduce, but no test has been added.I-slowIssue: Problems and improvements with respect to performance of generated code.Issue: Problems and improvements with respect to performance of generated code.S-has-mcveStatus: A Minimal Complete and Verifiable Example has been found for this issueStatus: A Minimal Complete and Verifiable Example has been found for this issueT-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.
Description
I tried this code on rustc nightly (rustc 1.71.0-nightly (c4190f2d3 2023-05-07)) on godbolt and the assembly code contains some unnecessary checks, but not when changing the value of N to anything different than 24 (but not out of bounds for a) or changing the version to 1.69.0 or beta
const N: usize = 24;
pub fn example(a: Vec<u8>) -> u8 {
if a.len() != 32 {
return 0;
}
let a: [u8; 32] = a.try_into().unwrap();
a[15] + a[N]
}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.C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchCategory: An issue highlighting optimization opportunities or PRs implementing suchE-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.Call for participation: An issue has been fixed and does not reproduce, but no test has been added.I-slowIssue: Problems and improvements with respect to performance of generated code.Issue: Problems and improvements with respect to performance of generated code.S-has-mcveStatus: A Minimal Complete and Verifiable Example has been found for this issueStatus: A Minimal Complete and Verifiable Example has been found for this issueT-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.
Activity
clubby789 commentedon May 12, 2023
searched nightlies: from nightly-2022-11-01 to nightly-2023-05-12
regressed nightly: nightly-2023-04-30
searched commit range: f495605...87b1f89
regressed commit: f229949
bisected with cargo-bisect-rustc v0.6.6
Host triple: x86_64-unknown-linux-gnu
Reproduce with:
It looks like the vec is copied through an alloca instead of just being handled through pointers. The cause is probably the layout changing from
type { { i64, ptr }, i64 }totype { { ptr, i64 }, i64 }the8472 commentedon May 12, 2023
That's the intended layout. And I wouldn't expect pointer-in-the-middle to optimize better other than by accident.
And the optimization failure depends on which array element gets accessed after the vec has been turned into an array. So it shouldn't even be related to the Vec struct layout anymore. So it looks more like spooky action at the distance going on in LLVM.
It's also possible that the
Resultlayout for thetry_intochanged.saethlin commentedon May 12, 2023
The index 24 seems to be special. Don't know why.
There's also something very odd going on in the MIR for this: https://godbolt.org/z/f9Wa46cMr
The
15 of 16is a bit surprising to me. Maybe this is just a subtelty of our MIR dumps? But the array is length 32, so I would have expected to see a 32 there.Cranking up the MIR inliner seems to improve things, but only if you don't also increase the inlining threshold for functions with
#[inline]: https://godbolt.org/z/Ed4GvPe8d (I feel like LLVM should be more stable than this)workingjubilee commentedon May 12, 2023
I am guessing this is on an inflection point of a "if x is less than y, do this" and an "if x is greater than y, do this" heuristic, where one of the cases should be "greater or equal than" or "less than or equal".
erikdesjardins commentedon May 12, 2023
In nightly looking at 24 vs. 25, the only difference in the LLVM IR we generate is the GEP index, as you would expect:
https://godbolt.org/z/zYcs9hhYc
nikic commentedon May 13, 2023
It looks like it gets SROAd (via bit insert/extract) if the index is 25 but not if it is 24. Haven't looked into why.
Something that would also fix this is to forward load from memcpy target to load from memcpy source in GVN, which seems like it would be a good idea to do anyway.
cjgillot commentedon May 14, 2023
This is not an issue. This is the
ConstantIndexprojection. 15 is the offset and 16 is the minimum length. That information is not used by codegen, so const-prop sets it to offset+1.erikdesjardins commentedon Feb 24, 2024
Looks like this was fixed in 1.72: https://godbolt.org/z/W4j8qx8s7. I don't know why.
Add codegen test for rust-lang#111508
Add codegen test for rust-lang#111508
Add codegen test for rust-lang#111508
Auto merge of rust-lang#125347 - tesuji:needtests, r=nikic
Auto merge of rust-lang#125347 - tesuji:needtests, r=nikic
Auto merge of rust-lang#125347 - tesuji:needtests, r=nikic
Auto merge of rust-lang#125347 - tesuji:needtests, r=nikic
Auto merge of rust-lang#125347 - tesuji:needtests, r=nikic
workingjubilee commentedon Sep 23, 2024
#130726 "unfixes" this if it lands, unfortunately.