https://gcc.gnu.org/bugzilla/show_bug.cgi?id=124175
Bug ID: 124175
Summary: Optimization when conditionals at the beginning of a
loop may be skipped by the variables' constraints
Product: gcc
Version: 15.2.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: Explorer09 at gmail dot com
Target Milestone: ---
```c
static inline void subroutine1(void) {__asm__("nop":);}
void func1a(char *restrict p) {
while (1) {
while (*p == 'x') {
p++;
}
while (*p != 'x') {
if (*p == '\0') {
return;
}
p++;
}
// Assume subroutine1 does not modify p ('restrict' qualifier)
subroutine1();
}
}
void func1b(char *restrict p) {
while (1) {
while (*p == 'x') {
p++;
}
while (*p != 'x') {
if (*p == '\0') {
return;
}
p++;
}
subroutine1();
p++;
}
}
void func1c(char *restrict p) {
while (1) {
while (*p == 'x') {
increment:
p++;
}
do {
if (*p == '\0') {
return;
}
p++;
} while (*p != 'x');
subroutine1();
goto increment;
}
}
```
Compiler Explorer link:
https://godbolt.org/z/bYhPeajvx
The three functions (func1a, func1b and func1c) are equivalent. I expect when
the compiler optimizes jumps, it would choose func1c.
Note the `goto increment;` and the "increment" label: After subroutine1 (which
is assumed to never modify `p`, by the way) the `(*p == 'x')` constraint should
still hold, and when the code jumps back to the beginning of the loop, it can
skip the `(*p == 'x')` conditional and jump to the block where the conditional
is true.
While this optimization won't reduce code size by itself, it can save some
compare operations upon an entry of the loop. Thus this optimization feature
request.
(In the Compiler Explorer link I included another example,
print_ancestor_dirs(), from which func1a() to func1c() are simplified.
```c
#include <stdio.h>
void print_ancestor_dirs(char *path) {
char *p = path;
while (1) {
while (*p == '/') {
p++;
}
while (*p != '\0' && *p != '/') {
p++;
}
if (*p == '\0') {
break;
}
*p = '\0';
puts(path);
*p = '/';
}
}
```
In print_ancestor_dirs(), the `(*p == '/')` condition is satisfied at the end
of the larger loop due to the `*p = '/';` assignment.)