https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121258

            Bug ID: 121258
           Summary: Missed optimization with 'while' loop that can be
                    converted to 'do-while'
           Product: gcc
           Version: 15.1.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: ---

GCC missed an optimization like this: When the loop body contains only counter
increments (or decrements), and the loop condition is determined externally, a
'while' loop construct can be converted to a 'do-while' with a small change in
the counter's initial value. This can save an unconditional 'jmp' instruction
at the end of the loop.

Example code:

```c
#include <stdbool.h>
#include <stdint.h>

extern bool cond(uint32_t x);

uint32_t func_a(uint32_t x) {
    uint32_t i = 10;
    while (cond(i)) {
        i++;
    }
    return i;
}

uint32_t func_b(uint32_t x) {
    uint32_t i = 9;
    do {
        i++;
    } while (cond(i));
    return i;
}
```

x86-64 gcc 15.1 with '-Os' option produces this (I tested this in Compiler
Explorer):

```x86asm
func_a:
        pushq   %rbx
        movl    $10, %ebx
.L2:
        movl    %ebx, %edi
        call    cond
        testb   %al, %al
        je      .L6
        incl    %ebx
        jmp     .L2
.L6:
        movl    %ebx, %eax
        popq    %rbx
        ret
func_b:
        pushq   %rbx
        movl    $9, %ebx
.L8:
        incl    %ebx
        movl    %ebx, %edi
        call    cond
        testb   %al, %al
        jne     .L8
        movl    %ebx, %eax
        popq    %rbx
        ret
```

The expected result is `func_a` optimizes to `func_b`. The two functions should
be equivalent.

Clang 20.1.0 does perform such an optimization.

Note that such optimization opportunity is not limited to additions and
subtractions. Below is an example that the counter multiplies by 2 instead
(Clang 20.1.0 currently missed this one):

```c
uint32_t func2_a(uint32_t x) {
    uint32_t i = 10;
    while (cond(i)) {
        i *= 2;
    }
    return i;
}

uint32_t func2_b(uint32_t x) {
    uint32_t i = 5;
    do {
        i *= 2;
    } while (cond(i));
    return i;
}
```

Reply via email to