Steve Ellcey wrote:
> +/* This file implements an optimization where, when a variable is set
> +   to a constant value and there is a path that leads from that definition
> +   to a switch statement that uses that variable as its controlling 
> expression
> +   we duplicate the blocks on this path and change the jump to the switch
> +   statement with a direct jump to the label of the switch block that control
> +   would goto based on the value of the variable.  This can come up in
> +   loops/switch statements that implement state machines.

Can you explain why the jump-threading pass cannot do this?  Why do we need
another pass to handle a corner case that jump-thread does not catch yet?

> +
> +   Example (modified from PR 54742):
> +
> +   foo(char *str) {
> +     int sum=0;
> +     int state=0;
> +     char *s=str;
> +     for (; *s; s++) {
> +       char c=*s;
> +       <CODE BLOCK 1>

>From what I understand, Jeff has fixed jump-threading to catch exactly the
pattern in this example.  What jump-threading doesn't do yet is duplicate the
path when <CODE BLOCK 1> is a condition, like in the example in comment 27:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54742#c27
(see the if (c == '*') ):

int sum0, sum1, sum2, sum3;
int foo(char * s, char** ret)
{
  int state=0;
  char c;

  for (; *s && state != 4; s++)
    {
      c = *s;
      if (c == '*')
        {
          s++;
          break;
        }
      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 == 'x') state = 4;
          break;
        default:
          break;
      }
    }
  *ret = s;
  return state;
}


> +       switch (state) {
> +         case 0:
> +           if (c == '+')       { state = 1; sum += 9; }
> +           else if (c != '-')  { state = 2; sum += 3; }
> +           break;
> +         case 1:
> +           if (c == '+')       { state = 2; sum += 4; }
> +           else if (c == '-')  { state = 0; sum += 7; }
> +           break;
> +         case 2:
> +           if (c == '+')       { state = 0; sum += 8; }
> +           else if (c == '-')  { state = 1; sum += 2; }
> +           break;
> +       }
> +       <CODE BLOCK 2>
> +     }
> +     return state;
> +   }
> +
> +  This pass will convert the code inside 'case 0' to something like:
> +
> +    case 0:
> +      if (c == '+')      { state = 1; sum += 9;
> +                           <CODE BLOCK 2>
> +                           s++; if (!s) goto loop_exit;
> +                           <CODE BLOCK 1>
> +                           goto case_1; }
> +      else if (c != '-') { state = 2; sum += 3;
> +                           <CODE BLOCK 2>
> +                           s++; if (!s) goto loop_exit;
> +                           <CODE BLOCK 1>
> +                           goto case_2; }
> +      else               { <CODE BLOCK 2>
> +                        s++; if (!s) goto exit;
> +                           <CODE BLOCK 1>
> +                           goto case_0; }
> +
> +Similar transformations would apply to the other parts of the switch
> +statement.  This obviously can lead to a lot of code duplication but
> +it can also result in faster code since we are replacing two jumps
> +(one indirect) with a single direct jump.  */

Reply via email to