karl@dartvax.UUCP (Karl Berry.) (07/11/85)
Although it is true that pc does not have an otherwise clause, pxp, when given the -O option, will translate the case statements appropriately. [I think the keyword in Pascal is `others:' to get it to do this.] This is what the TeX distribution does, and it works fine. If it works for TeX, it'll work for almost anything. I think this applies to both 4.1 and 4.2 bsd, but maybe just 4.2. The -O option is undocumented, of course. [Like having to use -J for long jumps to work correctly.] karl@dartmouth.csnet dartvax!karl
chris@umcp-cs.UUCP (Chris Torek) (07/12/85)
I *had* forgotten about that (blush). However, I would like to point out that we observed a 15% speed increase in TeX when compiling "others" directly (without using pxp to hack cases). That's not insignificant.... (I squeezed an additional 15% out of it by using a post-optimizer optimizer hack, that fixed up things like addl2 $30000,r0 ashl $2,r0,r0 addl2 $_mem,r0 addl2 $2,r0 turning them into moval 120002[r0],r0 Sequences like this are very common in code produced by pc that uses arrays of records whose lowest subscript is negative; TeX happens to use such arrays for pseudo-dynamic memory. Replacing 4 instructions with 1 has a pretty significant effect, especially when it can be done in the memory allocator....) [Heck, here's the code, if anyone wants to play with it.] #ifndef lint static char rcsid[] = "$Header$"; #endif /* * fiddle - fiddle with assembly code (play peephole optimizer). * Depends heavily on the output format of /lib/c2. * * Date: sometime in early 1985. * Author: Chris Torek. * * This code is public domain, not that many would want it in its * present state. You may redistribute it freely so long as the * author notice remains intact. */ #include <stdio.h> #include <ctype.h> char inbuf[BUFSIZ]; main () { register char *p, *bufp; while (fgets (inbuf, sizeof inbuf, stdin)) { retry: p = bufp = inbuf; while (*p) if (*p++ == ':') bufp = p; p = bufp; if (p > inbuf) { register int c = *p; *p = 0; fputs (inbuf, stdout); *p = c; } if (*p++ == 'a' && *p++ == 'd' && *p++ == 'd' && *p++ == 'l' && *p++ == '2' && *p++ == '\t') { /* stuff depending on "addl2\t" */ if (try1 (p)) goto retry; if (try2 (p)) goto retry; } p = bufp; if (*p++ == 'a' && *p++ == 's' && *p++ == 'h' && *p++ == 'l' && *p++ == '\t' && *p++ == '$' && *p++ == '2' && *p++ == ',' && *p++ == 'r') { /* stuff depending on "ashl\t$2,r" */ if (try3 ()) goto retry; } fputs (bufp, stdout); } exit (0); } char * getreg (p, ar) register char *p; int *ar; { register int r; r = *p++ - '0'; if (r == 1 && isdigit (*p)) r = 10 + *p++ - '0'; *ar = r; return p; } char * getconst (p, ac) register char *p; int *ac; { register int r; if (!isdigit (*p)) return 0; r = *p++ - '0'; while (isdigit (*p)) r = r * 10 + *p++ - '0'; *ac = r; return p; } /* * Try to convert * * addl2 $const,rX \ * ashl $2,rX,rX > moval y+4*const[rX],rX * addl2 $y,rX,rX / * * addl2 $const,rX \ * ashl $2,rX,rX -- moval 4*const[rX],rX * * return 0 iff didn't do anything at all */ try1 (p) register char *p; { register int n, r; int n2, r2; if (*p++ != '$') return 0; n = 0; while (isdigit (*p)) n = n * 10 + *p++ - '0'; if (*p++ != ',' || *p++ != 'r' || !isdigit (*p)) return 0; r = *p++ - '0'; if (r == 1 && isdigit (*p)) r = 10 + *p++ - '0'; if (*p != '\n') { /* shouldn't happen */ fprintf (stderr, "\n? left over: %s\n", p); return 0; } /* * About to be committed... */ if (fgets (inbuf, sizeof inbuf, stdin) == NULL) { e_o_f: inbuf[0] = 0; give_up: printf ("addl2\t$%d,r%d\n", n, r); return 1; } /* * addl2 $c1,rX \ * addl2 $c2,rX -- addl2 $c1+c2,rX */ more_adds: if (inbuf[0] == 'a' && inbuf[1] == 'd' && inbuf[2] == 'd' && inbuf[3] == 'l' && inbuf[4] == '2' && inbuf[5] == '\t' && inbuf[6] == '$') { p = &inbuf[7]; p = getconst (p, &n2); if (p == 0 || *p++ != ',' || *p++ != 'r') goto give_up; p = getreg (p, &r2); if (r2 != r || *p != '\n') goto give_up; n += n2; /* collapse the constants */ if (fgets (inbuf, sizeof inbuf, stdin) == NULL) goto e_o_f; goto more_adds; } if (inbuf[0] != 'a' || inbuf[1] != 's' || inbuf[2] != 'h' || inbuf[3] != 'l' || inbuf[4] != '\t' || inbuf[5] != '$' || inbuf[6] != '2' || inbuf[7] != ',' || inbuf[8] != 'r') goto give_up; p = &inbuf[9]; p = getreg (p, &r2); if (r2 != r || *p++ != ',' || *p++ != 'r') goto give_up; p = getreg (p, &r2); if (r2 != r || *p != '\n') goto give_up; putc ('#', stderr); (void) fflush (stderr); /* * One more trick: if next line is another "addl2 $y,rX", we can * use the instruction "moval $const*4+(y),rX". */ if (fgets (inbuf, sizeof inbuf, stdin) == NULL) { inbuf[0] = 0; just_one: printf ("moval\t%d[r%d],r%d\n", n << 2, r, r); return 1; } if (inbuf[0] == 'a' && inbuf[1] == 'd' && inbuf[2] == 'd' && inbuf[3] == 'l' && inbuf[4] == '2' && inbuf[5] == '\t' && inbuf[6] == '$') { char *end_of_y; p = &inbuf[7]; while (*p != ',') p++; end_of_y = p; p++; if (*p++ != 'r') goto just_one; p = getreg (p, &r2); if (r2 != r || *p != '\n') goto just_one; /* bingo! */ putc ('!', stderr); (void) fflush (stderr); *end_of_y = 0; printf ("moval\t%s+%d[r%d],r%d\n", &inbuf[7], n << 2, r, r); if (fgets (inbuf, sizeof inbuf, stdin) == NULL) inbuf[0] = 0; return 1; } goto just_one; } /* * Try to convert: * * addl2 rX,rX \ * addl2 $y,rX -- movaw y[rX],rX */ try2 (p) register char *p; { int r1, r2; char *end_of_y; if (*p++ != 'r') return 0; p = getreg (p, &r1); if (*p++ != ',' || *p++ != 'r') return 0; p = getreg (p, &r2); if (*p != '\n' || r1 != r2) return 0; if (fgets (inbuf, sizeof inbuf, stdin) == NULL) { inbuf[0] = 0; give_up: printf ("addl2\tr%d,r%d\n", r1, r1); return 1; } if (inbuf[0] != 'a' || inbuf[1] != 'd' || inbuf[2] != 'd' || inbuf[3] != 'l' || inbuf[4] != '2' || inbuf[5] != '\t' || inbuf[6] != '$') goto give_up; p = &inbuf[7]; while (*p != ',') p++; end_of_y = p; p++; if (*p++ != 'r') goto give_up; p = getreg (p, &r2); if (*p != '\n' || r1 != r2) goto give_up; /* got it */ putc ('>', stderr); (void) fflush (stderr); *end_of_y = 0; printf ("movaw\t%s[r%d],r%d\n", &inbuf[7], r1, r1); if (fgets (inbuf, sizeof inbuf, stdin) == NULL) inbuf[0] = 0; return 1; } /* * Try to convert: * * ashl $2,rX,rX \ * addl2 $y,rX -- moval y[rX],rX */ try3 (p) register char *p; { int r1, r2; char *end_of_y; p = getreg (&inbuf[9], &r1); if (*p++ != ',' || *p++ != 'r') return 0; p = getreg (p, &r2); if (*p != '\n' || r1 != r2) return 0; if (fgets (inbuf, sizeof inbuf, stdin) == NULL) { inbuf[0] = 0; give_up: printf ("ashl\t$2,r%d,r%d\n", r1, r1); return 1; } if (inbuf[0] != 'a' || inbuf[1] != 'd' || inbuf[2] != 'd' || inbuf[3] != 'l' || inbuf[4] != '2' || inbuf[5] != '\t' || inbuf[6] != '$') goto give_up; p = &inbuf[7]; while (*p != ',') p++; end_of_y = p; p++; if (*p++ != 'r') goto give_up; p = getreg (p, &r2); if (*p != '\n' || r1 != r2) goto give_up; /* got it */ putc ('-', stderr); (void) fflush (stderr); *end_of_y = 0; printf ("moval\t%s[r%d],r%d\n", &inbuf[7], r1, r1); if (fgets (inbuf, sizeof inbuf, stdin) == NULL) inbuf[0] = 0; return 1; } -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@maryland