optimize.c

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

C
1,806
字号
/* * Copyright (c) 1988-1990 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that: (1) source code distributions * retain the above copyright notice and this paragraph in its entirety, (2) * distributions including binary code include the above copyright notice and * this paragraph in its entirety in the documentation or other materials * provided with the distribution, and (3) all advertising materials mentioning * features or use of this software display the following acknowledgement: * ``This product includes software developed by the University of California, * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of * the University nor the names of its contributors may be used to endorse * or promote products derived from this software without specific prior * written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * *  Optimization module for tcpdump intermeddiate representation. * * SCCSID: @(#)optimize.c	4.2	ULTRIX	1/25/91 * Based on: * rcsid[] = "@(#) $Header: optimize.c,v 1.25 91/01/07 16:03:21 mccanne Exp $ (LBL)" */#include <stdio.h>#include <sys/types.h>#include <sys/time.h>#include <net/bpf.h>#include "interface.h"#include "gencode.h"#define A_REGNO BPF_MEMWORDS#define X_REGNO (BPF_MEMWORDS+1)/* * This define is used to represent *both* the accumulator and * x register in use-def computations. * Currently, the use-def code assumes only one definition per instruction. */#define AX_REGNO N_MEMWORDS/* * A flag to indicate that further optimization is needed. * Iterative passes are continued until a given pass yields no  * branch movement. */static int done;/* * A block is marked if only if its mark equals the current mark. * Rather than traverse the code array, marking each item, 'cur_mark' is * incremented.  This automatically makes each element unmarked. */static int cur_mark;#define isMarked(p) ((p)->mark == cur_mark)#define unMarkAll() cur_mark += 1#define Mark(p) ((p)->mark = cur_mark)static void opt_init();static void opt_cleanup();static void make_marks();static void mark_code();static void intern_blocks();static int eq_slist();static int n_blocks;struct block **blocks;/* * A bit vector set representation of the dominators.   * We round up the set size to the next power of two.   */static int ns_nwords;struct block **levels;u_long *space;#define BITS_PER_WORD (8*sizeof(u_long))/* * True if a is in nodeset {p} */#define NS_MEMBER(p, a) \((p)[(unsigned)(a) / BITS_PER_WORD] & (1 << ((unsigned)(a) % BITS_PER_WORD)))/* * Add 'a' to nodeset p. */#define NS_INSERT(p, a) \(p)[(unsigned)(a) / BITS_PER_WORD] |= (1 << ((unsigned)(a) % BITS_PER_WORD))/* * Delete 'a' from nodeset p. */#define NS_DELETE(p, a) \(p)[(unsigned)(a) / BITS_PER_WORD] &= ~(1 << ((unsigned)(a) % BITS_PER_WORD))/* * a := a intersect b */#define NS_INTERSECT(a, b)\{\	u_long *_x = a, *_y = b;\	int _n = ns_nwords;\	while (--_n >= 0) *_x++ &= *_y++;\}/* * a := a union b */#define NS_UNION(a, b)\{\	u_long *_x = a, *_y = b;\	int _n = ns_nwords;\	while (--_n >= 0) *_x++ |= *_y++;\}static nodeset all_dom_sets;static nodeset all_closure_sets;#define MAX(a,b) ((a)>(b)?(a):(b))static voidfind_levels_r(b)	struct block *b;{	int level;	if (isMarked(b))		return;	Mark(b);	b->link = 0;	if (b->jt) {		find_levels_r(b->jt);		find_levels_r(b->jf);		level = MAX(b->jt->level, b->jf->level) + 1;	} else		level = 0;	b->level = level;	b->link = levels[level];	levels[level] = b;}/* * Level graph.  The levels go from 0 at the leaves to  * N_LEVELS at the root.  The levels[] array points to the * first node of the level list, whose elements are linked * with the 'link' field of the struct block. */static voidfind_levels(root)	struct block *root;{	bzero((char *)levels, n_blocks * sizeof(*levels));	unMarkAll();	find_levels_r(root);}/*  * Find dominator relationships. * Assumes graph has been leveled. */static voidfind_dom(root)	struct block *root;{	int i;	struct block *b;	u_long *x;	/*	 * Initialize sets to contain all nodes.	 */	x = all_dom_sets;	i = n_blocks * ns_nwords;	while (--i >= 0)		*x++ = ~0;	/* Root starts off empty. */	for (i = ns_nwords; --i >= 0;)		root->dom[i] = 0;		/* root->level is the highest level no found. */	for (i = root->level; i >= 0; --i) {		for (b = levels[i]; b; b = b->link) {			NS_INSERT(b->dom, b->id);			if (b->jt == 0)				continue;			NS_INTERSECT(b->jt->dom, b->dom);			NS_INTERSECT(b->jf->dom, b->dom);		}	}}/*  * Find the backwards transitive closure of the flow graph.  These sets * are backwards in the sense that we find the set of nodes that reach * a given node, not the set of nodes that can be reached by a node. * * Assumes graph has been leveled. */static voidfind_closure(root)	struct block *root;{	int i;	struct block *b;	/*	 * Initialize sets to contain no nodes.	 */	bzero((char *)all_closure_sets, 	      n_blocks * ns_nwords * sizeof(*all_closure_sets));		/* root->level is the highest level no found. */	for (i = root->level; i >= 0; --i) {		for (b = levels[i]; b; b = b->link) {			NS_INSERT(b->closure, b->id);			if (b->jt == 0)				continue;			NS_UNION(b->jt->closure, b->closure);			NS_UNION(b->jf->closure, b->closure);		}	}}/*  * Return the register number that is used by s.  If A and X are both * used, return AX_REGNO.  If no register is used, return -1. *  * The implementation should probably change to an array access, and * and a special case for trx and tra. */static intreguse(s)	struct stmt *s;{	switch (s->code) {	case GEOp:	case GTOp:	case EQOp:	case AddIOp:	case SubIOp:	case MulIOp:	case DivIOp:	case AndIOp:	case OrIOp:	case LshIOp:	case RshIOp:	case NegOp:	case TaxOp:	case StmOp:	case RetAOp:		return A_REGNO;	case LdOp:	case LdHOp:	case LdBOp:	case LdLenOp:	case LdIOp:	case LdXIOp:	case LdxmsOp:	case NopOp:	case RetOp:		return -1;	case ILdOp:	case ILdHOp:	case ILdBOp:	case TxaOp:	case StmXOp:		return X_REGNO;	case AddXOp:	case SubXOp:	case MulXOp:	case DivXOp:	case AndXOp:	case OrXOp:	case LshXOp:	case RshXOp:		return AX_REGNO;	case LdmOp:	case LdmXOp:		return s->k;	}	abort();	/* NOTREACHED */}/*  * Return the register number that is defined by 's'.  We assume that * a single stmt cannot define more than one register.  If no register * is defined, return -1. * * The implementation should probably change to an array access, and * and a special case for txr and tar. */static intregdef(s)	struct stmt *s;{	switch (s->code) {	case GEOp:	case GTOp:	case EQOp:	case NopOp:	case RetOp:	case RetAOp:		return -1;	case LdOp:	case LdHOp:	case LdBOp:	case LdLenOp:	case LdIOp:	case ILdOp:	case ILdHOp:	case ILdBOp:	case AddIOp:	case SubIOp:	case MulIOp:	case DivIOp:	case AndIOp:	case OrIOp:	case LshIOp:	case RshIOp:	case NegOp:	case AddXOp:	case SubXOp:	case MulXOp:	case DivXOp:	case AndXOp:	case OrXOp:	case LshXOp:	case RshXOp:	case TxaOp:	case LdmOp:		return A_REGNO;	case LdXIOp:	case LdxmsOp:	case TaxOp:	case LdmXOp:		return X_REGNO;	case StmOp:	case StmXOp:		return s->k;	}	abort();	/* NOTREACHED */}static voidcompute_local_ud(b)	struct block *b;{	struct slist *s;	regset def = 0, use = 0;	int regno;	for (s = b->stmts; s; s = s->next) {		regno = reguse(&s->s);		if (regno >= 0) {			if (regno == AX_REGNO) {				if (!REGELEM(def, X_REGNO))					use |= REGMASK(X_REGNO);				if (!REGELEM(def, A_REGNO))					use |= REGMASK(A_REGNO);			}			else if (regno < N_MEMWORDS) {				if (!REGELEM(def, regno))					use |= REGMASK(regno);			}			else				abort();		}		regno = regdef(&s->s);		if (regno >= 0)			def |= REGMASK(regno);	}	if (!REGELEM(def, A_REGNO) && BPF_ISJUMP(b->s.code))		use |= REGMASK(A_REGNO);			b->def = def;	b->in_use = use;}/* * Assume graph is already leveled. */static voidfind_ud(root)	struct block *root;{	int i, maxlevel;	struct block *p;	/*	 * root->level is the highest level no found;	 * count down from there.	 */	maxlevel = root->level;	for (i = maxlevel; i >= 0; --i)		for (p = levels[i]; p; p = p->link) {			compute_local_ud(p);			p->out_use = 0;		}	for (i = 1; i <= maxlevel; ++i) {		for (p = levels[i]; p; p = p->link) {			p->out_use |= p->jt->in_use | p->jf->in_use;			p->in_use |= p->out_use;		}	}}/*  * These data structures used in a Cocke and Shwarz style * value numbering scheme.  Since the flowgraph is acyclic, * exit values can be propagated from a node's predecessors * provided it is uniquely defined. */struct valnode {	enum bpf_code code;	long v0, v1;	long val;	struct valnode *next;};	#define MODULUS 213static struct valnode *hashtbl[MODULUS];static int curval;static int maxval;/* Integer constants mapped with the LdIOp opcode. */#define K(i) F(LdIOp, i, 0L)struct vmapinfo {	int is_const;	long const_val;};struct vmapinfo *vmap;struct valnode *vnode_base;struct valnode *next_vnode;static voidinit_val(){	curval = 0;	next_vnode = vnode_base;	bzero((char *)vmap, maxval * sizeof(*vmap));	bzero((char *)hashtbl, sizeof hashtbl);}/* Because we really don't have an IR, this stuff is a little messy. */static longF(code, v0, v1)	enum bpf_code code;	long v0, v1;{	u_int hash;	int val;	struct valnode *p;	hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8);	hash %= MODULUS;	for (p = hashtbl[hash]; p; p = p->next)		if (p->code == code && p->v0 == v0 && p->v1 == v1)			return p->val;	val = ++curval;	if (code == LdIOp || code == LdXIOp) {		vmap[val].const_val = v0;		vmap[val].is_const = 1;	}	p = next_vnode++;	p->val = val;	p->code = code;	p->v0 = v0;	p->v1 = v1;	p->next = hashtbl[hash];	hashtbl[hash] = p;	return val;}static inline voidvstore(s, valp, newval, alter)	struct stmt *s;	long *valp;	long newval;	int alter;{	if (alter && *valp == newval)		s->code = NopOp;	else		*valp = newval;}static voidfold_op(s, v0, v1)	struct stmt *s;	long v0, v1;{	long a, b;	a = vmap[v0].const_val;	b = vmap[v1].const_val;	switch (s->code) {	case AddIOp:	case AddXOp:		a += b;		break;	case SubIOp:	case SubXOp:		a -= b;		break;	case MulIOp:	case MulXOp:		a *= b;		break;	case DivIOp:	case DivXOp:		if (b == 0)			error("division by zero");		a /= b;		break;	case AndIOp:	case AndXOp:		a &= b;		break;	case OrIOp:	case OrXOp:		a |= b;		break;	case LshIOp:	case LshXOp:		a <<= b;		break;	case RshIOp:	case RshXOp:		a >>= b;		break;	case NegOp:		a = -a;		break;	default:		abort();	}	s->k = a;	s->code = LdIOp;	done = 0;}static inline struct slist *this_op(s)	struct slist *s;{	while (s != 0 && s->s.code == NopOp)		s = s->next;	return s;}static voidopt_peep(b)	struct block *b;{	struct slist *s;	struct slist *next, *last;	int val;	long v;	s = b->stmts;	if (s == 0)		return;	last = s;	while (1) {		s = this_op(s);		if (s == 0)			break;

⌨️ 快捷键说明

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