https://gcc.gnu.org/bugzilla/show_bug.cgi?id=122911
Bug ID: 122911
Summary: Redundant code when calculating / 10 and %10 for
signed/unsigned mixture
Product: gcc
Version: 16.0
Status: UNCONFIRMED
Severity: enhancement
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: tkoenig at gcc dot gnu.org
Target Milestone: ---
Consider
void bar(unsigned long, long);
void foo(unsigned long u1)
{
long u3;
u1 = u1 / 10;
u3 = u1 % 10;
bar(u1,u3);
}
which yields, with a reasonably recent trunk at -O2,
foo:
.LFB0:
.cfi_startproc
movabsq $-3689348814741910323, %rcx
movq %rdi, %rax
mulq %rcx
movq %rdx, %rdi
shrq $3, %rdi
movq %rdi, %rax
movq %rdi, %rsi
mulq %rcx
shrq $3, %rdx
leaq (%rdx,%rdx,4), %rax
addq %rax, %rax
subq %rax, %rsi
jmp bar
which calculates u1/10 twice.
POWER has (compiled with godbolt)
foo:
.LCF0:
0: addis 2,12,.TOC.-.LCF0@ha
addi 2,2,.TOC.-.LCF0@l
mflr 0
lis 9,0xcccc
lis 10,0xcccc
ori 9,9,0xcccd
ori 10,10,0xcccc
rldimi 9,10,32,0
mulhdu 3,3,9
std 0,16(1)
stdu 1,-32(1)
srdi 3,3,3
mulhdu 9,3,9
srdi 9,9,3
mulli 9,9,10
subf 4,9,3
bl bar
nop
addi 1,1,32
ld 0,16(1)
mtlr 0
blr
so it shows a similar problem.
Dividing an unsigned long number by 10 will always yield a
valid long, so this could be improved.