-
Notifications
You must be signed in to change notification settings - Fork 15.4k
Open
Description
In clang 21.1.0 (and earlier), in the following code, which is about as reduced as I can get:
#include <cstddef>
// [[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_intsfunction to be noted asconst(or similar) Certainly "pure". TBAA should note that it only reads through anint*if at all. Maybeargmemonly(I think?) - as a result the
count_intsis called inside the loop (even though it's cleverly been turned into awcslen. 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.
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.