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