[comp.sources.atari.st] v02i097: sozobon1.2 -- Update to Sozobon C compiler part06/09

koreth@panarthea.ebay.sun.com (Steven Grimm) (10/26/89)

Submitted-by: ncar.ucar.edu!dunike!onecom!wldrdg!hans (Johann Ruegg)
Posting-number: Volume 2, Issue 97
Archive-name: sozobon1.2/part06

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 6 (of 9)."
# Contents:  hcc/OUT_ST.C top/BRANCH.C top/PEEP3.C
# Wrapped by koreth@panarthea on Tue Oct 24 18:40:46 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'hcc/OUT_ST.C' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'hcc/OUT_ST.C'\"
else
echo shar: Extracting \"'hcc/OUT_ST.C'\" \(12658 characters\)
sed "s/^X//" >'hcc/OUT_ST.C' <<'END_OF_FILE'
X/* Copyright (c) 1988 by Sozobon, Limited.  Author: Johann Ruegg
X *
X * Permission is granted to anyone to use this software for any purpose
X * on any computer system, and to redistribute it freely, with the
X * following restrictions:
X * 1) No charge may be made other than reasonable charges for reproduction.
X * 2) Modified versions must be clearly marked as such.
X * 3) The authors are not responsible for any harmful consequences
X *    of using this software, even if they result from defects in it.
X *
X *	out.c
X *
X *	Code generation output routines.
X */
X
X#include <stdio.h>
X#include "param.h"
X#include "nodes.h"
X#include "flags.h"
X#include "bstok.h"
X#include "tytok.h"
X#include "gen.h"
X
X#if dLibs
X#include <ctype.h>
X#endif
X
X#if MMCC
Xoverlay "pass2"
X#endif
X
X#if CC68
XFILE *fopen();
X#endif
X
X#if NEEDBUF
Xchar my_obuf[BUFSIZ];
X#endif
X
X#define T_SEG	0
X#define D_SEG	1
X#define B_SEG	2
X
X#define TO_TEXT	to_seg(T_SEG)
X#define TO_DATA	to_seg(D_SEG)
X#define TO_BSS	to_seg(B_SEG)
X
X#define isareg(np)	((np)->g_token == REGVAR && (np)->g_rno >= AREG)
X
Xextern FILE *output;
X
Xstatic int in_seg;
Xstatic int lblnum;
Xstatic int dat_size;
X
Xout_start(outs)
Xchar *outs;
X{
X	register int len;
X	char suff;
X#ifdef MINIX
X	extern char tmpdir[];
X#endif
X	char oname[128];
X
X	len = strlen(outs);
X	if (len >= 2 && outs[len-2] == '.') {
X		suff = outs[len-1];
X		if (suff != 'c' && suff != 'C')
X			fatals("Invalid suffix", outs);
X#ifdef MINIX
X		sprintf(oname, "%s/%s", tmpdir, outs);
X		len = strlen(oname);
X#else
X		strcpy(oname, outs);
X#endif
X		oname[len-1] = 's';
X		output = fopen(oname, "w");
X		if (output == NULL)
X			fatals("Cant open", oname);
X#if NEEDBUF
X		setbuf(output, my_obuf);
X#endif
X	} else
X		output = stdout;
X
X	in_seg = -1;
X	lblnum = 0;
X	dat_size = 0;
X}
X
Xout_end()
X{
X	if (output != stdout)
X		fclose(output);
X}
X
Xstatic char *sg_go[] = {
X	".text",
X	".data",
X	".bss"
X};
X
Xto_text()
X{
X	TO_TEXT;
X}
X
Xto_seg(sg)
X{
X	if (sg == in_seg)
X		return;
X	fprintf(output, "\t%s\n", sg_go[sg]);
X	in_seg = sg;
X}
X
Xo_aln(x)
X{
X	if (x && (dat_size & 1)) {
X		dat_size++;
X		TO_DATA;
X		fprintf(output, "\t.even\n");
X	}
X}
X
Xchar *rnms[] = {
X	"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
X	"a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp",
X};
X
Xchar *regnm(n)
X{
X	return rnms[n];
X}
X
X#define regnm(x)	rnms[x]
X
Xchar *
Xinit_str(n)
X{
X	char *s;
X
X	switch (n) {
X	case 1:
X		s = ".dc.b";	break;
X	case 2:
X		s = ".dc.w";	break;
X	default:
X		s = ".dc.l";	break;
X	}
X	return s;
X}
X
Xtlen(n)
X{
X	switch (n) {
X	case 1:
X		return 'b';
X	case 2:
X		return 'w';
X	default:
X		return 'l';
X	}
X}
X
Xo_vinit(tp, xp)
XNODEP tp, xp;
X{
X	fprintf(output, "\t%s\t", init_str((int)tp->t_size));
X	dat_size += tp->t_size;
X
X	p2_expr(&xp);
X	asn_chk(tp, xp);
X	to_init(xp, tp);
X
X	fputc('\n', output);
X}
X
Xto_init(np, typ)
XNODEP np, typ;
X{
X	NODEP tp;
X
X	tp = allocnode();
X	tp->e_token = TCONV;
X	tp->n_tptr = typ;
X	tp->n_flags |= N_COPYT;
X	tp->n_left = np;
X	tp->e_type = E_UNARY;
X	strcpy(tp->n_name, "i cast");
X
X	genx(tp, FORINIT);
X}
X
Xout_advice(np)
XNODEP np;
X{
X	long size;
X
X	size = np->n_tptr->t_size;
X	if (size == 0)
X		return;
X
X	switch (np->e_sc) {
X	case K_AUTO:
X		fprintf(output, ";var\t%d\t%d\t", (int)size,
X			(int)np->e_offs);
X		break;
X	case K_REGISTER:
X		fprintf(output, ";reg\t%d\t%s\t", (int)size,
X			regnm(np->e_rno));
X		break;
X	default:
X		return;
X	}
X	out_nm(np);
X	fputc('\n', output);
X}
X
Xout_argreg(np)
XNODEP np;
X{
X	fprintf(output, "\tmove.%c\t%d(%s),%s\n",
X		tlen((int)np->n_tptr->t_size), (int)np->e_offs,
X		regnm(FRAMEP), regnm(np->e_rno));
X}
X
Xout_fstart(np)
XNODEP np;
X{
X	extern	int	pflag;
X
X	TO_TEXT;
X	if (np->e_sc != K_STATIC) {
X		fprintf(output, "\t.globl\t");
X		und_nnm(np);
X		fputc('\n', output);
X	}
X	und_nnm(np);
X	fprintf(output, ":\n");	
X
X	if (pflag) {
X		int	tlab = new_lbl();
X
X		TO_BSS;
X		fprintf(output, "L%d:\t.ds.l\t1\n", tlab);
X		TO_TEXT;
X		fprintf(output, "\tmove.l\t#");
X		und_nnm(np);
X		fprintf(output, ",a0\n");
X
X		fprintf(output, "\tmove.l\t#L%d,a1\n", tlab);
X		fprintf(output,	"\tjsr\tmcount\n");
X	}
X}
X
Xstatic char rbuf[30];
X
Xchar *
Xregstr(regs)
X{
X	int lod, hid, loa, hia;
X	register i;
X	char *bp = rbuf;
X
X	lod = 999;
X	hid = -1;
X	for (i=DRV_START; i<=DRV_END; i++)
X		if (regs & (1<<i)) {
X			if (i < lod)  lod = i;
X			if (i > hid)  hid = i;
X		}
X	loa = 999;
X	hia = -1;
X	for (i=ARV_START; i<=ARV_END; i++)
X		if (regs & (1<<i)) {
X			if (i < loa)  loa = i;
X			if (i > hia)  hia = i;
X		}
X	if (lod < 999) {
X		if (lod != hid)
X			sprintf(bp, "%s-%s", rnms[lod], rnms[hid]);
X		else
X			sprintf(bp, "%s", rnms[lod]);
X		if (loa < 999) {
X			bp += strlen(rbuf);
X			*bp++ = '/';
X		}
X	}
X	if (loa < 999) {
X		if (loa != hia)
X			sprintf(bp, "%s-%s", rnms[loa], rnms[hia]);
X		else
X			sprintf(bp, "%s", rnms[loa]);
X	}
X	return rbuf;
X}
X
Xout_fend(regs, lsize)
Xlong lsize;
X{
X	if (lsize < 0x7fff)
X		fprintf(output, "\tlink\t%s,#-%d\n", rnms[FRAMEP], (int)lsize);
X	else
X		fprintf(output, "\tlink\t%s,#0\n\tsub.l\t#%ld,sp\n",
X			rnms[FRAMEP], lsize);
X	if (regs)
X		fprintf(output, "\tmovem.l\t%s,-(sp)\n", regstr(regs));
X}
X
Xout_fret(regs, strl)
X{
X	if (regs)
X		fprintf(output, "\tmovem.l\t(sp)+,%s\n", regstr(regs));
X	if (strl)
X		fprintf(output, "\tmove.l\t#L%d,a0\n", strl);
X	fprintf(output, "\tunlk\t%s\n\trts\n", rnms[FRAMEP]);
X}
X
Xout_fs(strl, size)
Xlong size;
X{
X	TO_BSS;
X	def_lbl(strl);
X	if (size & 1)
X		fprintf(output, "\t.ds.b\t%ld\n", size);
X	else
X		fprintf(output, "\t.ds.w\t%ld\n", size/2);
X}
X
Xout_gv(np, isbss)
Xregister NODEP np;
X{
X	long sz;
X	char c;
X
X	if (np->e_sc == K_STATIC) {
X		np->e_offs = lblnum++;
X	}
X	if (np->e_sc != K_EXTERN) {
X		to_seg(isbss ? B_SEG : D_SEG);
X		if (np->e_sc != K_STATIC) {
X			fprintf(output, "\t.globl\t");
X			out_nm(np);
X			fputc('\n', output);
X		}
X		if (isbss) {
X			if (np->e_sc == K_STATIC) {
X				out_nm(np);
X				sz = np->n_tptr->t_size;
X				c = 'b';
X				if (np->n_tptr->t_aln) {
X					c = 'w';
X					sz /= 2;
X				}
X				fprintf(output, ":\t.ds.%c\t%ld\n", c, sz);
X			} else {
X				fprintf(output, "\t.comm\t");
X				out_nm(np);
X				sz = np->n_tptr->t_size;
X				if (sz & 1) sz++;  /* ALCYON hack */
X				fprintf(output, ",%ld\n", sz);
X			}
X		} else {
X			out_nm(np);
X			fprintf(output, ":\n");
X		}
X	}
X}
X
Xnew_lbl()
X{
X	return lblnum++;
X}
X
Xdef_lbl(l)
X{
X	fprintf(output, "L%d:\n", l);
X}
X
Xout_br(l)
X{
X	if (l < 0)
X		error("bad branch");
X	else
X		fprintf(output, "\tbra\tL%d\n", l);
X}
X
Xstatic char *bnm[] = {
X	"",
X	"beq",
X	"bne",
X	"blt",
X	"bge",
X	"ble",
X	"bgt",
X	"bra",
X	"nop",
X	"bcs",
X	"bcc",
X	"bls",
X	"bhi"
X};
X
Xstatic char *snm[] = {
X	"",
X	"seq",
X	"sne",
X	"slt",
X	"sge",
X	"sle",
X	"sgt",
X	"",
X	"",
X	"scs",
X	"scc",
X	"sls",
X	"shi"
X};
X
Xout_b(key, l)
X{
X	if (key != B_NO)
X		fprintf(output, "\t%s\tL%d\n", bnm[key], l);
X}
X
Xout_bnol(key)
X{
X	fprintf(output, "\t%s\t", bnm[key]);
X}
X
Xout_snol(key)
X{
X	fprintf(output, "\t%s\t", snm[key]);
X}
X
Xout_d0cmp(x)
X{
X	fprintf(output, "\tcmp.w\t#%d,d0\n", x);
X}
X
Xout_d0sub(x)
X{
X	fprintf(output, "\tsub.w\t#%d,d0\n", x);
X}
X
Xout_tlbl(l)
X{
X	fprintf(output, "\t.dc.l\tL%d\n", l);
X}
X
Xout_tsw()
X{
X	fprintf(output, "\text.l\td0\n");
X	fprintf(output, "\tasl.l\t#2,d0\n");
X	fprintf(output, "\tmove.l\t4(pc,d0.l),a0\n");
X	fprintf(output, "\tjmp\t(a0)\n");
X}
X
Xout_nm(np)
XNODEP np;
X{
X	if (np->e_sc == K_STATIC)
X		fprintf(output, "L%d", (int)np->e_offs);
X	else
X		und_nnm(np);
X}
X
Xout_zi(tp)
XNODEP tp;
X{
X	char *s;
X/*
X	switch (tp->t_token) {
X	case K_FLOAT:
X		fprintf(output, "\t.float\t0.0\n");	return;
X	case K_DOUBLE:
X		fprintf(output, "\t.double\t0.0\n");	return;
X	}
X*/
X	dat_size += tp->t_size;
X	s = init_str((int)tp->t_size);
X	fprintf(output, "\t%s\t0\n", s);
X}
X
Xo_nz(sz, aln)
Xlong sz;
X{
X	dat_size += sz;
X	if (aln) {
X		if (sz & 1)
X			fprintf(output, "\t.ds.b\t1\n");
X		sz >>= 1;
X		fprintf(output, "\t.ds.w\t%ld\n", sz);
X	} else {
X		fprintf(output, "\t.ds.b\t%ld\n", sz);
X	}
X}
X
Xdumpstrs(np)
XNODEP np;
X{
X	TO_DATA;
Xmore:
X	if (np == NULL)
X		return;
X	fprintf(output, "L%d:", (int)np->g_offs);
X	out_scon(np);
X	np = np->n_next;
X	goto more;
X}
X
Xint see_esc;
X
Xout_scon(np)
XNODEP np;
X{
X	int len = 0;
X
X	if (np == NULL)
X		return 0;
X	see_esc = 0;
Xmore:
X	if (np->n_name[0]) {
X		fprintf(output, "\t.dc.b\t");
X		len += out_str(np->n_name);
X		putc('\n', output);
X	}
X	np = np->n_nmx;
X	if (np)
X		goto more;
X
X	fprintf(output, "\t.dc.b\t0\n");
X	len++;
X	dat_size += len;
X	return len;
X}
X
Xout_str(s)
Xchar *s;
X{
X	int len;
X	register c;
X
X	len = 0;
X	for ( ; c = *s; s++) {
X		if (see_esc) {	/* allow null */
X			c--;
X			see_esc = 0;
X		} else if (c == 1) {
X			see_esc = 1;
X			continue;
X		}
X		if (len) {
X			if ((len & 15) == 0)
X				fprintf(output, "\n\t.dc.b\t");
X			else
X				putc(',', output);
X		}
X		out_1c(c);
X		len++;
X	}
X	return len;
X}
X
Xout_asm(np)
XNODEP np;
X{
X	putc('\t', output);
Xmore:
X	fprintf(output, "%s", np->n_name);	/* no \0 or \1 please! */
X	np = np->n_nmx;
X	if (np)
X		goto more;
X	putc('\n', output);
X}
X
Xund_nnm(np)
XNODEP np;
X{
X	fputc('_', output);
X	fput_nnm(np);
X}
X
Xout_1c(c)
Xchar c;
X{
X	fprintf(output, "$%x", c & 0xff);
X}
X
Xoutcode(np)
Xregister NODEP np;
X{
X	NODEP tp;
X
X	if (np == NULL) return;
X
X	switch (np->g_type) {
X	case EV_NONE:
X		break;
X	case EV_RL:
X		outcode(np->n_right);
X		outsub(np->g_betw, np);
X		/* fall through */
X	case EV_LEFT:
X		outcode(np->n_left);
X		break;
X	case EV_LR:
X	case EV_LRSEP:
X		outcode(np->n_left);
X		outsub(np->g_betw, np);
X		/* fall through */
X	case EV_RIGHT:
X		outcode(np->n_right);
X		break;
X	default:
X		printf("bad eval %d ", np->g_type);
X	}
X	if (np->n_flags & N_COPYT)	/* g_code is a char * */
X		outsub(np->g_code, np);
X	else				/* g_code is a list of nodes */
X		for (tp=np->g_code; tp != NULL; tp = tp->g_code)
X			outsub(tp->n_name, np);
X}
X
Xoutsub(cp, np)
Xregister char *cp;
Xregister NODEP np;
X{
X	register char c;
X
X	if (cp == NULL) return;
X	while (c = *cp++)
X		if (c == '<')
X			out_let(*cp++, np->n_left);
X		else if (c == '>')
X			out_let(*cp++, np->n_right);
X		else if (c == '\'') {
X			c = *cp++;
X			fputc(c, output);
X		} else if (c == 'L')
X			seelab(*cp++, np);
X		else if (c == 'R')
X			seereg(np, *cp++);
X		else if (c >= 'A' && c <= 'Z') {
X			out_let(c, np);
X		} else
X			fputc(c, output);
X}
X
Xseereg(np, c)
XNODEP np;
X{
X	int i;
X
X	switch (c) {
X	case '0':	i = np->g_rno;  break;
X	case '1':	i = np->g_r1;   break;
X	case '2':	i = np->g_r2;   break;
X	}
X	fprintf(output, regnm(i));	
X}
X
Xout_let(c, np)
Xregister NODEP np;
X{
X	int i;
X
X	switch (c) {
X	case 'A':
X		if (np->g_flags & IMMEDID)
X			fputc('#', output);
X		out_a(np, output);
X		break;
X	case 'E':
X	case 'F':	/* branch if false */
X		i = cctok(np);
X		i = (i&1) ? i+1 : i-1;	/* reverse truth */
X		if (c == 'F')
X			out_bnol(i);
X		else
X			out_snol(i);
X		break;
X	case 'H':	/* last a reg (for struct assign) */
X		fprintf(output, regnm(ARV_START-1));
X		break;
X	case 'K':
X		fprintf(output, "%ld", np->g_bsize);
X		break;
X	case 'N':
X		fprintf(output, "%s", np->n_name);
X		break;
X	case 'O':
X		fprintf(output, "%ld", np->g_offs);
X		break;
X	case 'Q':
X		if (np->g_flags & IMMEDID) {
X			warn("constant test expr");
X			if (np->g_token == ICON && np->g_offs == 0)
X				fprintf(output, "\tor\t#$FF,ccr\n");
X			else
X				fprintf(output, "\tand\t#0,ccr\n");
X			return;
X		}
X		fprintf(output, "\t%s.%c\t", isareg(np) ? "cmp" : "tst",
X			tlen(np->g_sz));
X		if (isareg(np))
X			fprintf(output, "#0,");
X		out_let('A', np);
X		fputc('\n', output);
X		break;
X	case 'S':
X		fputc(tlen(np->g_sz), output);
X		break;
X	case 'T':	/* branch if true */
X		out_bnol(cctok(np));
X		break;
X	case 'U':
X		fputc(np->g_ty == ET_U ? 'u' : 's', output);
X		break;
X	case 'W':	/* field width 1's */
X		fprintf(output, "$%x", ones(np->g_fldw));
X		break;
X	case 'X':	/* ~(W << offset) */
X		fprintf(output, "$%x", (unsigned short)
X				(~(ones(np->g_fldw)<<np->g_fldo)));
X		break;
X	case 'Y':	/* field offset */
X		fprintf(output, "%d", np->g_fldo);
X		break;
X	case 'Z':	/* field offset - 8 */
X		fprintf(output, "%d", np->g_fldo - 8);
X		break;
X	default:
X		printf("bad out_let %c ", c);
X	}
X}
X
Xout_a(np, fd)
Xregister NODEP np;
XFILE *fd;
X{
X	int offs = np->g_offs;
X
X	switch (np->g_token) {
X	case ICON:
X		fprintf(fd, "%ld", np->g_offs);
X		break;
X	case FCON:
X		/* works for ALCYON C */
X		/* otherwise depends on floating internal format */
X		fprintf(fd, "$%lx", np->g_offs);
X		break;
X	case ONAME:
X		while (np->g_flags & (CHILDNM|RCHILDNM)) {
X			np = (np->g_flags & CHILDNM) ? 
X				np->n_left : np->n_right;
X		}
X		qput_nnm(np, fd);
X		if (offs)
X			fprintf(fd, offs > 0 ? "+%d" : "%d", offs);
X		break;
X	case PUSHER:
X		fprintf(fd, "(sp)+");
X		break;
X	case OREG:
X		if (offs)
X			fprintf(fd, "%d", offs);
X		fprintf(fd, "(%s)", regnm(np->g_rno));
X		break;
X	case REGVAR:
X		fprintf(fd, regnm(np->g_rno));
X		break;
X	case ',':
X		fputc(',', fd);		/* for debug */
X		break;
X	default:
X		if (np->g_token >= BR_TOK) {
X			fprintf(fd, "B_%s", bnm[np->g_token - BR_TOK]);
X			break;
X		}
X		printf("? tok %d ", np->g_token);
X	}
X}
X
Xseelab(c, np)
Xchar c;
XNODEP np;
X{
X	c -= '1';
X	fprintf(output, "L%d", (int)np->g_bsize+c);
X}
X
Xones(n)
X{
X	return (1 << n) - 1;
X}
X	
END_OF_FILE
if test 12658 -ne `wc -c <'hcc/OUT_ST.C'`; then
    echo shar: \"'hcc/OUT_ST.C'\" unpacked with wrong size!
fi
# end of 'hcc/OUT_ST.C'
fi
if test -f 'top/BRANCH.C' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'top/BRANCH.C'\"
else
echo shar: Extracting \"'top/BRANCH.C'\" \(12147 characters\)
sed "s/^X//" >'top/BRANCH.C' <<'END_OF_FILE'
X/* Copyright (c) 1988 by Sozobon, Limited.  Author: Tony Andrews
X *
X * Permission is granted to anyone to use this software for any purpose
X * on any computer system, and to redistribute it freely, with the
X * following restrictions:
X * 1) No charge may be made other than reasonable charges for reproduction.
X * 2) Modified versions must be clearly marked as such.
X * 3) The authors are not responsible for any harmful consequences
X *    of using this software, even if they result from defects in it.
X */
X#include "top.h"
X
X#define	TOUCHED(bp)	((bp)->flags & B_TOUCHED)
X
X/*
X * bcomp(bc) - return the complement of the given branch code
X *
X * Used when a branch reversal is needed.
X */
Xstatic	int
Xbcomp(bc)
Xregister int	bc;
X{
X	switch (bc) {
X	case BHI: return BLS;
X	case BLS: return BHI;
X	case BCC: return BCS;
X	case BCS: return BCC;
X	case BNE: return BEQ;
X	case BEQ: return BNE;
X	case BVC: return BVS;
X	case BVS: return BVC;
X	case BPL: return BMI;
X	case BMI: return BPL;
X	case BGE: return BLT;
X	case BLT: return BGE;
X	case BGT: return BLE;
X	case BLE: return BGT;
X	default:
X		fprintf(stderr, "bcomp() - bad branch code %d\n", bc);
X		exit(1);
X	}
X}
X
X/*
X * isbranch(s) - determines if 's' is a branch opcode
X *
X * Returns 1 for branches whose destination is the first operand,
X * and 2 for branches whose dest. is the second.
X */
Xstatic	int
Xisbranch(c)
Xregister int	c;
X{
X	switch (c) {
X	case BRA: case BHI: case BLS: case BCC:
X	case BCS: case BNE: case BEQ: case BVC:
X	case BVS: case BPL: case BMI: case BGE:
X	case BLT: case BGT: case BLE:
X		return 1;
X
X	case DBRA: case DBHI: case DBLS: case DBCC:
X	case DBCS: case DBNE: case DBEQ: case DBMI:
X	case DBGE: case DBLT: case DBGT: case DBLE:
X	case  DBT:
X		return 2;
X
X	default:
X		return 0;
X	}
X}
X
X/*
X * cblock(cp) - return the first block containing some code
X *
X * Starting with 'cp', find a block that has one or more instructions
X * in it. This is useful to collapse multiple null blocks into a single
X * logical point. This happens at points in the generated code where
X * there are multiple labels at the same logical location.
X */
Xstatic	BLOCK *
Xcblock(bp)
Xregister BLOCK	*bp;
X{
X	while (bp->first == NULL && bp->bcond == NULL) {
X		if (bp->bfall == NULL) {
X			fprintf(ofp, "cblock() - error in block %s\n",
X				bp->name);
X			exit(1);
X		}
X		bp = bp->bfall;
X	}
X
X	return bp;
X}
X
X/*
X * bsplit() - split up blocks with branches inside them
X *
X * Look for branch instructions in each block. If somewhere in the middle of
X * the block, split up the block. When done, the blocks are broken down into
X * true basic blocks.
X */
Xstatic	void
Xbsplit(bp)
XBLOCK	*bp;
X{
X	register BLOCK	*cp;	/* the current block */
X	register BLOCK	*np;	/* new block (if needed) */
X	register INST	*ip;	/* current instruction */
X
X	for (cp = bp; cp != NULL ;cp = cp->chain) {
X		for (ip = cp->first; ip != NULL ;ip = ip->next) {
X			if (isbranch(ip->opcode) && ip->next != NULL) {
X				np = mksym(mktmp());
X
X				np->chain = cp->chain;
X				cp->chain = np;
X
X				np->next = cp->next;
X				cp->next = np;
X
X				np->first = ip->next;
X				np->first->prev = NULL;
X				np->last = cp->last;
X
X				cp->last = ip;
X				cp->last->next = NULL;
X
X			} else if (ip->opcode == DC) {
X				BLOCK	*db;
X
X				/*
X				 * If the instruction is part of a branch
X				 * table, both the current block and the
X				 * destination need to be marked as "reached".
X				 */
X				cp->flags |= B_ISREACHED;
X
X				if ((db = getsym(ip->src.astr)) != NULL)
X					db->flags |= B_ISREACHED;
X				else {
X					fprintf(stderr,
X					  "bsplit() - symbol '%s' not found\n",
X					  ip->src.astr);
X					exit(1);
X				}
X			}
X		}
X	}
X}
X
X/*
X * bfix() - fix up the branch pointers
X *
X * Go through each block setting up 'bcond' and 'bfall' properly. If the
X * last instruction in the block is an unconditional branch, remove it
X * and set 'bfall' instead. The idea is that there should be no branch
X * instructions left when we're done. We remember the logical effect of
X * each branch, but reconstruct the branches later in a more optimal way.
X */
Xstatic	void
Xbfix(bp)
Xregister BLOCK	*bp;
X{
X	register BLOCK	*cp;	/* current block */
X	register INST	*ip;	/* current instruction */
X
X	for (cp = bp; cp != NULL ;cp = cp->chain) {
X
X		/* no instructions in the block */
X		if (cp->first == NULL) {
X			cp->bcond = NULL;
X			cp->bfall = cp->next;
X			continue;
X		}
X
X		/* the last instruction is a "return" */
X		if (cp->last->opcode == RTS) {
X			cp->bcond = cp->bfall = NULL;
X			cp->flags |= B_RET;
X			continue;
X		}
X
X		/* the last instruction isn't a branch */
X		if (!isbranch(cp->last->opcode)) {
X			cp->bcond = NULL;
X			cp->bfall = cp->next;
X			continue;
X		}
X
X		/*
X		 * If we reach this point, then we've got a branch we need
X		 * to remove at the end of this block.
X		 */
X		cp->bfall = cp->next;
X		if (isbranch(cp->last->opcode) == 1) {
X			cp->bcode = cp->last->opcode;
X			cp->bcond = getsym(cp->last->src.astr);
X		} else {
X			cp->bcode = -1;
X			cp->bcond = getsym(cp->last->dst.astr);
X		}
X
X		if (cp->bcond == NULL) {
X			fprintf(stderr, "top: branch to bad label '%s'\n",
X				cp->last->src.astr);
X			exit(1);
X		}
X
X		if (cp->bcode < 0)
X			continue;
X
X		for (ip = cp->first; ip != NULL ;ip = ip->next) {
X			if (ip->next == cp->last) {
X				ip->next = NULL;
X				break;
X			}
X		}
X		free(cp->last->src.astr);
X		free(cp->last);
X
X		if (cp->first == cp->last)
X			cp->first = cp->last = NULL;
X		else
X			cp->last = ip;
X		/*
X		 * If the branch was unconditional, we want to represent
X		 * it as a "fall through", so fix the pointers to do that.
X		 */
X		if (cp->bcode == BRA) {
X			s_bdel++;
X			cp->bfall = cp->bcond;
X			cp->bcond = NULL;
X		}
X	}
X}
X
X/*
X * bclean() - remove references to empty blocks
X *
X * Called after bsplit() and bfix().
X */
Xstatic	void
Xbclean(bp)
Xregister BLOCK	*bp;
X{
X	register BLOCK	*cp;
X
X	/*
X	 * First clean up references to empty blocks
X	 */
X	for (cp = bp; cp != NULL ;cp = cp->chain) {
X		if (cp->bcond != NULL)
X			cp->bcond = cblock(cp->bcond);
X		if (cp->bfall != NULL)
X			cp->bfall = cblock(cp->bfall);
X	}
X
X	/*
X	 * Now there are generally blocks that are still linked by the
X	 * 'chain' pointers, but no longer referenced through 'bcond'
X	 * or 'bfall' pointers. They don't actually need to be deleted
X	 * since they won't cause trouble anywhere else.
X	 */
X}
X
X#if 0
X/*
X * reachable(p1, p2) - is p2 reachable (with constraints) from p1
X *
X * Try to reach p2 from p1 by following the 'bfall' pointers, without
X * going through a block that has already been touched. We stop searching
X * after a while since this function doesn't have to be perfect, and we're
X * mainly interested in improving small loops anyway.
X */
Xstatic	bool
Xreachable(p1, p2)
Xregister BLOCK	*p1, *p2;
X{
X	register int	i;
X
X	for (i=0; (i < 40) && (p1 != NULL) ;i++, p1 = p1->bfall) {
X
X		if (TOUCHED(p1))
X			return FALSE;
X
X		if (p1 == p2)
X			return TRUE;
X	}
X	return FALSE;
X}
X#endif
X
X/*
X * bwalk() - recursive walk through the branch graph
X *
X * Starting at the entry point, walk through the block graph placing
X * blocks on the output list. By traversing the "bfall" nodes first
X * we attempt to make blocks that fall through come in order so that
X * branches are minimized.
X *
X * Joe describes this process as "grabbing the tree at the top and
X * shaking".
X *
X * The 'lp' variable below maintains our position in the generated list
X * of blocks.
X */
Xstatic	BLOCK	*lp;	/* pointer to the next block in the file */
X
Xstatic	bwalk(p)
Xregister BLOCK	*p;
X{
X	if (p == NULL || TOUCHED(p))
X		return;
X
X#if 0
X	/*
X	 * The following code still needs some work, so it is disabled
X	 * for now...
X	 */
X	/*
X	 * Check to see if loop rotation is required. We "rotate" the loop
X	 * by skipping the current node and traversing the 'bfall' node,
X	 * and then the 'bcond' node. The function reachable() tells us
X	 * that there's a loop through the 'bfall' nodes allowing us to
X	 * make this optimization. The net result is that we try to move
X	 * conditional branches to the bottoms of loops making the loop
X	 * one instruction shorter. The overall number of branches remains
X	 * the same.
X	 *
X	 * Rather than marking all the nodes again within the function
X	 * "reachable", we just give up after a while if no loop is
X	 * detected. This isn't perfect, but we get the biggest gain in
X	 * small loops, and these will be detected accurately.
X	 */
X	if (do_lrot && p->bcond != NULL && reachable(p->bfall, p)) {
X		s_lrot++;
X		bwalk(p->bfall);
X		bwalk(p->bcond);
X		return;
X	}
X#endif
X
X	p->flags |= B_TOUCHED;
X	lp->next = p;
X	lp = lp->next;
X
X	/*
X	 * We should swap 'bfall' and 'bcond' and alter 'bcode' IF:
X	 *
X	 * 1. Both bfall and bcond are non-null.
X	 * 2. The branch is a simple one (not a DBcc inst.)
X	 * 3. Branch reversals are enabled.
X	 * 4. The block at bfall has already been touched.
X	 * 5. The block at bcond hasn't been touched.
X	 *
X	 * In this case, we can avoid an extra branch if we reverse the
X	 * sense of the conditional branch, and swap the pointers.
X	 */
X	if (p->bfall != NULL && p->bcond != NULL && p->bcode >= 0 &&
X	    do_brev && TOUCHED(p->bfall) && !TOUCHED(p->bcond)) {
X		register BLOCK	*tmp;
X
X		s_brev++;
X	    	tmp = p->bfall;
X	    	p->bfall = p->bcond;
X	    	p->bcond = tmp;
X	    	if ((p->bcode = bcomp(p->bcode)) < 0) {
X	    		fprintf(stderr, "top: internal error in bwalk()\n");
X	    		exit(1);
X	    	}
X	}
X	bwalk(p->bfall);
X	bwalk(p->bcond);
X}
X
X/*
X * bsort() - branch optimization
X *
X * Initialize and terminate the 'next' pointers before and after
X * traversing the branch graph.
X */
Xstatic	void
Xbsort(bp)
Xregister BLOCK	*bp;
X{
X	register BLOCK	*cb;
X
X	lp = bp;
X
X	bwalk(bp);	/* traverse the tree starting at the entry point */
X
X	/*
X	 * Now look for other parts of the tree that don't appear to be
X	 * reachable, but really are. This can happen through the jump
X	 * tables created for switch statements. For each such block,
X	 * walk the subtree starting with it.
X	 */
X	for (cb = bp; cb != NULL ;cb = cb->chain) {
X		if (!TOUCHED(cb) && (cb->flags & B_ISREACHED))
X			bwalk(cb);
X	}
X
X	lp->next = NULL;
X}
X
X/*
X * bsetlab() - figure out which blocks really need labels
X *
X * This can be called AFTER bsort() to mark the blocks that are going to
X * need labels. Anything that we're going to branch to later gets a label.
X */
Xstatic	void
Xbsetlab(bp)
Xregister BLOCK	*bp;
X{
X	for (; bp != NULL ;bp = bp->next) {
X		if (bp->bcond != NULL)
X			cblock(bp->bcond)->flags |= B_LABEL;
X		if (bp->bfall != NULL && bp->bfall != bp->next)
X			cblock(bp->bfall)->flags |= B_LABEL;
X		/*
X		 * If the block is reached via a jump table, then we
X		 * need a label on THIS block directly.
X		 */
X		if (bp->flags & B_ISREACHED)
X			bp->flags |= B_LABEL;
X	}
X}
X
X/*
X * bjoin() - join blocks that always come together
X *
X * If block 'b' always follows block 'a' unconditionally, then move the
X * instructions in 'b' to the end of 'a', and remove 'b'. This allows us
X * to do better peephole optimization since we can optimize sequences that
X * used to span blocks.
X */
Xbjoin(bp)
Xregister BLOCK	*bp;
X{
X	BLOCK	*np, *bnext;
X
X	for (; bp != NULL ;bp = bnext) {
X		bnext = bp->next;
X
X		/*
X		 * First block can't end with a conditional branch.
X		 */
X		if (bp->bcond != NULL)
X			continue;
X
X		/*
X		 * Block must fall through to the next thing in the file.
X		 */
X		if (bp->next == NULL || bp->next != bp->bfall)
X			continue;
X
X		np = bp->next;
X
X		/*
X		 * Second block can't be the destination of a branch.
X		 */
X		if (np->flags & B_LABEL)
X			continue;
X
X		/*
X		 * Join the blocks...
X		 */
X		if (np->first != NULL)
X			np->first->prev = bp->last;
X
X		if (bp->last != NULL)
X			bp->last->next = np->first;
X		else {
X			bp->first = np->first;
X			bp->last = np->last;
X		}
X
X		if (np->flags & B_RET)
X			bp->flags |= B_RET;
X
X		bp->last = np->last;
X		bp->bfall = np->bfall;
X		bp->bcond = np->bcond;
X		bp->bcode = np->bcode;
X		bp->next = np->next;
X
X		/*
X		 * Fix pointers so we don't free the instructions
X		 * twice later on.
X		 */
X		np->first = NULL;
X		np->last = NULL;
X
X		/*
X		 * If we've done a join, then we want to loop again on
X		 * the current block to see if any others can be joined.
X		 */
X		bnext = bp;
X	}
X}
X
X/*
X * bopt() - coordinates branch optimization for the given function
X */
Xvoid
Xbopt(bp)
Xregister BLOCK	*bp;
X{
X	bsplit(bp);
X	bfix(bp);
X	bclean(bp);
X	bsort(bp);
X	bsetlab(bp);
X	bjoin(bp);
X}
END_OF_FILE
if test 12147 -ne `wc -c <'top/BRANCH.C'`; then
    echo shar: \"'top/BRANCH.C'\" unpacked with wrong size!
fi
# end of 'top/BRANCH.C'
fi
if test -f 'top/PEEP3.C' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'top/PEEP3.C'\"
else
echo shar: Extracting \"'top/PEEP3.C'\" \(12352 characters\)
sed "s/^X//" >'top/PEEP3.C' <<'END_OF_FILE'
X/* Copyright (c) 1988 by Sozobon, Limited.  Author: Tony Andrews
X *
X * Permission is granted to anyone to use this software for any purpose
X * on any computer system, and to redistribute it freely, with the
X * following restrictions:
X * 1) No charge may be made other than reasonable charges for reproduction.
X * 2) Modified versions must be clearly marked as such.
X * 3) The authors are not responsible for any harmful consequences
X *    of using this software, even if they result from defects in it.
X */
X
X/*
X * 3-instruction peephole optimizations
X */
X
X#include "top.h"
X
X
X/*
X * ipeep3(bp, ip) - look for 3-instruction optimizations at the given inst.
X */
Xstatic bool
Xipeep3(bp, i1)
Xregister BLOCK	*bp;
Xregister INST	*i1;
X{
X	register INST	*i2 = i1->next;	/* the next instruction */
X	INST	*i3 = i1->next->next;	/* the third instruction */
X
X	register int	op1 = i1->opcode;
X	register int	op2 = i2->opcode;
X	register int	op3 = i3->opcode;
X
X	/*
X	 *	move.l	Am, Dn		=>	lea	N(Am), Ao
X	 *	add.l	#N, Dn
X	 *	move.l	Dn, Ao
X	 *
X	 *	Also, Dn must be dead after the third instruction.
X	 */
X	if ((op1 == MOVE) && (i1->flags & LENL) &&
X	    (i1->src.amode == REG) &&
X	    ISA(i1->src.areg) &&
X	    (i1->dst.amode == REG) &&
X	    ISD(i1->dst.areg)) {
X
X		if (((op2 == ADD) || (op2 == ADDQ)) &&
X		    (i2->flags & LENL) &&
X		    (i2->src.amode == IMM) &&
X		    DOK(i2->src.disp) &&
X		    (i2->dst.amode == REG) &&
X		    (i2->dst.areg == i1->dst.areg)) {
X
X			if ((op3 == MOVE) && (i3->flags & LENL) &&
X			    (i3->src.amode == REG) &&
X			    (i3->src.areg == i1->dst.areg) &&
X			    (i3->dst.amode == REG) &&
X			    ISA(i3->dst.areg) &&
X			    ((i3->live & RM(i3->src.areg)) == 0)) {
X
X				/*
X				 * rewrite i1 and delete i2 and i3
X				 */
X				i1->opcode = LEA;
X				i1->flags = 0;
X				i1->dst = i3->dst;
X
X				i1->src.amode = REGID;
X				i1->src.disp = i2->src.disp;
X
X			    	delinst(bp, i2);
X			    	delinst(bp, i3);
X			    	DBG(printf("%d ", __LINE__))
X			    	return TRUE;
X			}
X		}
X	}
X
X	/*
X	 *	move.l	Dm, Dn		=>	move.l	Dm, Ao
X	 *	add.l	#N, Dn			lea	N(Ao), Ao
X	 *	move.l	Dn, Ao
X	 *
X	 *	Also, Dn must be dead after the third instruction.
X	 */
X	if ((op1 == MOVE) && (i1->flags & LENL) &&
X	    (i1->src.amode == REG) &&
X	    ISD(i1->src.areg) &&
X	    (i1->dst.amode == REG) &&
X	    ISD(i1->dst.areg)) {
X
X		if (((op2 == ADD) || (op2 == ADDQ)) &&
X		    (i2->flags & LENL) &&
X		    (i2->src.amode == IMM) &&
X		    DOK(i2->src.disp) &&
X		    (i2->dst.amode == REG) &&
X		    (i2->dst.areg == i1->dst.areg)) {
X
X			if ((op3 == MOVE) && (i3->flags & LENL) &&
X			    (i3->src.amode == REG) &&
X			    (i3->src.areg == i1->dst.areg) &&
X			    (i3->dst.amode == REG) &&
X			    ISA(i3->dst.areg) &&
X			    ((i3->live & RM(i3->src.areg)) == 0)) {
X
X				/*
X				 * rewrite i1 and i2 and delete i3
X				 */
X				i1->dst.areg = i3->dst.areg;
X				
X				i2->opcode = LEA;
X				i2->flags = 0;
X				i2->dst = i3->dst;
X
X				i2->src.amode = REGID;
X				i2->src.areg = i2->dst.areg;
X				i2->src.disp = i2->src.disp;
X
X			    	delinst(bp, i3);
X			    	DBG(printf("%d ", __LINE__))
X			    	return TRUE;
X			}
X		}
X	}
X
X	/*
X	 *	move.l	Am, Dn		=>	lea	-N(Am), Ao
X	 *	sub.l	#N, Dn
X	 *	move.l	Dn, Ao
X	 *
X	 *	Also, Dn must be dead after the third instruction.
X	 */
X	if ((op1 == MOVE) && (i1->flags & LENL) &&
X	    (i1->src.amode == REG) &&
X	    ISA(i1->src.areg) &&
X	    (i1->dst.amode == REG) &&
X	    ISD(i1->dst.areg)) {
X
X		if (((op2 == SUB) || (op2 == ADDQ)) &&
X		    (i2->flags & LENL) &&
X		    (i2->src.amode == IMM) &&
X		    DOK(i2->src.disp) &&
X		    (i2->dst.amode == REG) &&
X		    (i2->dst.areg == i1->dst.areg)) {
X
X			if ((op3 == MOVE) && (i3->flags & LENL) &&
X			    (i3->src.amode == REG) &&
X			    (i3->src.areg == i1->dst.areg) &&
X			    (i3->dst.amode == REG) &&
X			    ISA(i3->dst.areg) &&
X			    ((i3->live & RM(i3->src.areg)) == 0)) {
X
X				/*
X				 * rewrite i1 and delete i2 and i3
X				 */
X				i1->opcode = LEA;
X				i1->flags = 0;
X				i1->dst = i3->dst;
X
X				i1->src.amode = REGID;
X				i1->src.disp = -i2->src.disp;
X
X			    	delinst(bp, i2);
X			    	delinst(bp, i3);
X			    	DBG(printf("%d ", __LINE__))
X			    	return TRUE;
X			}
X		}
X	}
X
X	/*
X	 *	move.l	Am, Dn		=>	lea	0(Am, Do), Ap
X	 *	add.x	Do, Dn
X	 *	move.l	Dn, Ap
X	 *
X	 *	The second instruction can be either a word or long add.
X	 *	Also, Dn must be dead after the third instruction.
X	 */
X	if ((op1 == MOVE) && (i1->flags & LENL) &&
X	    (i1->src.amode == REG) &&
X	    ISA(i1->src.areg) &&
X	    (i1->dst.amode == REG) &&
X	    ISD(i1->dst.areg)) {
X
X		if (((op2 == ADD) || (op2 == ADDQ)) &&
X		    (i2->flags & (LENL|LENW)) &&
X		    (i2->src.amode == REG) &&
X		    ISD(i2->src.areg) && (i1->dst.areg != i2->src.areg) &&
X		    (i2->dst.amode == REG) &&
X		    (i2->dst.areg == i1->dst.areg)) {
X
X			if ((op3 == MOVE) && (i3->flags & LENL) &&
X			    (i3->src.amode == REG) &&
X			    (i3->src.areg == i1->dst.areg) &&
X			    (i3->dst.amode == REG) &&
X			    ISA(i3->dst.areg) &&
X			    ((i3->live & RM(i3->src.areg)) == 0)) {
X
X				/*
X				 * rewrite i1 and delete i2 and i3
X				 */
X				i1->opcode = LEA;
X				i1->flags = 0;
X				i1->dst = i3->dst;
X
X				i1->src.amode = REGIDX;
X				if (i2->flags & LENL)
X					i1->src.amode |= XLONG;
X				i1->src.ireg = i2->src.areg;
X				i1->src.disp = 0;
X
X			    	delinst(bp, i2);
X			    	delinst(bp, i3);
X			    	DBG(printf("%d ", __LINE__))
X			    	return TRUE;
X			}
X		}
X	}
X
X	/*
X	 *	move.l	X(Am), Dn	=>	move.l	X(Am), Ao
X	 *	add.l	#N, Dn
X	 *	move.l	Dn, Ao			lea	N(Ao), Ao
X	 *
X	 *	Also, Dn must be dead after the third instruction.
X	 */
X	if ((op1 == MOVE) && (i1->flags & LENL) &&
X	    (i1->src.amode == REGI || i1->src.amode == REGID) &&
X	    (i1->dst.amode == REG) &&
X	    ISD(i1->dst.areg)) {
X
X		if (((op2 == ADD) || (op2 == ADDQ)) &&
X		    (i2->flags & LENL) &&
X		    (i2->src.amode == IMM) &&
X		    DOK(i2->src.disp) &&
X		    (i2->dst.amode == REG) &&
X		    (i2->dst.areg == i1->dst.areg)) {
X
X			if ((op3 == MOVE) && (i3->flags & LENL) &&
X			    (i3->src.amode == REG) &&
X			    (i3->src.areg == i1->dst.areg) &&
X			    (i3->dst.amode == REG) &&
X			    ISA(i3->dst.areg) &&
X			    ((i3->live & RM(i3->src.areg)) == 0)) {
X
X				/*
X				 * rewrite i1 and i3 and delete i2
X				 */
X				i1->dst = i3->dst;
X
X				i3->opcode = LEA;
X				i3->flags = 0;
X				i3->src.amode = REGID;
X				i3->src.areg = i3->dst.areg;
X				i3->src.disp = i2->src.disp;
X
X			    	delinst(bp, i2);
X			    	DBG(printf("%d ", __LINE__))
X			    	return TRUE;
X			}
X		}
X	}
X
X	/*
X	 *	move.x	X, Dn		=>	move.x	X, Do
X	 *	ext.y	Dn			ext.y	Do
X	 *	move.y	Dn, Do
X	 *
X	 *	Where Dn is dead.
X	 */
X	if ((op1 == MOVE)&&(op2 == EXT)&&(op3 == MOVE)&&
X	    (i1->dst.amode == REG) && ISD(i1->dst.areg) &&
X	    (i2->src.amode == REG) && (i3->src.amode == REG) &&
X	    (i3->dst.amode == REG) && ISD(i3->dst.areg) &&
X	    (i1->dst.areg == i2->src.areg) && (i1->dst.areg == i3->src.areg) &&
X	    (i2->flags == i3->flags)) {
X
X		if ((i3->live & RM(i3->src.areg)) == 0) {
X			i1->dst.areg = i3->dst.areg;
X			i2->src.areg = i3->dst.areg;
X
X		    	delinst(bp, i3);
X		    	DBG(printf("%d ", __LINE__))
X		    	return TRUE;
X		}
X	}
X
X	/*
X	 *	move.l	X, Dm		=>	move.l	X, An
X	 *	INST				INST
X	 *	move.l	Dm, An			...deleted...
X	 *
X	 *	where INST doesn't modify Dm, and Dm is dead after i3
X	 */
X	if ((op1 == MOVE) && (op3 == MOVE) &&
X	    (i1->dst.amode == REG) && ISD(i1->dst.areg) &&
X	    (i3->src.amode == REG) && (i1->dst.areg == i3->src.areg) &&
X	    (i3->dst.amode == REG) && ISA(i3->dst.areg) &&
X	    !sets(i3, RM(i3->src.areg))) {
X
X		if ((i3->live & i3->src.areg) == 0) {
X			i1->dst.areg = i3->dst.areg;
X			delinst(bp, i3);
X
X		    	DBG(printf("%d ", __LINE__))
X			return TRUE;
X		}
X	}
X
X	/*
X	 *	move.l	Am, An			...deleted...
X	 *	addq.l	#1, Am			...deleted...
X	 *	... stuff ...			... stuff ...
X	 *	???.b	..(An)..	=>	???.b	..(Am)+..
X	 *
X	 *	An must be dead after the last instruction. Nothing in
X	 *	"stuff" can modify Am.
X	 */
X	if ((op1 == MOVE) && (i1->flags & LENL) &&
X	    (i1->src.amode == REG) && ISA(i1->src.areg) &&
X	    (i1->dst.amode == REG) && ISA(i1->dst.areg)) {
X
X		int	rm = i1->src.areg;
X		int	rn = i1->dst.areg;
X
X		if (((op2 == ADD) || (op2 == ADDQ)) &&
X		    (i2->flags & LENL) &&
X		    (i2->src.amode == IMM) && (i2->src.disp == 1) &&
X		    (i2->dst.amode == REG) &&
X		    (i2->dst.areg == rm)) {
X
X			while (i3 != NULL) {
X				if (sets(i3, RM(rm)))
X					goto end7;
X
X				if (i3->src.amode==REGI && i3->src.areg==rn) {
X					if (i3->live & RM(rn))
X						goto end7;
X
X					if ((i3->flags & LENB) == 0)
X						goto end7;
X
X					i3->src.amode |= INC;
X					i3->src.areg = rm;
X
X				    	delinst(bp, i1);
X				    	delinst(bp, i2);
X				    	DBG(printf("%d ", __LINE__))
X				    	return TRUE;
X				}
X				if (i3->dst.amode==REGI && i3->dst.areg==rn) {
X					if (i3->live & RM(rn))
X						goto end7;
X
X					if ((i3->flags & LENB) == 0)
X						goto end7;
X
X					i3->dst.amode |= INC;
X					i3->dst.areg = rm;
X
X				    	delinst(bp, i1);
X				    	delinst(bp, i2);
X				    	DBG(printf("%d ", __LINE__))
X				    	return TRUE;
X				}
X
X				if (i3->next == NULL)
X					goto end7;
X				else
X					i3 = i3->next;
X
X			}
X		}
X	}
Xend7:
X
X	/*
X	 *	move.l	Am, An
X	 *	addq.l	#2, Am
X	 *	... stuff ...
X	 *	???.w	..(An)..	=>	???.w	..(Am)+..
X	 *
X	 *	An must be dead after the last instruction. Nothing in
X	 *	"stuff" can modify Am.
X	 */
X	if ((op1 == MOVE) && (i1->flags & LENL) &&
X	    (i1->src.amode == REG) && ISA(i1->src.areg) &&
X	    (i1->dst.amode == REG) && ISA(i1->dst.areg)) {
X
X		int	rm = i1->src.areg;
X		int	rn = i1->dst.areg;
X
X		if (((op2 == ADD) || (op2 == ADDQ)) &&
X		    (i2->flags & LENL) &&
X		    (i2->src.amode == IMM) && (i2->src.disp == 2) &&
X		    (i2->dst.amode == REG) &&
X		    (i2->dst.areg == rm)) {
X
X			while (i3 != NULL) {
X				if (sets(i3, RM(rm)))
X					goto end9;
X
X				if (i3->src.amode==REGI && i3->src.areg==rn) {
X					if (i3->live & RM(rn))
X						goto end9;
X
X					if ((i3->flags & LENW) == 0)
X						goto end9;
X
X					i3->src.amode |= INC;
X					i3->src.areg = rm;
X
X				    	delinst(bp, i1);
X				    	delinst(bp, i2);
X				    	DBG(printf("%d ", __LINE__))
X				    	return TRUE;
X				}
X				if (i3->dst.amode==REGI && i3->dst.areg==rn) {
X					if (i3->live & RM(rn))
X						goto end9;
X
X					if ((i3->flags & LENW) == 0)
X						goto end9;
X
X					i3->dst.amode |= INC;
X					i3->dst.areg = rm;
X
X				    	delinst(bp, i1);
X				    	delinst(bp, i2);
X				    	DBG(printf("%d ", __LINE__))
X				    	return TRUE;
X				}
X
X				if (i3->next == NULL)
X					goto end9;
X				else
X					i3 = i3->next;
X
X			}
X		}
X	}
Xend9:
X
X	/*
X	 *	move.l	Am, An
X	 *	addq.l	#4, Am
X	 *	... stuff ...
X	 *	???.l	..(An)..	=>	???.l	..(Am)+..
X	 *
X	 *	An must be dead after the last instruction. Nothing in
X	 *	"stuff" can modify Am.
X	 */
X	if ((op1 == MOVE) && (i1->flags & LENL) &&
X	    (i1->src.amode == REG) && ISA(i1->src.areg) &&
X	    (i1->dst.amode == REG) && ISA(i1->dst.areg)) {
X
X		int	rm = i1->src.areg;
X		int	rn = i1->dst.areg;
X
X		if (((op2 == ADD) || (op2 == ADDQ)) &&
X		    (i2->flags & LENL) &&
X		    (i2->src.amode == IMM) && (i2->src.disp == 4) &&
X		    (i2->dst.amode == REG) &&
X		    (i2->dst.areg == rm)) {
X
X			while (i3 != NULL) {
X				if (sets(i3, RM(rm)))
X					goto end11;
X
X				if (i3->src.amode==REGI && i3->src.areg==rn) {
X					if (i3->live & RM(rn))
X						goto end11;
X
X					if ((i3->flags & LENL) == 0)
X						goto end11;
X
X					i3->src.amode |= INC;
X					i3->src.areg = rm;
X
X				    	delinst(bp, i1);
X				    	delinst(bp, i2);
X				    	DBG(printf("%d ", __LINE__))
X				    	return TRUE;
X				}
X				if (i3->dst.amode==REGI && i3->dst.areg==rn) {
X					if (i3->live & RM(rn))
X						goto end11;
X
X					if ((i3->flags & LENL) == 0)
X						goto end11;
X
X					i3->dst.amode |= INC;
X					i3->dst.areg = rm;
X
X				    	delinst(bp, i1);
X				    	delinst(bp, i2);
X				    	DBG(printf("%d ", __LINE__))
X				    	return TRUE;
X				}
X
X				if (i3->next == NULL)
X					goto end11;
X				else
X					i3 = i3->next;
X
X			}
X		}
X	}
Xend11:
X
X	return FALSE;
X}
X
X/*
X * peep3(bp) - scan blocks starting at 'bp'
X */
Xbool
Xpeep3(bp)
Xregister BLOCK	*bp;
X{
X	register INST	*ip;
X	register bool	changed = FALSE;
X
X	DBG(printf("p3: "))
X	for (; bp != NULL ;bp = bp->next) {
X		ip = bp->first;
X		while (ip!=NULL && ip->next != NULL && ip->next->next != NULL) {
X			if (ipeep3(bp, ip)) {
X				s_peep3++;
X				bprep(bp);
X				changed = TRUE;
X				/*
X				 * If we had a match, then any instruction
X				 * could have been deleted, so the safe thing
X				 * to do is to go to the next block.
X				 */
X				break;
X			} else
X				ip = ip->next;
X		}
X	}
X	DBG(printf("\n"); fflush(stdout))
X	return changed;
X}
END_OF_FILE
if test 12352 -ne `wc -c <'top/PEEP3.C'`; then
    echo shar: \"'top/PEEP3.C'\" unpacked with wrong size!
fi
# end of 'top/PEEP3.C'
fi
echo shar: End of archive 6 \(of 9\).
cp /dev/null ark6isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 9 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0