https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69569

            Bug ID: 69569
           Summary: unnecessary branches on an if followed by a switch
           Product: gcc
           Version: 6.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: rtl-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: msebor at gcc dot gnu.org
  Target Milestone: ---

While investigating the target-specific bug 37262 we noticed a
target-independent optimization opportunity for code like the following where
GCC emits an unnecessary branch for code like that below:

int foo ();

int baz (int i)
{
  if (i < 3)
    switch (i) {
    case 0:
    case 1:
      break;
    case 2:
      return foo ();
   }
   return 77;
}

For instance, in the powerpc64le code, when the first branch is taken it's
immediately followed by another branch.  The second branch could be eliminated.

baz:
.LCF1:
0:      addis 2,12,.TOC.-.LCF1@ha
        addi 2,2,.TOC.-.LCF1@l
        cmpwi 7,3,2
        ble 7,.L17
.L12:
        li 3,77
        blr
.L17:
        bne 7,.L12
        mflr 0
        std 0,16(1)
        stdu 1,-96(1)
        bl foo
        nop
        addi 1,1,96
        ld 0,16(1)
        mtlr 0
        blr

Annotating the if conditional using __builtin_expect(i < 3, E) and comparing
the results shows that GCC assumes the if branch not to be taken.  When
annotated to indicate the branch is likely to be taken (E=1), the problem
becomes more obvious.  Of the two consecutive branch instructions the first is
clearly unnecessary.

bar_1:
.LCF2:
0:      addis 2,12,.TOC.-.LCF2@ha
        addi 2,2,.TOC.-.LCF2@l
        cmpwi 7,3,2
        bgt 7,.L29    <<< unnecessary branch
        beq 7,.L34
.L29:
        li 3,77
        blr
.L34:
        mflr 0
        std 0,16(1)
        stdu 1,-96(1)
        bl foo
        nop
        addi 1,1,96
        ld 0,16(1)
        mtlr 0
        blr

The x86_64 code is comparable:

        cmpl    $2, %edi
        jg      .L14       <<< unnecessary branch
        je      .L19
.L14:
        movl    $77, %eax
        ret
.L19:
        xorl    %eax, %eax
        jmp     foo


For comparison, Clang emits the following for x86_64:

bar_1:                                  # @bar_1
        cmpl    $2, %edi
        jne     .LBB2_1
        xorl    %eax, %eax
        jmp     foo                     # TAILCALL
.LBB2_1:                                # %return
        movl    $77, %eax
        retq

Reply via email to