[net.lang.pascal] Otherwise in Berkeley Pascal.

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