optimize.c

来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,806 行 · 第 1/3 页

C
1,806
字号
		next = this_op(s->next);		if (next == 0)			break;		last = next;		if (s->s.code == StmOp &&		    next->s.code == LdmXOp &&		    s->s.k == next->s.k) {			done = 0;			next->s.code = TaxOp;		}		if (s->s.code == LdIOp &&			 next->s.code == TaxOp) {			s->s.code = LdXIOp;			next->s.code = TxaOp;			done = 0;		}		/*		 * This is an ugly special case, but it happens		 * when you say tcp[k] or udp[k] where k is a constant.		 */		if (s->s.code == LdIOp &&		    next->s.code == LdxmsOp) {			struct slist *add, *tax, *ild;			add = this_op(next->next);			if (add == 0 || add->s.code != AddXOp)				break;			tax = this_op(add->next);			if (tax == 0 || tax->s.code != TaxOp)				break;			ild = this_op(tax->next);			if (ild == 0 || 			    (ild->s.code != ILdOp && ild->s.code != ILdHOp &&			     ild->s.code != ILdBOp))				break;			/* 			 * XXX We need to check that X is not			 * subsequently used.  We know we can eliminate the			 * accumaltor modifications since it is defined			 * by the last stmt of this sequence.			 *			 * We want to turn this sequence:			 *			 * (004) ldi     #0x2		{s}			 * (005) ldxms   [14]		{next}			 * (006) addx			{add}			 * (007) tax			{tax}			 * (008) ild     [x+0]		{ild}			 *			 * into this sequence:			 *			 * (004) nop			 * (005) ldxms   [14]			 * (006) nop			 * (007) nop			 * (008) ild     [x+2]			 *			 * The nops get removed later.			 */			ild->s.k += s->s.k;			s->s.code = NopOp;			add->s.code = NopOp;			tax->s.code = NopOp;			done = 0;		}		s = next;	}	/*	 * If we have a subtract to do a comparsion, and the X register	 * is a known constant, we can merge this value into the 	 * comparison.	 */	if (last->s.code == SubXOp && !REGELEM(b->out_use, A_REGNO)) {		val = b->val[X_REGNO];		if (vmap[val].is_const) {			b->s.k += vmap[val].const_val;			last->s.code = NopOp;			done = 0;		}	}	/*	 * Likewise, a constant subtract can be simplified.	 */	else if (last->s.code == SubIOp && !REGELEM(b->out_use, A_REGNO)) {		b->s.k += last->s.k;		last->s.code = NopOp;		done = 0;	}	/*	 * If the accumulator is a known constant, we can compute the	 * comparison result.	 */	val = b->val[A_REGNO];	if (vmap[val].is_const) {		v = vmap[val].const_val;		switch (b->s.code) {		case EQOp:			v = v == b->s.k;			break;		case GTOp:			v = v > b->s.k;			break;		case GEOp:			v = v >= b->s.k;			break;		default:			abort();		}		if (b->jf != b->jt)			done = 0;		if (v)			b->jf = b->jt;		else			b->jt = b->jf;	}}static inline enum bpf_codeopadjust(code, diff)	enum bpf_code code;	int diff;{	return (enum bpf_code)((int)code - diff);}/* * Update compute the symbolic value of expression of 's', and update * anything it defines in the value table 'val'.  If 'alter' is true, * do various optimizations.  This code would be cleaner if symblic * evaluation and code transformations weren't folded together. */static voidopt_stmt(s, val, alter)	struct stmt *s;	long val[];	int alter;{	long v;	switch (s->code) {	case LdOp:	case LdHOp:	case LdBOp:		v = F(s->code, s->k, 0L);		vstore(s, &val[A_REGNO], v, alter);		break;	case ILdOp:	case ILdHOp:	case ILdBOp:		v = val[X_REGNO];		if (alter && vmap[v].is_const) {			s->code = opadjust(s->code, (int)ILdOp - (int)LdOp);			s->k += vmap[v].const_val;			v = F(s->code, s->k, 0L);			done = 0;		}		else			v = F(s->code, s->k, v);		vstore(s, &val[A_REGNO], v, alter);		break;			case LdLenOp:		v = F(s->code, 0L, 0L);		vstore(s, &val[A_REGNO], v, alter);		break;	case LdIOp:		v = K(s->k);		vstore(s, &val[A_REGNO], v, alter);		break;	case LdXIOp:		v = K(s->k);		vstore(s, &val[X_REGNO], v, alter);		break;	case LdxmsOp:		v = F(s->code, s->k, 0L);		vstore(s, &val[X_REGNO], v, alter);		break;	case NegOp:		if (alter && vmap[val[A_REGNO]].is_const) {			s->code = LdIOp;			s->k = -vmap[val[A_REGNO]].const_val;			val[A_REGNO] = K(s->k);		}		else			val[A_REGNO] = F(s->code, val[A_REGNO], 0L);		break;	case AddIOp:	case SubIOp:	case MulIOp:	case DivIOp:	case AndIOp:	case OrIOp:	case LshIOp:	case RshIOp:		if (alter && vmap[val[A_REGNO]].is_const) {			fold_op(s, val[A_REGNO], K(s->k));			val[A_REGNO] = K(s->k);		}		else			val[A_REGNO] = F(s->code, val[A_REGNO], K(s->k));		break;	case AddXOp:	case SubXOp:	case MulXOp:	case DivXOp:	case AndXOp:	case OrXOp:	case LshXOp:	case RshXOp:		if (alter && vmap[val[X_REGNO]].is_const) {			if (vmap[val[A_REGNO]].is_const) {				fold_op(s, val[A_REGNO], val[X_REGNO]);				val[A_REGNO] = K(s->k);			}			else {				s->code = opadjust(s->code, 						   (int)AddXOp - (int)AddIOp);				s->k = vmap[val[X_REGNO]].const_val;				done = 0;				val[A_REGNO] = 					F(s->code, val[A_REGNO], K(s->k));			}			break;		}		/*		 * Check if we're doing something to an accumulator		 * that is 0, and simplify.  This may nnot seem like		 * much of a simplification but it could open up further		 * optimizations.		 * XXX We could also check for mul by 1, and -1, etc.		 */		if (alter && vmap[val[A_REGNO]].is_const		    && vmap[val[A_REGNO]].const_val == 0) {			if (s->code == AddXOp ||			    s->code == OrXOp ||			    s->code == LshXOp ||			    s->code == RshXOp) {				s->code = TxaOp;				vstore(s, &val[A_REGNO], val[X_REGNO], alter);				break;			}			else if (s->code == MulXOp ||				 s->code == DivXOp ||				 s->code == AndXOp) {				s->code = LdIOp;				s->k = 0;				vstore(s, &val[A_REGNO], K(s->k), alter);				break;			}			else if (s->code == NegOp) {				s->code = NopOp;				break;			}		}		val[A_REGNO] = F(s->code, val[A_REGNO], val[X_REGNO]);		break;	case TxaOp:		vstore(s, &val[A_REGNO], val[X_REGNO], alter);		break;	case LdmOp:		v = val[s->k];		if (alter && vmap[v].is_const) {			s->code = LdIOp;			s->k = vmap[v].const_val;			done = 0;		}		vstore(s, &val[A_REGNO], v, alter);		break;			case TaxOp:		vstore(s, &val[X_REGNO], val[A_REGNO], alter);		break;	case LdmXOp:		v = val[s->k];		if (alter && vmap[v].is_const) {			s->code = LdXIOp;			s->k = vmap[v].const_val;			done = 0;		}		vstore(s, &val[X_REGNO], v, alter);		break;	case StmOp:		vstore(s, &val[s->k], val[A_REGNO], alter);		break;	case StmXOp:		vstore(s, &val[s->k], val[X_REGNO], alter);		break;	}}/* * Allocation for blist nodes is done cheaply by mallocing the * max we will need before the optimization passes.  There is a  * linear bound on the number required. */static struct blist *blist_base;static struct blist *next_blist;static voidopt_deadstores(b)	struct block *b;{	struct slist *s;	int i, regno;	struct stmt *last[N_MEMWORDS];	bzero((char *)last, sizeof last);	for (s = b->stmts; s; s = s->next) {		regno = reguse(&s->s);		if (regno >= 0) {			if (regno == AX_REGNO) {				last[X_REGNO] = 0;				last[A_REGNO] = 0;			}			else				last[regno] = 0;		}		regno = regdef(&s->s);		if (regno >= 0) {			if (last[regno]) {				done = 0;				last[regno]->code = NopOp;			}			last[regno] = &s->s;		}	}	for (i = 0; i < N_MEMWORDS; ++i)		if (last[i] && !REGELEM(b->out_use, i) && i != A_REGNO) {			last[i]->code = NopOp;			done = 0;		}}static voidopt_blk(b, do_stmts)	struct block *b;{	struct slist *s;	struct blist *p;	int i;	long aval;	/* 	 * Initialize the register values.	 * If we have no predecessors, everything is undefined.	 * Otherwise, we inherent our values from our predecessors.  	 * If any register has an ambiguous value (i.e. control paths are	 * merging) give it the undefined value of 0.	 */	p = b->pred;	if (p == 0)		bzero((char *)b->val, sizeof(b->val));	else {		bcopy((char *)p->blk->val, (char *)b->val, sizeof(b->val));		while (p = p->next) {			for (i = 0; i < N_MEMWORDS; ++i)				if (b->val[i] != p->blk->val[i])					b->val[i] = 0;		}	}	aval = b->val[A_REGNO];	for (s = b->stmts; s; s = s->next)		opt_stmt(&s->s, b->val, do_stmts);	/*	 * This is a special case: if we don't use anything from this	 * block, and we load the accumulator with value that is 	 * already there, eliminate all the statements.	 */	if (do_stmts && b->out_use == 0 && aval != 0 &&	    b->val[A_REGNO] == aval)		b->stmts = 0;	else {		opt_peep(b);		opt_deadstores(b);	}}/* * Return true if any register that is used on exit from 'succ', has * an exit value that is different from the corresponding exit value * from 'b'. */static int use_conflict(b, succ)	struct block *b, *succ;{	int regno;	regset uset = succ->out_use;	if (uset == 0)		return 0;	for (regno = 0; regno < N_MEMWORDS; ++regno)		if (REGELEM(uset, regno))			if (b->val[regno] != succ->val[regno])				return 1;	return 0;}static voidopt_j(b, which)	struct block *b;	int which;{	int k;	struct block **br;	struct block *target;	struct block *ancestor;	struct block *next;	nodeset dom, closure;	int sense;	/*	 * Don't bother checking if b is a leaf, since we 	 * are never called that way.	 */	if (which) {		br = &b->jt;		target = b->jt;	} else {		br = &b->jf;		target = b->jf;	}	dom = b->dom;	closure = b->closure; top:	/*	 * If we hit a leaf, stop.  Otherwise, 	 * try to move down another level.	 */	if (target->jt == 0) {		*br = target;		return;	}	if (target->jt == target->jf) {		/*		 * Common branch targets can be eliminated, provided		 * there is no a data dependency.		 */		if (!use_conflict(b, target->jt)) {			done = 0;			target = target->jt;			goto top;		} else {			*br = target;			return;		}	}	for (k = 0; k < n_blocks; ++k) {		if (!NS_MEMBER(dom, k))			continue;		ancestor = blocks[k];		if (target->val[A_REGNO] != ancestor->val[A_REGNO])			/*			 * Ignore blocks that do not load the same values.			 */			continue;					if (ancestor == b)			/*			 * The ancestor happens to be the node whose edge			 * is being moved (i.e. there are two consective 			 * nodes that compute the same thing).  The sense			 * of this branch is given by the branch of the			 * node we are optimizing.			 */			sense = which;		else if (NS_MEMBER(closure, ancestor->jt->id))			/*			 * We can reach the node we are optimizing			 * along the true branch of the ancestor.			 * Either we know we came down the true branch,			 * or we might also be able to reach this node			 * from the false branch.  In the latter case,			 * we cannot do anything.			 */			if (NS_MEMBER(closure, ancestor->jf->id))				continue;			else				sense = 1;		else if (NS_MEMBER(closure, ancestor->jf->id))			/*			 * The false branch must have been taken.			 * (We ruled out the true branch above.)			 */			sense = 0;		else			/* XXX			 * If we cannot reach the current node from its			 * dominator, the code is broken.  We can eliminate			 * the test above.			 */			abort();				if (target->s.code == ancestor->s.code) {			if (target->s.code != EQOp)				continue;			if (ancestor->s.k == target->s.k)				/*				 * The operands are the same, so the 				 * result is true if a true branch was				 * taken to get here, otherwise false.				 */				next = sense ? target->jt : target->jf;			else {				if (!sense)					/* 					 * We do not know the outcome					 * if we had a false comparison					 * and the operands are 					 * different.					 */					continue;				/*				 * If this is a true comparison but the				 * operands were different, then the				 * current must be false.				 */				next = target->jf;			}			if (use_conflict(b, next))				/*				 * There is a data dependency between that				 * will be invalidated if we move this edge.				 */				continue;			target = next;			/*			 * Moved a branch, so do another pass.			 */			done = 0;			goto top;		}	}	/*	 * Went through all the dominators of the last block	 * but couldn't move down.	 */	*br = target;}static voidor_pullup(b)	struct block *b;{	int val, at_top;	struct block *pull;	struct block **diffp, **samep;	struct blist *plist;	plist = b->pred;	if (plist == 0)		return;	/*	 * Make sure each predecessor loads the same value.	 */	val = plist->blk->val[A_REGNO];	for (plist = plist->next; plist; plist = plist->next)		if (val != plist->blk->val[A_REGNO])			return;	if (b->pred->blk->jt == b)		diffp = &b->pred->blk->jt;	else		diffp = &b->pred->blk->jf;	at_top = 1;	while (1) {		if (*diffp == 0)			return;		if ((*diffp)->jt != b->jt)			return;		if (!NS_MEMBER((*diffp)->dom, b->id))

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?