[llvm:optimizations] [missed-optimization] Unable to hoist out call to readonly function in a loop
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
In clang 21.1.0 (and earlier), in the following code, which is about as reduced as I can get:
```cpp
#include
// [[gnu::noinline]]
// [[gnu::const]]
// [[gnu::noinline, gnu::const]]
static std::size_t count_ints(const int *ints) {
std::size_t num{};
while (*ints) {
num++;
ints++;
}
return num;
}
std::size_t num_compares{};
// Returns if a zero-termed list of ints has 1234
bool has_1234(const int *ints) {
for (std::size_t index = 0; index < count_ints(ints); ++index) {
++num_compares;
if (ints[index] == 1234) {
return true;
}
}
return false;
}
```
CE link: https://godbolt.org/z/raPrvq9aT
Here I would expect:
- the `count_ints` function to be noted as `const` (or similar) Certainly "pure". TBAA should note that it only reads through an `int*` if at all. Maybe `argmemonly` (I think?)
- as a result the `count_ints` is called inside the loop (even though it's cleverly been turned into a `wcslen`. I'd hope LICM could yank it out
- that results in poor performance (O(n2)) though naturally this code is awful (on purpose!)
Interestingly, marking it `gnu::const` (not strictly true) still causes the wcslen to be inlined and called every iteration. Making it `noinline` _and_ `const` "fixes" this but I think is not strictly true (as I understand it the read through `*ints` makes it non-const which is to say "readnone" in llvm).
Similar reported to [gcc](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122240).
I discussed this over Discord with a few folks more familiar with LLVM and they said to file this with the tags in the title. Sorry if this is not the correct way to do this.
Contributor guide
Assessment
This issue has not been assessed yet.