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?