📄 optimize.c
字号:
/* * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996 * 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 intermediate representation. */#ifndef lintstatic const char rcsid[] _U_ = "@(#) $Header: /tcpdump/master/libpcap/optimize.c,v 1.85 2005/04/04 08:42:18 guy Exp $ (LBL)";#endif#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdio.h>#include <stdlib.h>#include <memory.h>#include <string.h>#include <errno.h>#include "pcap-int.h"#include "gencode.h"#ifdef HAVE_OS_PROTO_H#include "os-proto.h"#endif#ifdef BDEBUGextern int dflag;#endif#if defined(MSDOS) && !defined(__DJGPP__)extern int _w32_ffs (int mask);#define ffs _w32_ffs#endif/* * Represents a deleted instruction. */#define NOP -1/* * Register numbers for use-def values. * 0 through BPF_MEMWORDS-1 represent the corresponding scratch memory * location. A_ATOM is the accumulator and X_ATOM is the index * register. */#define A_ATOM BPF_MEMWORDS#define X_ATOM (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_ATOM N_ATOMS/* * 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(struct block *);static void opt_cleanup(void);static void make_marks(struct block *);static void mark_code(struct block *);static void intern_blocks(struct block *);static int eq_slist(struct slist *, struct slist *);static void find_levels_r(struct block *);static void find_levels(struct block *);static void find_dom(struct block *);static void propedom(struct edge *);static void find_edom(struct block *);static void find_closure(struct block *);static int atomuse(struct stmt *);static int atomdef(struct stmt *);static void compute_local_ud(struct block *);static void find_ud(struct block *);static void init_val(void);static int F(int, int, int);static inline void vstore(struct stmt *, int *, int, int);static void opt_blk(struct block *, int);static int use_conflict(struct block *, struct block *);static void opt_j(struct edge *);static void or_pullup(struct block *);static void and_pullup(struct block *);static void opt_blks(struct block *, int);static inline void link_inedge(struct edge *, struct block *);static void find_inedges(struct block *);static void opt_root(struct block **);static void opt_loop(struct block *, int);static void fold_op(struct stmt *, int, int);static inline struct slist *this_op(struct slist *);static void opt_not(struct block *);static void opt_peep(struct block *);static void opt_stmt(struct stmt *, int[], int);static void deadstmt(struct stmt *, struct stmt *[]);static void opt_deadstores(struct block *);static struct block *fold_edge(struct block *, struct edge *);static inline int eq_blk(struct block *, struct block *);static int slength(struct slist *);static int count_blocks(struct block *);static void number_blks_r(struct block *);static int count_stmts(struct block *);static int convert_code_r(struct block *);#ifdef BDEBUGstatic void opt_dump(struct block *);#endifstatic int n_blocks;struct block **blocks;static int n_edges;struct edge **edges;/* * A bit vector set representation of the dominators. * We round up the set size to the next power of two. */static int nodewords;static int edgewords;struct block **levels;bpf_u_int32 *space;#define BITS_PER_WORD (8*sizeof(bpf_u_int32))/* * True if a is in uset {p} */#define SET_MEMBER(p, a) \((p)[(unsigned)(a) / BITS_PER_WORD] & (1 << ((unsigned)(a) % BITS_PER_WORD)))/* * Add 'a' to uset p. */#define SET_INSERT(p, a) \(p)[(unsigned)(a) / BITS_PER_WORD] |= (1 << ((unsigned)(a) % BITS_PER_WORD))/* * Delete 'a' from uset p. */#define SET_DELETE(p, a) \(p)[(unsigned)(a) / BITS_PER_WORD] &= ~(1 << ((unsigned)(a) % BITS_PER_WORD))/* * a := a intersect b */#define SET_INTERSECT(a, b, n)\{\ register bpf_u_int32 *_x = a, *_y = b;\ register int _n = n;\ while (--_n >= 0) *_x++ &= *_y++;\}/* * a := a - b */#define SET_SUBTRACT(a, b, n)\{\ register bpf_u_int32 *_x = a, *_y = b;\ register int _n = n;\ while (--_n >= 0) *_x++ &=~ *_y++;\}/* * a := a union b */#define SET_UNION(a, b, n)\{\ register bpf_u_int32 *_x = a, *_y = b;\ register int _n = n;\ while (--_n >= 0) *_x++ |= *_y++;\}static uset all_dom_sets;static uset all_closure_sets;static uset all_edge_sets;#ifndef MAX#define MAX(a,b) ((a)>(b)?(a):(b))#endifstatic voidfind_levels_r(b) struct block *b;{ int level; if (isMarked(b)) return; Mark(b); b->link = 0; if (JT(b)) { find_levels_r(JT(b)); find_levels_r(JF(b)); level = MAX(JT(b)->level, JF(b)->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;{ memset((char *)levels, 0, 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; bpf_u_int32 *x; /* * Initialize sets to contain all nodes. */ x = all_dom_sets; i = n_blocks * nodewords; while (--i >= 0) *x++ = ~0; /* Root starts off empty. */ for (i = nodewords; --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) { SET_INSERT(b->dom, b->id); if (JT(b) == 0) continue; SET_INTERSECT(JT(b)->dom, b->dom, nodewords); SET_INTERSECT(JF(b)->dom, b->dom, nodewords); } }}static voidpropedom(ep) struct edge *ep;{ SET_INSERT(ep->edom, ep->id); if (ep->succ) { SET_INTERSECT(ep->succ->et.edom, ep->edom, edgewords); SET_INTERSECT(ep->succ->ef.edom, ep->edom, edgewords); }}/* * Compute edge dominators. * Assumes graph has been leveled and predecessors established. */static voidfind_edom(root) struct block *root;{ int i; uset x; struct block *b; x = all_edge_sets; for (i = n_edges * edgewords; --i >= 0; ) x[i] = ~0; /* root->level is the highest level no found. */ memset(root->et.edom, 0, edgewords * sizeof(*(uset)0)); memset(root->ef.edom, 0, edgewords * sizeof(*(uset)0)); for (i = root->level; i >= 0; --i) { for (b = levels[i]; b != 0; b = b->link) { propedom(&b->et); propedom(&b->ef); } }}/* * 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. */ memset((char *)all_closure_sets, 0, n_blocks * nodewords * 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) { SET_INSERT(b->closure, b->id); if (JT(b) == 0) continue; SET_UNION(JT(b)->closure, b->closure, nodewords); SET_UNION(JF(b)->closure, b->closure, nodewords); } }}/* * Return the register number that is used by s. If A and X are both * used, return AX_ATOM. If no register is used, return -1. * * The implementation should probably change to an array access. */static intatomuse(s) struct stmt *s;{ register int c = s->code; if (c == NOP) return -1; switch (BPF_CLASS(c)) { case BPF_RET: return (BPF_RVAL(c) == BPF_A) ? A_ATOM : (BPF_RVAL(c) == BPF_X) ? X_ATOM : -1; case BPF_LD: case BPF_LDX: return (BPF_MODE(c) == BPF_IND) ? X_ATOM : (BPF_MODE(c) == BPF_MEM) ? s->k : -1; case BPF_ST: return A_ATOM; case BPF_STX: return X_ATOM; case BPF_JMP: case BPF_ALU: if (BPF_SRC(c) == BPF_X) return AX_ATOM; return A_ATOM; case BPF_MISC: return BPF_MISCOP(c) == BPF_TXA ? X_ATOM : A_ATOM; } 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. */static intatomdef(s) struct stmt *s;{ if (s->code == NOP) return -1; switch (BPF_CLASS(s->code)) { case BPF_LD: case BPF_ALU: return A_ATOM; case BPF_LDX: return X_ATOM; case BPF_ST: case BPF_STX: return s->k; case BPF_MISC: return BPF_MISCOP(s->code) == BPF_TAX ? X_ATOM : A_ATOM; } return -1;}/* * Compute the sets of registers used, defined, and killed by 'b'. * * "Used" means that a statement in 'b' uses the register before any * statement in 'b' defines it, i.e. it uses the value left in * that register by a predecessor block of this block. * "Defined" means that a statement in 'b' defines it. * "Killed" means that a statement in 'b' defines it before any * statement in 'b' uses it, i.e. it kills the value left in that * register by a predecessor block of this block. */static voidcompute_local_ud(b) struct block *b;{ struct slist *s; atomset def = 0, use = 0, kill = 0; int atom; for (s = b->stmts; s; s = s->next) { if (s->s.code == NOP) continue; atom = atomuse(&s->s); if (atom >= 0) { if (atom == AX_ATOM) { if (!ATOMELEM(def, X_ATOM)) use |= ATOMMASK(X_ATOM); if (!ATOMELEM(def, A_ATOM)) use |= ATOMMASK(A_ATOM); } else if (atom < N_ATOMS) { if (!ATOMELEM(def, atom)) use |= ATOMMASK(atom); } else abort(); } atom = atomdef(&s->s); if (atom >= 0) { if (!ATOMELEM(use, atom)) kill |= ATOMMASK(atom); def |= ATOMMASK(atom); } } if (BPF_CLASS(b->s.code) == BPF_JMP) { /* * XXX - what about RET? */ atom = atomuse(&b->s); if (atom >= 0) { if (atom == AX_ATOM) { if (!ATOMELEM(def, X_ATOM)) use |= ATOMMASK(X_ATOM); if (!ATOMELEM(def, A_ATOM)) use |= ATOMMASK(A_ATOM); } else if (atom < N_ATOMS) { if (!ATOMELEM(def, atom)) use |= ATOMMASK(atom); } else abort(); } } b->def = def; b->kill = kill; 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 |= JT(p)->in_use | JF(p)->in_use; p->in_use |= p->out_use &~ p->kill; } }}/* * These data structures are 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 { int code; int v0, v1; int val; struct valnode *next;};#define MODULUS 213static struct valnode *hashtbl[MODULUS];static int curval;static int maxval;/* Integer constants mapped with the load immediate opcode. */#define K(i) F(BPF_LD|BPF_IMM|BPF_W, i, 0L)struct vmapinfo { int is_const; bpf_int32 const_val;};struct vmapinfo *vmap;struct valnode *vnode_base;struct valnode *next_vnode;static voidinit_val(){ curval = 0; next_vnode = vnode_base; memset((char *)vmap, 0, maxval * sizeof(*vmap)); memset((char *)hashtbl, 0, sizeof hashtbl);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -