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?

Reply via email to