llvm / llvm/llvm-project

[InstCombine] failed to recognize branchless conditional negate to abs

Closed
#212,139 6 comments 0 reactions 2 assignees Claimed by @AZero13 View on GitHub
llvm:instcombine missed-optimization
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

https://godbolt.org/z/hnhe9TxfW

found from https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113894

https://github.com/gcc-mirror/gcc/commit/01d1d20266a4c1f02457dd9df1b25a733d701466

>match.pd: Recognize branchless conditional negate [PR113894]
>This patch teaches match.pd to recognize the branchless conditional negate
>idiom (x ^ -cmp) + cmp when cmp is known to be zero or one. The
>expression is folded to a conditional negate form.
>
>For the sign-test spelling based on x < 0, the patch exposes ABS_EXPR.
>
> PR tree-optimization/113894
>
>gcc/ChangeLog:
>
> * match.pd: Add simplifications for branchless conditional negate
> and sign-test absolute value idioms.
>
>gcc/testsuite/ChangeLog:
>
> * gcc.dg/tree-ssa/pr113894.c: New test.

```c
int f_cmp_lt(int x, int y)
{
int cmp = x < y;
return (x ^ -cmp) + cmp;
}

int f_cmp_gt_commuted(int x, int y)
{
int cmp = x > y;
return cmp + (-cmp ^ x);
}

unsigned f_unsigned_cmp(unsigned x, unsigned y)
{
unsigned cmp = x < y;
return (x ^ -cmp) + cmp;
}

int f_mask(int x, unsigned y)
{
int cmp = y & 1;
return (x ^ -cmp) + cmp;
}

int f_bool(int x, _Bool cmp)
{
int icmp = cmp;
return (x ^ -icmp) + icmp;
}

int f_abs_int(int x)
{
int cmp = x < 0;
return (x ^ -cmp) + cmp;
}

long f_abs_long(long x)
{
long cmp = x < 0;
return (x ^ -cmp) + cmp;
}

int f_signed_not_zero_one(int x, int cmp)
{
return (x ^ -cmp) + cmp;
}

unsigned f_unsigned_not_zero_one(unsigned x, unsigned cmp)
{
return (x ^ -cmp) + cmp;
}
```
gcc
```asm
f_cmp_lt:
movl %edi, %eax
negl %eax
cmpl %esi, %edi
cmovge %edi, %eax
ret
f_cmp_gt_commuted:
movl %edi, %eax
negl %eax
cmpl %esi, %edi
cmovle %edi, %eax
ret
f_unsigned_cmp:
movl %edi, %eax
negl %eax
cmpl %esi, %edi
cmovnb %edi, %eax
ret
f_mask:
movl %edi, %eax
negl %eax
andl $1, %esi
cmove %edi, %eax
ret
f_bool:
movl %edi, %eax
negl %eax
testb %sil, %sil
cmove %edi, %eax
ret
f_abs_int:
movl %edi, %edx
movl %edi, %eax
sarl $31, %edx
xorl %edx, %eax
subl %edx, %eax
ret
f_abs_long:
movq %rdi, %rdx
movq %rdi, %rax
sarq $63, %rdx
xorq %rdx, %rax
subq %rdx, %rax
ret
f_signed_not_zero_one:
movl %esi, %eax
negl %eax
xorl %edi, %eax
addl %esi, %eax
ret
f_unsigned_not_zero_one:
movl %esi, %eax
negl %eax
xorl %edi, %eax
addl %esi, %eax
ret
```
clang
```asm
f_cmp_lt:
xorl %ecx, %ecx
cmpl %esi, %edi
setl %cl
movl %ecx, %eax
negl %eax
xorl %edi, %eax
addl %ecx, %eax
retq

f_cmp_gt_commuted:
xorl %ecx, %ecx
cmpl %esi, %edi
setg %cl
movl %ecx, %eax
negl %eax
xorl %edi, %eax
addl %ecx, %eax
retq

f_unsigned_cmp:
xorl %ecx, %ecx
cmpl %esi, %edi
setb %cl
movl %ecx, %eax
negl %eax
xorl %edi, %eax
addl %ecx, %eax
retq

f_mask:
andl $1, %esi
movl %esi, %eax
negl %eax
xorl %edi, %eax
addl %esi, %eax
retq

f_bool:
movl %esi, %eax
negl %eax
xorl %edi, %eax
addl %esi, %eax
retq

f_abs_int:
movl %edi, %eax
sarl $31, %eax
xorl %edi, %eax
shrl $31, %edi
addl %edi, %eax
retq

f_abs_long:
movq %rdi, %rax
sarq $63, %rax
xorq %rdi, %rax
shrq $63, %rdi
addq %rdi, %rax
retq

f_signed_not_zero_one:
movl %esi, %eax
negl %eax
xorl %edi, %eax
addl %esi, %eax
retq

f_unsigned_not_zero_one:
movl %esi, %eax
negl %eax
xorl %edi, %eax
addl %esi, %eax
retq
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.