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. */