File:  [MW Coherent from dump] / coherent / d / bin / cc / c / n2 / optim.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:39 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * C compiler.
 * Jump and shape optimization.
 * Jump to jump, etc.
 * Common sequences.
 * Cross jumping.
 */
#ifdef   vax
#include "INC$LIB:cc2.h"
#else
#include "cc2.h"
#endif

#define	NLHASH	64
#define	LHMASK	077

static	INS	*labhash[NLHASH];

/*
 * Shuffle segments,
 * Move all non 'SHRI' segments to the front,
 * then squash any extra switches out of the stream.
 * This is necessary to make code that is together in
 * memory together in the 'ins' lists.
 */
shuffle()
{
	register INS	*fp, *ip;
	register INS	*niloc;
	INS		*bep, *bfp;
	register int	curseg;

	niloc = &ins;
	for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
		if (ip->i_type != ENTER)
			continue;
		bfp = ip;
		do {
			ip = ip->i_fp;
		} while (ip->i_type != ENTER);
		if (bfp != ins.i_fp) {
			bep = ip;
			ip = bfp->i_bp;
			bfp->i_bp->i_fp = bep->i_fp;
			bep->i_fp->i_bp = bfp->i_bp;
			niloc->i_fp->i_bp = bep;
			bfp->i_bp = niloc;
			bep->i_fp = niloc->i_fp;
			niloc->i_fp = bfp;
			niloc = bep;
		}
	}
	curseg = dotseg;
	for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
		if (ip->i_type != ENTER)
			continue;
		while ((fp=ip->i_fp)!=&ins && fp->i_type==ENTER)
			ip = deleteins(ip, ip->i_fp)->i_fp;
		if (ip->i_seg == curseg) {
			ip = deleteins(ip, ip->i_fp);
			continue;
		}
		curseg = ip->i_seg;
	}
}

/*
 * Delete node ip.
 * Return a pointer to the previous node.
 * Merge any line number references onto ip1.
 */
INS *
deleteins(ip, ip1)
register INS	*ip;
INS		*ip1;
{
	register INS	*bp, *fp;

	mrgdbgt(ip, ip1);
	if ((ip->i_type==JUMP || ip->i_type==LLLINK) && ((fp=ip->i_ip)!=NULL))
		decrefc(fp);
	bp = ip->i_bp;
	fp = ip->i_fp;
	bp->i_fp = fp;
	fp->i_bp = bp;
	free((char *) ip);
	return (bp);
}

/*
 * Decrement the reference count on a label.
 * Delete it if the label is now unreferenced.
 * It is a fatal error to hand this routine a non label.
 */
decrefc(ip)
register INS	*ip;
{
	if (ip->i_type != LLABEL)
		cbotch("decrefc passed non label");
	if (--ip->i_refc == 0)
		deleteins(ip, ip->i_fp);
}

/*
 * Set up label reference counts and delete any unused labels.
 */
labels()
{
	register INS	*fp, *ip, *lp;
	INS		*findlab();
	register int	curseg, i;

	for (i=0; i<NLHASH; ++i)
		labhash[i] = NULL;
	curseg = dotseg;
	for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
		if (ip->i_type == ENTER)
			curseg = ip->i_seg;
		else if (ip->i_type == LLABEL) {
			ip->i_refc = 0;
			/*
			 * Hack the reference count on the
			 * label if it is the label on a switch
			 * table to prevent it from being deleted
			 * by the next bit of code. Kludgy.
			 */
			if (curseg != SCODE)
				++ip->i_refc;
			else if ((fp=ip->i_fp) != &ins) {
				if (fp->i_type == LLLINK)
					++ip->i_refc;
				else if (fp->i_type == CODE
				     &&  fp->i_op >= ZBYTE
				     &&  fp->i_op <= ZGPTR)
					++ip->i_refc;
			}
			labhash[ip->i_labno&LHMASK] = ip;
		}
	}
	for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
		if (ip->i_type!=JUMP && ip->i_type!=LLLINK)
			continue;
		if ((lp=findlab(ip->i_labno)) != NULL) {
			while ((fp=lp->i_fp)!=&ins && fp->i_type==LLABEL)
				lp = fp;
			ip->i_labno = lp->i_labno;
			++lp->i_refc;
		}
		ip->i_ip = lp;
	}
	for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
		if (ip->i_type!=LLABEL || ip->i_refc!=0)
			continue;
		ip = deleteins(ip, ip->i_fp);
		++nlabdel;
	}
}

/*
 * Find label.
 * Quick test using hashtable.
 * Long linear search if that fails.
 */
INS *
findlab(n)
register int	n;
{
	register INS	*lp;

	if ((lp=labhash[n&LHMASK])!=NULL && lp->i_labno==n)
		return (lp);
	for (lp=ins.i_fp; lp!=&ins; lp=lp->i_fp)
		if (lp->i_type==LLABEL && lp->i_labno==n)
			return (lp);
	return (NULL);
}

/*
 * Delete dead code.
 * Dead code begins after an unconditional jump and continues
 * until the next label, segment change or the EPILOG.
 */
deadcode()
{
	register INS	*fp, *ip;
	register int	t;

	for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
		t = ip->i_type;
		if (t == LLLINK) {	/* Switch table */
			while ((fp=ip->i_fp) != &ins && (fp->i_type == LLLINK
			  || (fp->i_type == CODE && opinfo[fp->i_op].op_style
			  == OF_WORD)))
				ip = fp;
		} else if (t != JUMP || ip->i_rel != UNCON)
			continue;
		fp = ip->i_fp;
		while (fp != &ins) {
			t = fp->i_type;
			if (t==LLABEL || t==EPILOG || t==ENTER)
				break;
			fp = deleteins(fp, fp->i_fp)->i_fp;
			++ndead;
			++changes;
		}
	}
}

/*
 * Fix some of the more common funny things
 * associated with jump instructions and labels.
 * There are more things that could be done.
 * These five things should get most of the common things.
 */
fixbr()
{
	register INS	*ip, *ip1, *ip2;
	INS 		*ip3, *ip4;
	int 		t;

again:
	for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
		t = ip->i_type;
		/* Jump to jump. */
		if ((t==JUMP && ischnrel(ip->i_rel)) || t==LLLINK) {
			ip1 = ip->i_ip;
			if (ip1 != NULL) {
				ip2 = ip1;
				for (;;) {
					while (ip2->i_type == LLABEL)
						ip2 = ip2->i_fp;
					if (ip2->i_type!=JUMP
					||  ip2->i_rel!=UNCON)
						break;
					ip3 = ip2->i_ip;
					if (ip3==NULL
					 || ip3==ip1
					 || ip3==ip2->i_bp)
						break;
					ip2 = ip3;
				}
				ip2 = ip2->i_bp;
				if (ip1 != ip2) {
					decrefc(ip1);
					increfc(ip2);
					ip->i_labno = ip2->i_labno;
					ip->i_ip = ip2;
					++nbrbr;
					++changes;
				}
			}
		}
		/* Reversible jump over unconditional jump. */
		if (t==JUMP && isrevrel(ip->i_rel)) {
			ip1 = ip->i_fp;
			if (ip1->i_type==JUMP && ip1->i_rel==UNCON) {
				ip2 = ip1->i_fp;
				if (ip2->i_type==LLABEL && ip->i_ip==ip2) {
					ip1->i_rel = revrel(ip->i_rel);
					deleteins(ip, ip1);
					++ncbrbr;
					++changes;
					goto again;
				}
			}
		}
		/* Jump to next instruction. */
		if (t==JUMP && ip->i_ip==ip->i_fp) {
			deleteins(ip, ip->i_fp);
			++nbrnext;
			++changes;
			goto again;
		}
		/*
 		 * The preceding optimizations do not change the code order,
		 * so they can be executed even if VNOOPT.
		 * The following optimizations do change the code order,
		 * so they are suppressed if VNOOPT.
		 */
		if (isvariant(VNOOPT))
			continue;
		/*
		 * [ip]JUMP L1; [ip1]L2:...; [ip2]L1:...; [ip3]JUMP L2; ...
		 * becomes [ip2]L1:...; [ip1]L2:...; [ip]JUMP L1; ...
		 * Saves a jump in every for loop.
		 */
		if (t==JUMP && ip->i_rel==UNCON) {
			ip1 = ip->i_fp;
			if (ip1!=&ins && ip1->i_type==LLABEL) {
				ip2 = NULL;
				for (ip3=ip1->i_fp; ip3!=&ins; ip3=ip3->i_fp) {
					if (ip3->i_type==LLABEL
					   && ip->i_ip==ip3)
						ip2 = ip3;
					else if (ip2!=NULL
					      && ip3->i_type==JUMP
					      && ip3->i_rel==UNCON
					      && ip3->i_ip==ip1) {
						ip4 = ip2->i_bp;
						ip->i_bp->i_fp = ip2;
						ip3->i_bp->i_fp = ip1;
						ip4->i_fp = ip;
						ip->i_fp = ip3;
						ip2->i_bp = ip->i_bp;
						ip1->i_bp = ip3->i_bp;
						ip->i_bp = ip4;
						ip3->i_bp = ip;
						deleteins(ip3, ip1);
						++nexbr;
						++changes;
						goto again;
					}
				}
			}
		}
		/*
		 * [ip] JUMP L1; <code1>; [ip2] JUMP L2; [ip1] L1: <code2>; [ip3] L2:
		 * becomes [ip1] L1: <code2>; [ip] JUMP L2; <code1>; [ip3] L2:
		 * Saves a jump in every switch and restores natural code order.
		 * <code2> often ends in JUMP or LLLINK, in which case JUMP L2
		 * gets optimized out later.
		 */
		if (t==JUMP && ip->i_rel==UNCON && precedes(ip, ip->i_ip)) {
			ip1 = ip->i_ip;
			ip2 = ip1->i_bp;
			if (ip2->i_type==JUMP && ip2->i_rel==UNCON
			    && precedes(ip1, ip2->i_ip)) {
				ip3 = ip2->i_ip;
				/* Rearrange the code. */
				ip->i_bp->i_fp = ip1;
				ip3->i_bp->i_fp = ip;
				ip2->i_fp = ip3;
				ip1->i_bp = ip->i_bp;
				ip->i_bp = ip3->i_bp;
				ip3->i_bp = ip2;
				/* Change JUMP L1 at ip into JUMP L2. */
				ip->i_ip = ip3;
				ip->i_labno = ip3->i_labno;
				increfc(ip3);
				decrefc(ip1);
				/* Delete the now extraneous JUMP. */
				deleteins(ip2, ip3);
				++nexbr;
				++changes;
				goto again;
			}
		}
	}
}

/*
 * Return true iff ip1 precedes ip2 in the INS node chain.
 */
static
precedes(ip1, ip2)
register INS *ip1, *ip2;
{
	while ((ip1 = ip1->i_fp) != &ins)
		if (ip1 == ip2)
			return(1);
	return(0);
}

/*
 * Increment the reference count on a label.
 * It is a fatal error to hand this routine a non label.
 */
increfc(ip)
register INS	*ip;
{
	if (ip->i_type != LLABEL)
		cbotch("increfc passed non label");
	++ip->i_refc;
}

/*
 * Insert a label.
 * It has been 'increfc'ed.
 * Return pointer to the new label.
 */
INS *
inslab(ip)
register INS	*ip;
{
	register INS	*lp, *bp;

	if (ip->i_type == LLABEL) {
		increfc(ip);
		return (ip);
	}
	lp = (INS *) malloc(sizeof(INS));
	if (lp != NULL) {
		lp->i_type = LLABEL;
		lp->i_labno = newlab();
		lp->i_sp = NULL;
		lp->i_refc = 1;
		bp = ip->i_bp;
		bp->i_fp = lp;
		lp->i_fp = ip;
		ip->i_bp = lp;
		lp->i_bp = bp;
	}
	return (lp);
}

/*
 * Cross jumps.
 * If the same code precedes an unconditional jump and
 * the label to which it jumps, replace the former with
 * a jump to a new local label.
 */
xjumps()
{
	register INS	*ip, *lp;

	for (ip=ins.i_fp; ip!=&ins; ip=ip->i_fp) {
		if (ip->i_type!=JUMP || ip->i_rel!=UNCON
		|| (lp = ip->i_ip)==NULL)
			continue;
		if (!docomseq(lp, ip, &nxjump))
			return;
	}
}

/*
 * Compare two nodes.
 * True return if the same.
 * Never called on strange stuff
 * or labels.
 */
xeq(ip1, ip2)
register INS	*ip1, *ip2;
{
	register int	t;

	if ((t=ip1->i_type) != ip2->i_type)
		return (0);
	if (t==JUMP || t==LLLINK) {
		if (ip1->i_labno != ip2->i_labno)
			return (0);
		if (t==JUMP && ip1->i_rel!=ip2->i_rel)
			return (0);
		return (1);
	}
	if (t != CODE)
		cbotch("xeq");
	if (ip1->i_op != ip2->i_op)
		return (0);
	if (ip1->i_naddr != ip2->i_naddr)
		return (0);
	return (cmpfield(ip1, ip2));
}

/*
 * Detect common sequences before jumps.
 * When found, replace the later with a jump to a new
 * local label preceding the former.
 */
comseq()
{
	register INS	*ip, *xp, *yp;

	for (xp=ins.i_fp; xp!=&ins; xp=xp->i_fp) {
		if (xp->i_type!=JUMP || xp->i_rel!=UNCON)
			continue;
		ip = xp->i_ip;
		if (ip==NULL || ip->i_type != LLABEL)
			continue;
		for (yp=xp->i_fp; yp!=&ins; yp=yp->i_fp) {
			if (yp->i_type==JUMP && yp->i_rel==UNCON
			&&  yp->i_ip==ip) {
				if (!docomseq(xp, yp, &ncomseq))
					return;
			}
		}
	}
}


/*
 * Back up through the code looking for valid cross jumps.
 * When found, insert a new local label before the first
 * and change the second into an unconditional jump to it.
 * Called from xjumps and comseq.
 * Returns 0 if the new node allocation fails.
 */
docomseq(xp, yp, countp)
register INS *xp, *yp;
int *countp;
{
	for (;;) {
		xp = xp->i_bp;
		if (xp==&ins || xp->i_type==LLABEL || xp->i_type==LLLINK)
			break;
		yp = yp->i_bp;
		if (yp==&ins || yp->i_type==LLABEL || yp->i_type==LLLINK
			     || xeq(xp, yp)==0)
			break;
		xp = inslab(xp);
		if (xp == NULL)
			return (0);
		mrgdbgt(yp, xp->i_fp);
		if ((yp->i_type==JUMP || yp->i_type==LLLINK) && yp->i_ip!=NULL)
			decrefc(yp->i_ip);
		yp->i_type = JUMP;
		yp->i_labno = xp->i_labno;
		yp->i_sp = NULL;
		yp->i_ip = xp;
		yp->i_rel = UNCON;
		yp->i_long = 0;
		++*countp;
		++changes;
	}
	return(1);
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.