https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92953
Bug ID: 92953
Summary: Undesired if-conversion with overflow builtins
Product: gcc
Version: 10.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: rtl-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: amonakov at gcc dot gnu.org
Target Milestone: ---
Consider:
/* Return 0 if a==b, any positive value if a>b, any negative value otherwise.
*/
int foo(int a, int b)
{
int c;
if (__builtin_sub_overflow(a, b, &c))
c = 1 | ~c;
return c;
}
(suggestions for implementations that would be more efficient on x86 welcome)
on x86 with -Os gives the expected
foo:
subl %esi, %edi
movl %edi, %eax
jno .L1
notl %eax
orl $1, %eax
.L1:
ret
but with -O2 there's if-conversion despite internal-fn.c marking the branch as
"very_unlikely":
foo:
xorl %edx, %edx
subl %esi, %edi
movl %edi, %eax
seto %dl
notl %eax
orl $1, %eax
testl %edx, %edx
cmove %edi, %eax
ret
Adding __builtin_expect to the source doesn't help. Adding
__builtin_expect_with_probability helps when specified probability is very low
(<3%), but I feel that shouldn't be required here.
Looking at expand dump, on RTL we start with two branches, first from expanding
the internal fn to calculate a 0/1 predicate value, the second corresponding to
the "if" in the source, branching on testing that predicate against 0. At -Os,
we rely on first if-conversion pass to eliminate the first branch, and then on
combine to optimize the second branch.
Is it possible to expand straight to one branch by noticing that the predicate
is only used in the gimple conditional that follows immediately?