Bug 122272 - extra move in some cases; missed optimizations in classic "gcd" implementation
Summary: extra move in some cases; missed optimizations in classic "gcd" implementation
Status: ASSIGNED
Alias: None
Product: gcc
Classification: Unclassified
Component: rtl-optimization (show other bugs)
Version: 15.2.1
: P3 normal
Target Milestone: ---
Assignee: Drea Pinski
URL:
Keywords: missed-optimization, ra
Depends on:
Blocks:
 
Reported: 2025-10-13 22:35 UTC by Matt Godbolt
Modified: 2026-01-02 07:01 UTC (History)
2 users (show)

See Also:
Host:
Target: x86_64
Build:
Known to work:
Known to fail:
Last reconfirmed: 2026-01-02 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Matt Godbolt 2025-10-13 22:35:52 UTC
In the straightforward code:

```
unsigned gcd(unsigned a, unsigned b) {
  if (b == 0) return a;
  return gcd(b, a % b);
}
```

GCC for x86 at -O2 (or -O3) generates the following assembly, which has a number of redundant register moves (marked with ?):

```asm
gcd(unsigned int, unsigned int):
  mov eax, edi      ; eax (return value) = a
  test esi, esi     ; is b == 0?
  jne .L2           ; if b != 0; goto starting point L2
  jmp .L10          ; if b = 0; goto special case

.L11:               ; loop top
  mov esi, edx      ; set b to be a % b from the previous iteration

.L2:
  xor edx, edx      ; set up for divide
  div esi           ; eax = edx:eax (0:a) / esi (b)
                    ; edx = edx:eax (0:a) % esi (b)
  mov eax, esi      ; eax = b
  test edx, edx     ; was a % b zero?
  jne .L11          ; if not, loop around
  mov eax, esi      ; return esi (? eax is already esi)
  ret               ; returns a
.L10:
; This seems daft; when we get here, eax already has
; the right value, so the compiler has overcomplicated things.
  mov esi, edi      ; (?) esi = a
  mov eax, esi      ; (?) eax (return value) = esi
  ret               ; returns a
```

Nothing obvious (to me, anyway) in the optimisation report.

Clang 21 produces much tighter code (unannotated here):

```
gcd(unsigned int, unsigned int):
  mov eax, edi
  test esi, esi
  je .LBB0_4
  mov edx, esi
.LBB0_2:
  mov ecx, edx
  xor edx, edx
  div ecx
  mov eax, ecx
  test edx, edx
  jne .LBB0_2
  mov eax, ecx
.LBB0_4:
  ret
```

CE link: https://godbolt.org/z/34jfKrW57
Comment 1 Drea Pinski 2025-10-13 22:56:56 UTC
99% sure this is a dup of bug 106688. The number of extra moves is fixed with -fno-tree-coalesce-vars even.

Basically out of ssa sometimes with coalescing turned on will chose the wrong coalescing and that causes extra moves for returns.
Comment 2 Drea Pinski 2026-01-02 07:01:06 UTC
Related to the other bug I am working on.