[Bug tree-optimization/54742] New: Switch elimination in FSM loop

joey.ye at arm dot com gcc-bugzilla@gcc.gnu.org
Sat Sep 29 03:16:00 GMT 2012


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54742

             Bug #: 54742
           Summary: Switch elimination in FSM loop
    Classification: Unclassified
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
        AssignedTo: unassigned@gcc.gnu.org
        ReportedBy: joey.ye@arm.com


Following interesting case is reduced from a benchmark. It implements a FSM
with a loop and switch. There is opportunity to eliminate the switch since all
state transition is definite in compile time.


Source program:
---
int sum0, sum1, sum2, sum3;
int foo(const char * str)
{
    int state=0;
    const char *s=str;

    for (; *s; s++)
    {
        char c=*s;
        switch (state) {
            case 0:
                if (c == '+') state = 1;
                else if (c != '-') sum0+=c;
                break;
            case 1:
                if (c == '+') state = 2;
                else if (c == '-') state = 0;
                else sum1+=c;
                break;
            case 2:
                if (c == '+') state = 3;
                else if (c == '-') state = 1;
                else sum2+=c;
                break;
            case 3:
                if (c == '-') state = 2;
                else if (c != '+') sum3+=c;
                break;
            default:
                break;
        }
    }
    return state;
}
---
Say, instead of setting state=1 and loop back to switch head, it can be
optimized to setting state=1, check loop end condition and jump directly to the
label of case_1. Thus the overhead of switch (either if-then-else or jump
table) is eliminated. On machine without sophisticate branch prediction, such
an optimization is even more appealing.

GCC trunk 4.8 doesn't have such a optimization.

Expected tree output in source form:
---
int sum0, sum1, sum2, sum3;
int foo(const char * str)
{
    int state=0;
    const char *s=str;
    char c=*s;
    if (!c) goto end;
state_0:
    if (c == '+') {
        state = 1;
        if ((c=* (++s))!=0) goto state_1;   // Check loop end condition and go
directly to next state
        else goto end;
    }
    else if (c != '-') sum0+=c;
    if ((c=* (++s))!=0) goto state_0;
    goto end;

state_1:
    if (c == '+') {
        state = 2;
        if ((c=* (++s))!=0) goto state_2;
        else goto end;
    }
    else if (c == '-') {
        state = 0;
        if ((c=* (++s))!=0) goto state_0;
        else goto end;
    }
    else sum1+=c;
    if ((c=* (++s))!=0) goto state_1;
    goto end;

state_2:
    if (c == '+') {
        state = 3;
        if ((c=* (++s))!=0) goto state_3;
        else goto end;
    }
    else if (c == '-') {
        state = 1;
        if ((c=* (++s))!=0) goto state_1;
        else goto end;
    }
    else sum1+=c;
    if ((c=* (++s))!=0) goto state_2;
    goto end;

state_3:
    if (c == '-') {
        state = 2;
        if ((c=* (++s))!=0) goto state_2;
        else goto end;
    }
    else if (c != '+') sum3+=c;
    if ((c=* (++s))!=0) goto state_3;
end:
    return state;
}
---



More information about the Gcc-bugs mailing list