File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / usr / src / lib / c2 / c22.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:24:19 2019 UTC (6 years, 11 months ago) by root
Branches: bsd, MAIN
CVS tags: v12b, v121, HEAD
Power 6/32 Unix version 1.2b

/*
 * C object code improver-- third part
 */

#include "c2.h"
#include <stdio.h>
#include <ctype.h>

#define NUSE 6
struct node *uses[NUSE]; /* for backwards flow analysis */
char *lastrand; /* last operand of instruction */
char *findcon();

ispow2(n) register long n; {/* -1 -> no; else -> log to base 2 */
	register int log;
	if (n==0 || n&(n-1)) return(-1); log=0;
	for (;;) {n >>= 1; if (n==0) return(log); ++log; if (n== -1) return(log);}
}

equop(p1, p2)
register struct node *p1, *p2;
{
	register char *cp1, *cp2;

	if (p1->op != p2->op || p1->subop != p2->subop)
		return(0);
	if (p1->op>0 && p1->op<MOV)
		return(0);
	if (p1->op==MOVA && p1->labno!=p2->labno) return(0);
	cp1 = p1->code;
	cp2 = p2->code;
	if (cp1==0 && cp2==0)
		return(1);
	if (cp1==0 || cp2==0)
		return(0);
	while (*cp1 == *cp2++)
		if (*cp1++ == 0)
			return(1);
	return(0);
}

delnode(p) register struct node *p; {
	p->back->forw = p->forw;
	p->forw->back = p->back;
}

decref(p)
register struct node *p;
{
	if (p && --p->refc <= 0) {
		nrlab++; nchange++;
		delnode(p);
	}
}

struct node *
nonlab(ap)
struct node *ap;
{
	register struct node *p;

	p = ap;
	while (p && p->op==LABEL)
		p = p->forw;
	return(p);
}

clearuse() {
	register struct node **i;
	for (i=uses+NUSE; i>uses;) *--i=0;
}

clearreg() {
	register char **i;
	for (i=regs+NREG; i>regs;){ **--i=0; **i=0; }
	conloc[0] = 0; ccloc[0] = 0;
}

savereg(ai, s, type)
register char *s;
{
	register char *p, *sp;

	sp = p = regs[ai];
	/* if any indexing, must be parameter or local */
	/* indirection (as in "*-4(fp)") is ok, however */
	*p++ = type;
	while (*p++ = *s)
		if (*s=='[' || *s++=='(' && *s!='f') {*sp = 0; return;}
}

dest(s,type, ccflg)
register char *s;
{
	register int i;

	if ((i = isreg(s)) >= 0) {
		*(short *)(regs[i]) = 0; /* if register destination, that reg is a goner */
	}
	for (i=NREG; --i>=0;)
		if (regs[i][1]=='*' && equstr(s, regs[i]+2))
			*(short *)(regs[i]) = 0; /* previous indirection through destination is invalid */
	while ((i = findrand(s,0)) >= 0) /* previous values of destination are invalid */
		*(short *)(regs[i]) = 0;
	if (!natural(s)) {/* wild store, everything except constants vanishes */
		for (i=NREG; --i>=0;) if (regs[i][1] != '$') *(short *)(regs[i]) = 0;
		conloc[0] = 0; ccloc[0] = 0;
	} else if(ccflg)setcc(s,type); /* natural destinations set condition codes */
}

splitrand(p) struct node *p; {
/* separate operands at commas, set up 'regs' and 'lastrand' */
register char *p1, *p2; register char **preg;

	preg=regs+RT1;
	if (p1=p->code) while (*p1) {
		lastrand=p2= *preg++;
		while (*p1) if (','==(*p2++= *p1++)) {--p2; break;}
		*p2=0;
	}
	while (preg<(regs+RT1+5)) *(*preg++)=0;
}

compat(have, want) {
	register int hsrc, hdst;

	if (0==(want &= 0xF)) return(1); /* anything satisfies a wildcard want */
	hsrc=have&0xF; if (0==(hdst=((have>>4)&0xF)) || hdst>=OP2) hdst=hsrc;
	if (want>=QUAD) return(hdst==want && hsrc==want);
	return(hsrc==want && hdst>=want && hdst<QUAD);
}

equtype(t1,t2) {return(compat(t1,t2) && compat(t2,t1));}

findrand(as, type)
char *as;
{
	register char **i;
	for (i = regs+NREG; --i>=regs;) {
		if (**i && equstr(*i+1, as) && compat(**i,type))
			return(i-regs);
	}
	return(-1);
}

isreg(s)
register char *s;
{
	if (*s++!='r' || !isdigit(*s++)) return(-1);
	if (*s==0) return(*--s-'0');
	if (*(s-1)=='1' && isdigit(*s++) && *s==0) return(10+*--s-'0');
	return(-1);
}

/*
check()
{
	register struct node *p, *lp;

	lp = &first;
	for (p=first.forw; p!=0; p = p->forw) {
		if (p->back != lp)
			abort(-1);
		lp = p;
	}
}
*/

newcode(p) struct node *p; {
	register char *p1,*p2,**preg;

	preg=regs+RT1; p2=line;
	while (*(p1= *preg++)) {while (*p2++= *p1++); *(p2-1)=',';}
	*--p2=0;
	p->code=copy(line);
}

repladdr(p)
struct node *p;
{
	register r;
	register char *p1;
	register char **preg;
	register int nrepl;

	preg=regs+RT1; nrepl=0;
	while (lastrand!=(p1= *preg++))
		if (0<=(r=findrand(p1,p->subop))) {
			*p1++='r'; if (r>9) {*p1++='1'; r -= 10;} *p1++=r+'0'; *p1=0;
			nchange++; nrepl++; nsaddr++;
		}
	if (nrepl) newcode(p);
}

/* conditional branches which are never/always taken */
reduncbr(p)
register struct node *p;
{
	register struct node *p1;
	register char *ap1, *ap2;

	p1 = p->back;
	if (p1->op==CMP) {
		splitrand(p1);
		ap1 = findcon(regs[RT1], p1->subop);
		ap2 = findcon(regs[RT2], p1->subop);
	} else {
		if(!ccloc[0])
			return;
		ap1 = findcon(ccloc+1, ccloc[0]);
		ap2 = "$0";
	}
	switch (compare(p->subop, ap1, ap2)) {
	case 0:		/* branch never taken */
		delnode(p);
		nredunj++;
		nchange++;
		decref(p->ref);
		if(p->forw->op!=CBR && (p1->op==TST || p1->op==CMP)) {
			delnode(p1);
			nrtst++;
		}
		break;
	case 1:		/* branch always taken */
		p->op = JBR;
		p->subop = 0;
		p->pop = 0;
		nchange++;
	}
}

/* a jump to a redundant compare (start of a 'for') */
redunbr(p)
register struct node *p;
{
	register struct node *p1;
	register char *ap1, *ap2;

	if ((p1 = p->ref) == 0)
		return;
	p1 = nonlab(p1);
	if (p1->op==TST || p1->op==CMP)
		splitrand(p1);
	else
		return;
	if (p1->forw->op==CBR) {
		ap1 = findcon(regs[RT1], p1->subop);
		if (p1->op==TST)
			ap2 = "$0";
		else
			ap2 = findcon(regs[RT2], p1->subop);
		p1 = p1->forw;
		if (compare(p1->subop, ap1, ap2) > 0) {
			nredunj++;
			nchange++;
			decref(p->ref);
			p->ref = p1->ref;
			p->labno = p1->labno;
#ifdef COPYCODE
			if (p->labno == 0)
				p->code = p1->code;
			if (p->ref)
#endif
				p->ref->refc++;
		}
	} else if (p1->op==TST && equstr(regs[RT1],ccloc+1) &&
			equtype(ccloc[0],p1->subop)) {
		p1=insertl(p1->forw); decref(p->ref); p->ref=p1; 
		nrtst++; nchange++;
	}
}

char *
findcon(p, type)
	register char *p;
{
	register r;

	if (*p=='$')
		return(p);
	if ((r = isreg(p)) >= 0 && compat(regs[r][0],type))
		return(regs[r]+1);
	if (equstr(p, conloc))
		return(conval+1);
	return(p);
}

/* compare constants: 0 - branch taken; 1 - not taken; -1 - don't know */
compare(op, acp1, acp2)
char *acp1, *acp2;
{
	register char *cp1, *cp2;
	register n1, n2, sign;

	cp1 = acp1;
	cp2 = acp2;
	if (*cp1++ != '$' || *cp2++ != '$')
		return(-1);
	n1 = 0; sign=1; if (*cp1=='-') {++cp1; sign= -1;}
	while (isdigit(*cp1)) {n1 *= 10; n1 += *cp1++ - '0';}
	n1 *= sign;
	n2 = 0; sign=1; if (*cp2=='-') {++cp2; sign= -1;}
	while (isdigit(*cp2)) {n2 *= 10; n2 += *cp2++ - '0';}
	n2 *= sign;
	if (*cp1=='+')
		cp1++;
	if (*cp2=='+')
		cp2++;
	do {
		if (*cp1++ != *cp2)
			return(-1);
	} while (*cp2++);
	switch(op) {

	case JEQ:
		return(n1 == n2);
	case JNE:
		return(n1 != n2);
	case JLE:
		return(n1 <= n2);
	case JGE:
		return(n1 >= n2);
	case JLT:
		return(n1 < n2);
	case JGT:
		return(n1 > n2);
	case JLO:
		return((unsigned)n1 < (unsigned)n2);
	case JHI:
		return((unsigned)n1 > (unsigned)n2);
	case JLOS:
		return((unsigned)n1 <= (unsigned)n2);
	case JHIS:
		return((unsigned)n1 >= (unsigned)n2);
	}
	return(-1);
}

setcon(cv, cl, type)
register char *cv, *cl;
{
	register char *p;

	if (*cv != '$')
		return;
	if (!natural(cl))
		return;
	p = conloc;
	while (*p++ = *cl++);
	p = conval;
	*p++ = type;
	while (*p++ = *cv++);
}

equstr(p1, p2)
register char *p1, *p2;
{
	do {
		if (*p1++ != *p2)
			return(0);
	} while (*p2++);
	return(1);
}

setcc(ap,type)
char *ap;
{
	register char *p, *p1;

	p = ap;
	if (!natural(p)) {
		ccloc[0] = 0;
		return;
	}
	p1 = ccloc;
	*p1++ = type;
	while (*p1++ = *p++);
}

indexa(p) register char *p; {/* 1-> uses [r] addressing mode; 0->doesn't */
	while (*p) if (*p++=='[') return(1);
	return(0);
}

natural(p)
register char *p;
{/* 1->simple local, parameter, global, or register; 0->otherwise */

	if (*p=='*' || *p=='(' || *p=='$')
		return(0);
	while (*p++);
	p--;
	if (*--p==']' || *p==')' && *(p-2)!='f')
		return(0);
	return(1);
}

/*
** Tell if an argument is most likely static.
*/

isstatic(cp)
register char	*cp;
{
	if (*cp == '_' || *cp == 'L' || (*cp++ == 'v' && *cp == '.'))
		return (1);
	return (0);
}

unix.superglobalmegacorp.com

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