https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126078
Bug ID: 126078
Summary: guaranteed power of two value is not recognized,
leading to div instead and operation
Product: gcc
Version: 16.1.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: gcc at breakpoint dot cc
Target Milestone: ---
The following code:
#define EINVAL 22
#define FLAGS_NUMA 0x0080
#define FLAGS_SIZE_MASK 0x0003
static inline unsigned int futex_size(unsigned int flags)
{
return 1 << (flags & FLAGS_SIZE_MASK);
}
int get_futex_key(unsigned int *uaddr, unsigned flags)
{
unsigned long address = (unsigned long)uaddr;
int size;
size = futex_size(flags);
if (flags & FLAGS_NUMA)
size *= 2;
if ((address % size) != 0)
return -EINVAL;
return 0;
}
guarantees that size is always power of two. The check
"(address % size) != 0" is translated into a div operation at -O2:
movl %esi, %ecx
movq %rdi, %rax
movl $2, %edx
movl %esi, %edi
andl $3, %ecx
movl $1, %esi
sall %cl, %esi
sall %cl, %edx
andl $128, %edi
cmove %esi, %edx
movslq %edx, %rcx
xorl %edx, %edx
divq %rcx
testq %rdx, %rdx
jne .L5
xorl %eax, %eax
ret
but this could be avoided if it knew that it is the same as "(address &
(size-1)) != 0" due to "1 << val" in futex_size. clang figures it out:
movl %esi, %ecx
xorl %eax, %eax
testb %cl, %cl
sets %al
incl %eax
andb $3, %cl
shll %cl, %eax
decq %rax
xorl %ecx, %ecx
testq %rdi, %rax
movl $-22, %eax
cmovel %ecx, %eax
retq
Could we have the same for gcc, please?