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