176404edcSAsim Jamshed /*
276404edcSAsim Jamshed * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996
376404edcSAsim Jamshed * The Regents of the University of California. All rights reserved.
476404edcSAsim Jamshed *
576404edcSAsim Jamshed * Some portions Copyright (C) 2010-2013 Sourcefire, Inc.
676404edcSAsim Jamshed *
776404edcSAsim Jamshed * Redistribution and use in source and binary forms, with or without
876404edcSAsim Jamshed * modification, are permitted provided that: (1) source code distributions
976404edcSAsim Jamshed * retain the above copyright notice and this paragraph in its entirety, (2)
1076404edcSAsim Jamshed * distributions including binary code include the above copyright notice and
1176404edcSAsim Jamshed * this paragraph in its entirety in the documentation or other materials
1276404edcSAsim Jamshed * provided with the distribution, and (3) all advertising materials mentioning
1376404edcSAsim Jamshed * features or use of this software display the following acknowledgement:
1476404edcSAsim Jamshed * ``This product includes software developed by the University of California,
1576404edcSAsim Jamshed * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1676404edcSAsim Jamshed * the University nor the names of its contributors may be used to endorse
1776404edcSAsim Jamshed * or promote products derived from this software without specific prior
1876404edcSAsim Jamshed * written permission.
1976404edcSAsim Jamshed * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
2076404edcSAsim Jamshed * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
2176404edcSAsim Jamshed * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2276404edcSAsim Jamshed *
2376404edcSAsim Jamshed * Optimization module for tcpdump intermediate representation.
2476404edcSAsim Jamshed */
2576404edcSAsim Jamshed #ifndef lint
26*8a8b63d6SAsim Jamshed static const char __attribute__ ((unused)) rcsid[] =
2776404edcSAsim Jamshed "@(#) $Header: /usr/cvsroot/sfeng/ims/src/libraries/daq/daq/sfbpf/sf_optimize.c,v 1.3 2013/06/28 14:57:30 rcombs Exp $ (LBL)";
2876404edcSAsim Jamshed #endif
2976404edcSAsim Jamshed
3076404edcSAsim Jamshed #ifdef HAVE_CONFIG_H
3176404edcSAsim Jamshed #include "config.h"
3276404edcSAsim Jamshed #endif
3376404edcSAsim Jamshed
3476404edcSAsim Jamshed #ifdef WIN32
3576404edcSAsim Jamshed #include "win32-stdinc.h"
3676404edcSAsim Jamshed #else /* WIN32 */
3776404edcSAsim Jamshed #if HAVE_INTTYPES_H
3876404edcSAsim Jamshed #include <inttypes.h>
3976404edcSAsim Jamshed #elif HAVE_STDINT_H
4076404edcSAsim Jamshed #include <stdint.h>
4176404edcSAsim Jamshed #endif
4276404edcSAsim Jamshed #ifdef HAVE_SYS_BITYPES_H
4376404edcSAsim Jamshed #include <sys/bitypes.h>
4476404edcSAsim Jamshed #endif
4576404edcSAsim Jamshed #include <sys/types.h>
4676404edcSAsim Jamshed #endif /* WIN32 */
4776404edcSAsim Jamshed
4876404edcSAsim Jamshed #include <stdio.h>
4976404edcSAsim Jamshed #include <stdlib.h>
5076404edcSAsim Jamshed #include <memory.h>
5176404edcSAsim Jamshed #include <string.h>
5276404edcSAsim Jamshed
5376404edcSAsim Jamshed #include <errno.h>
5476404edcSAsim Jamshed
5576404edcSAsim Jamshed #include "sfbpf-int.h"
5676404edcSAsim Jamshed
5776404edcSAsim Jamshed #include "gencode.h"
5876404edcSAsim Jamshed
5976404edcSAsim Jamshed #ifdef BDEBUG
6076404edcSAsim Jamshed extern int dflag;
6176404edcSAsim Jamshed #endif
6276404edcSAsim Jamshed
6376404edcSAsim Jamshed #if defined(MSDOS) && !defined(__DJGPP__)
6476404edcSAsim Jamshed extern int _w32_ffs(int mask);
6576404edcSAsim Jamshed #define ffs _w32_ffs
6676404edcSAsim Jamshed #endif
6776404edcSAsim Jamshed
6876404edcSAsim Jamshed #if defined(WIN32) && defined (_MSC_VER)
6976404edcSAsim Jamshed int ffs(int mask);
7076404edcSAsim Jamshed #endif
7176404edcSAsim Jamshed
7276404edcSAsim Jamshed /*
7376404edcSAsim Jamshed * Represents a deleted instruction.
7476404edcSAsim Jamshed */
7576404edcSAsim Jamshed #define NOP -1
7676404edcSAsim Jamshed
7776404edcSAsim Jamshed /*
7876404edcSAsim Jamshed * Register numbers for use-def values.
7976404edcSAsim Jamshed * 0 through BPF_MEMWORDS-1 represent the corresponding scratch memory
8076404edcSAsim Jamshed * location. A_ATOM is the accumulator and X_ATOM is the index
8176404edcSAsim Jamshed * register.
8276404edcSAsim Jamshed */
8376404edcSAsim Jamshed #define A_ATOM BPF_MEMWORDS
8476404edcSAsim Jamshed #define X_ATOM (BPF_MEMWORDS+1)
8576404edcSAsim Jamshed
8676404edcSAsim Jamshed /*
8776404edcSAsim Jamshed * This define is used to represent *both* the accumulator and
8876404edcSAsim Jamshed * x register in use-def computations.
8976404edcSAsim Jamshed * Currently, the use-def code assumes only one definition per instruction.
9076404edcSAsim Jamshed */
9176404edcSAsim Jamshed #define AX_ATOM N_ATOMS
9276404edcSAsim Jamshed
9376404edcSAsim Jamshed /*
9476404edcSAsim Jamshed * A flag to indicate that further optimization is needed.
9576404edcSAsim Jamshed * Iterative passes are continued until a given pass yields no
9676404edcSAsim Jamshed * branch movement.
9776404edcSAsim Jamshed */
9876404edcSAsim Jamshed static __thread int done;
9976404edcSAsim Jamshed
10076404edcSAsim Jamshed /*
10176404edcSAsim Jamshed * A block is marked if only if its mark equals the current mark.
10276404edcSAsim Jamshed * Rather than traverse the code array, marking each item, 'cur_mark' is
10376404edcSAsim Jamshed * incremented. This automatically makes each element unmarked.
10476404edcSAsim Jamshed */
10576404edcSAsim Jamshed static __thread int cur_mark;
10676404edcSAsim Jamshed #define isMarked(p) ((p)->mark == cur_mark)
10776404edcSAsim Jamshed #define unMarkAll() cur_mark += 1
10876404edcSAsim Jamshed #define Mark(p) ((p)->mark = cur_mark)
10976404edcSAsim Jamshed
11076404edcSAsim Jamshed static void opt_init(struct block *);
11176404edcSAsim Jamshed static void opt_cleanup(void);
11276404edcSAsim Jamshed
11376404edcSAsim Jamshed static void make_marks(struct block *);
11476404edcSAsim Jamshed static void mark_code(struct block *);
11576404edcSAsim Jamshed
11676404edcSAsim Jamshed static void intern_blocks(struct block *);
11776404edcSAsim Jamshed
11876404edcSAsim Jamshed static int eq_slist(struct slist *, struct slist *);
11976404edcSAsim Jamshed
12076404edcSAsim Jamshed static void find_levels_r(struct block *);
12176404edcSAsim Jamshed
12276404edcSAsim Jamshed static void find_levels(struct block *);
12376404edcSAsim Jamshed static void find_dom(struct block *);
12476404edcSAsim Jamshed static void propedom(struct edge *);
12576404edcSAsim Jamshed static void find_edom(struct block *);
12676404edcSAsim Jamshed static void find_closure(struct block *);
12776404edcSAsim Jamshed static int atomuse(struct stmt *);
12876404edcSAsim Jamshed static int atomdef(struct stmt *);
12976404edcSAsim Jamshed static void compute_local_ud(struct block *);
13076404edcSAsim Jamshed static void find_ud(struct block *);
13176404edcSAsim Jamshed static void init_val(void);
13276404edcSAsim Jamshed static int F(int, int, int);
13376404edcSAsim Jamshed static inline void vstore(struct stmt *, int *, int, int);
13476404edcSAsim Jamshed static void opt_blk(struct block *, int);
13576404edcSAsim Jamshed static int use_conflict(struct block *, struct block *);
13676404edcSAsim Jamshed static void opt_j(struct edge *);
13776404edcSAsim Jamshed static void or_pullup(struct block *);
13876404edcSAsim Jamshed static void and_pullup(struct block *);
13976404edcSAsim Jamshed static void opt_blks(struct block *, int);
14076404edcSAsim Jamshed static inline void link_inedge(struct edge *, struct block *);
14176404edcSAsim Jamshed static void find_inedges(struct block *);
14276404edcSAsim Jamshed static void opt_root(struct block **);
14376404edcSAsim Jamshed static void opt_loop(struct block *, int);
14476404edcSAsim Jamshed static void fold_op(struct stmt *, int, int);
14576404edcSAsim Jamshed static inline struct slist *this_op(struct slist *);
14676404edcSAsim Jamshed static void opt_not(struct block *);
14776404edcSAsim Jamshed static void opt_peep(struct block *);
14876404edcSAsim Jamshed static void opt_stmt(struct stmt *, int[], int);
14976404edcSAsim Jamshed static void deadstmt(struct stmt *, struct stmt *[]);
15076404edcSAsim Jamshed static void opt_deadstores(struct block *);
15176404edcSAsim Jamshed static struct block *fold_edge(struct block *, struct edge *);
15276404edcSAsim Jamshed static inline int eq_blk(struct block *, struct block *);
15376404edcSAsim Jamshed static int slength(struct slist *);
15476404edcSAsim Jamshed static int count_blocks(struct block *);
15576404edcSAsim Jamshed static void number_blks_r(struct block *);
15676404edcSAsim Jamshed static int count_stmts(struct block *);
15776404edcSAsim Jamshed static int convert_code_r(struct block *);
15876404edcSAsim Jamshed #ifdef BDEBUG
15976404edcSAsim Jamshed static void opt_dump(struct block *);
16076404edcSAsim Jamshed #endif
16176404edcSAsim Jamshed
16276404edcSAsim Jamshed static __thread int n_blocks;
16376404edcSAsim Jamshed __thread struct block **blocks;
16476404edcSAsim Jamshed static __thread int n_edges;
16576404edcSAsim Jamshed __thread struct edge **edges;
16676404edcSAsim Jamshed
16776404edcSAsim Jamshed /*
16876404edcSAsim Jamshed * A bit vector set representation of the dominators.
16976404edcSAsim Jamshed * We round up the set size to the next power of two.
17076404edcSAsim Jamshed */
17176404edcSAsim Jamshed static __thread int nodewords;
17276404edcSAsim Jamshed static __thread int edgewords;
17376404edcSAsim Jamshed __thread struct block **levels;
17476404edcSAsim Jamshed __thread bpf_u_int32 *space;
17576404edcSAsim Jamshed #define BITS_PER_WORD (8*sizeof(bpf_u_int32))
17676404edcSAsim Jamshed /*
17776404edcSAsim Jamshed * True if a is in uset {p}
17876404edcSAsim Jamshed */
17976404edcSAsim Jamshed #define SET_MEMBER(p, a) \
18076404edcSAsim Jamshed ((p)[(unsigned)(a) / BITS_PER_WORD] & (1 << ((unsigned)(a) % BITS_PER_WORD)))
18176404edcSAsim Jamshed
18276404edcSAsim Jamshed /*
18376404edcSAsim Jamshed * Add 'a' to uset p.
18476404edcSAsim Jamshed */
18576404edcSAsim Jamshed #define SET_INSERT(p, a) \
18676404edcSAsim Jamshed (p)[(unsigned)(a) / BITS_PER_WORD] |= (1 << ((unsigned)(a) % BITS_PER_WORD))
18776404edcSAsim Jamshed
18876404edcSAsim Jamshed /*
18976404edcSAsim Jamshed * Delete 'a' from uset p.
19076404edcSAsim Jamshed */
19176404edcSAsim Jamshed #define SET_DELETE(p, a) \
19276404edcSAsim Jamshed (p)[(unsigned)(a) / BITS_PER_WORD] &= ~(1 << ((unsigned)(a) % BITS_PER_WORD))
19376404edcSAsim Jamshed
19476404edcSAsim Jamshed /*
19576404edcSAsim Jamshed * a := a intersect b
19676404edcSAsim Jamshed */
19776404edcSAsim Jamshed #define SET_INTERSECT(a, b, n)\
19876404edcSAsim Jamshed {\
19976404edcSAsim Jamshed register bpf_u_int32 *_x = a, *_y = b;\
20076404edcSAsim Jamshed register int _n = n;\
20176404edcSAsim Jamshed while (--_n >= 0) *_x++ &= *_y++;\
20276404edcSAsim Jamshed }
20376404edcSAsim Jamshed
20476404edcSAsim Jamshed /*
20576404edcSAsim Jamshed * a := a - b
20676404edcSAsim Jamshed */
20776404edcSAsim Jamshed #define SET_SUBTRACT(a, b, n)\
20876404edcSAsim Jamshed {\
20976404edcSAsim Jamshed register bpf_u_int32 *_x = a, *_y = b;\
21076404edcSAsim Jamshed register int _n = n;\
21176404edcSAsim Jamshed while (--_n >= 0) *_x++ &=~ *_y++;\
21276404edcSAsim Jamshed }
21376404edcSAsim Jamshed
21476404edcSAsim Jamshed /*
21576404edcSAsim Jamshed * a := a union b
21676404edcSAsim Jamshed */
21776404edcSAsim Jamshed #define SET_UNION(a, b, n)\
21876404edcSAsim Jamshed {\
21976404edcSAsim Jamshed register bpf_u_int32 *_x = a, *_y = b;\
22076404edcSAsim Jamshed register int _n = n;\
22176404edcSAsim Jamshed while (--_n >= 0) *_x++ |= *_y++;\
22276404edcSAsim Jamshed }
22376404edcSAsim Jamshed
22476404edcSAsim Jamshed static __thread uset all_dom_sets;
22576404edcSAsim Jamshed static __thread uset all_closure_sets;
22676404edcSAsim Jamshed static __thread uset all_edge_sets;
22776404edcSAsim Jamshed
22876404edcSAsim Jamshed #ifndef MAX
22976404edcSAsim Jamshed #define MAX(a,b) ((a)>(b)?(a):(b))
23076404edcSAsim Jamshed #endif
23176404edcSAsim Jamshed
find_levels_r(b)23276404edcSAsim Jamshed static void find_levels_r(b)
23376404edcSAsim Jamshed struct block *b;
23476404edcSAsim Jamshed {
23576404edcSAsim Jamshed int level;
23676404edcSAsim Jamshed
23776404edcSAsim Jamshed if (isMarked(b))
23876404edcSAsim Jamshed return;
23976404edcSAsim Jamshed
24076404edcSAsim Jamshed Mark(b);
24176404edcSAsim Jamshed b->link = 0;
24276404edcSAsim Jamshed
24376404edcSAsim Jamshed if (JT(b))
24476404edcSAsim Jamshed {
24576404edcSAsim Jamshed find_levels_r(JT(b));
24676404edcSAsim Jamshed find_levels_r(JF(b));
24776404edcSAsim Jamshed level = MAX(JT(b)->level, JF(b)->level) + 1;
24876404edcSAsim Jamshed }
24976404edcSAsim Jamshed else
25076404edcSAsim Jamshed level = 0;
25176404edcSAsim Jamshed b->level = level;
25276404edcSAsim Jamshed b->link = levels[level];
25376404edcSAsim Jamshed levels[level] = b;
25476404edcSAsim Jamshed }
25576404edcSAsim Jamshed
25676404edcSAsim Jamshed /*
25776404edcSAsim Jamshed * Level graph. The levels go from 0 at the leaves to
25876404edcSAsim Jamshed * N_LEVELS at the root. The levels[] array points to the
25976404edcSAsim Jamshed * first node of the level list, whose elements are linked
26076404edcSAsim Jamshed * with the 'link' field of the struct block.
26176404edcSAsim Jamshed */
find_levels(root)26276404edcSAsim Jamshed static void find_levels(root)
26376404edcSAsim Jamshed struct block *root;
26476404edcSAsim Jamshed {
26576404edcSAsim Jamshed memset((char *) levels, 0, n_blocks * sizeof(*levels));
26676404edcSAsim Jamshed unMarkAll();
26776404edcSAsim Jamshed find_levels_r(root);
26876404edcSAsim Jamshed }
26976404edcSAsim Jamshed
27076404edcSAsim Jamshed /*
27176404edcSAsim Jamshed * Find dominator relationships.
27276404edcSAsim Jamshed * Assumes graph has been leveled.
27376404edcSAsim Jamshed */
find_dom(root)27476404edcSAsim Jamshed static void find_dom(root)
27576404edcSAsim Jamshed struct block *root;
27676404edcSAsim Jamshed {
27776404edcSAsim Jamshed int i;
27876404edcSAsim Jamshed struct block *b;
27976404edcSAsim Jamshed bpf_u_int32 *x;
28076404edcSAsim Jamshed
28176404edcSAsim Jamshed /*
28276404edcSAsim Jamshed * Initialize sets to contain all nodes.
28376404edcSAsim Jamshed */
28476404edcSAsim Jamshed x = all_dom_sets;
28576404edcSAsim Jamshed i = n_blocks * nodewords;
28676404edcSAsim Jamshed while (--i >= 0)
28776404edcSAsim Jamshed *x++ = ~0;
28876404edcSAsim Jamshed /* Root starts off empty. */
28976404edcSAsim Jamshed for (i = nodewords; --i >= 0;)
29076404edcSAsim Jamshed root->dom[i] = 0;
29176404edcSAsim Jamshed
29276404edcSAsim Jamshed /* root->level is the highest level no found. */
29376404edcSAsim Jamshed for (i = root->level; i >= 0; --i)
29476404edcSAsim Jamshed {
29576404edcSAsim Jamshed for (b = levels[i]; b; b = b->link)
29676404edcSAsim Jamshed {
29776404edcSAsim Jamshed SET_INSERT(b->dom, b->id);
29876404edcSAsim Jamshed if (JT(b) == 0)
29976404edcSAsim Jamshed continue;
30076404edcSAsim Jamshed SET_INTERSECT(JT(b)->dom, b->dom, nodewords);
30176404edcSAsim Jamshed SET_INTERSECT(JF(b)->dom, b->dom, nodewords);
30276404edcSAsim Jamshed }
30376404edcSAsim Jamshed }
30476404edcSAsim Jamshed }
30576404edcSAsim Jamshed
propedom(ep)30676404edcSAsim Jamshed static void propedom(ep)
30776404edcSAsim Jamshed struct edge *ep;
30876404edcSAsim Jamshed {
30976404edcSAsim Jamshed SET_INSERT(ep->edom, ep->id);
31076404edcSAsim Jamshed if (ep->succ)
31176404edcSAsim Jamshed {
31276404edcSAsim Jamshed SET_INTERSECT(ep->succ->et.edom, ep->edom, edgewords);
31376404edcSAsim Jamshed SET_INTERSECT(ep->succ->ef.edom, ep->edom, edgewords);
31476404edcSAsim Jamshed }
31576404edcSAsim Jamshed }
31676404edcSAsim Jamshed
31776404edcSAsim Jamshed /*
31876404edcSAsim Jamshed * Compute edge dominators.
31976404edcSAsim Jamshed * Assumes graph has been leveled and predecessors established.
32076404edcSAsim Jamshed */
find_edom(root)32176404edcSAsim Jamshed static void find_edom(root)
32276404edcSAsim Jamshed struct block *root;
32376404edcSAsim Jamshed {
32476404edcSAsim Jamshed int i;
32576404edcSAsim Jamshed uset x;
32676404edcSAsim Jamshed struct block *b;
32776404edcSAsim Jamshed
32876404edcSAsim Jamshed x = all_edge_sets;
32976404edcSAsim Jamshed for (i = n_edges * edgewords; --i >= 0;)
33076404edcSAsim Jamshed x[i] = ~0;
33176404edcSAsim Jamshed
33276404edcSAsim Jamshed /* root->level is the highest level no found. */
33376404edcSAsim Jamshed memset(root->et.edom, 0, edgewords * sizeof(*(uset) 0));
33476404edcSAsim Jamshed memset(root->ef.edom, 0, edgewords * sizeof(*(uset) 0));
33576404edcSAsim Jamshed for (i = root->level; i >= 0; --i)
33676404edcSAsim Jamshed {
33776404edcSAsim Jamshed for (b = levels[i]; b != 0; b = b->link)
33876404edcSAsim Jamshed {
33976404edcSAsim Jamshed propedom(&b->et);
34076404edcSAsim Jamshed propedom(&b->ef);
34176404edcSAsim Jamshed }
34276404edcSAsim Jamshed }
34376404edcSAsim Jamshed }
34476404edcSAsim Jamshed
34576404edcSAsim Jamshed /*
34676404edcSAsim Jamshed * Find the backwards transitive closure of the flow graph. These sets
34776404edcSAsim Jamshed * are backwards in the sense that we find the set of nodes that reach
34876404edcSAsim Jamshed * a given node, not the set of nodes that can be reached by a node.
34976404edcSAsim Jamshed *
35076404edcSAsim Jamshed * Assumes graph has been leveled.
35176404edcSAsim Jamshed */
find_closure(root)35276404edcSAsim Jamshed static void find_closure(root)
35376404edcSAsim Jamshed struct block *root;
35476404edcSAsim Jamshed {
35576404edcSAsim Jamshed int i;
35676404edcSAsim Jamshed struct block *b;
35776404edcSAsim Jamshed
35876404edcSAsim Jamshed /*
35976404edcSAsim Jamshed * Initialize sets to contain no nodes.
36076404edcSAsim Jamshed */
36176404edcSAsim Jamshed memset((char *) all_closure_sets, 0, n_blocks * nodewords * sizeof(*all_closure_sets));
36276404edcSAsim Jamshed
36376404edcSAsim Jamshed /* root->level is the highest level no found. */
36476404edcSAsim Jamshed for (i = root->level; i >= 0; --i)
36576404edcSAsim Jamshed {
36676404edcSAsim Jamshed for (b = levels[i]; b; b = b->link)
36776404edcSAsim Jamshed {
36876404edcSAsim Jamshed SET_INSERT(b->closure, b->id);
36976404edcSAsim Jamshed if (JT(b) == 0)
37076404edcSAsim Jamshed continue;
37176404edcSAsim Jamshed SET_UNION(JT(b)->closure, b->closure, nodewords);
37276404edcSAsim Jamshed SET_UNION(JF(b)->closure, b->closure, nodewords);
37376404edcSAsim Jamshed }
37476404edcSAsim Jamshed }
37576404edcSAsim Jamshed }
37676404edcSAsim Jamshed
37776404edcSAsim Jamshed /*
37876404edcSAsim Jamshed * Return the register number that is used by s. If A and X are both
37976404edcSAsim Jamshed * used, return AX_ATOM. If no register is used, return -1.
38076404edcSAsim Jamshed *
38176404edcSAsim Jamshed * The implementation should probably change to an array access.
38276404edcSAsim Jamshed */
atomuse(s)38376404edcSAsim Jamshed static int atomuse(s)
38476404edcSAsim Jamshed struct stmt *s;
38576404edcSAsim Jamshed {
38676404edcSAsim Jamshed register int c = s->code;
38776404edcSAsim Jamshed
38876404edcSAsim Jamshed if (c == NOP)
38976404edcSAsim Jamshed return -1;
39076404edcSAsim Jamshed
39176404edcSAsim Jamshed switch (BPF_CLASS(c))
39276404edcSAsim Jamshed {
39376404edcSAsim Jamshed
39476404edcSAsim Jamshed case BPF_RET:
39576404edcSAsim Jamshed return (BPF_RVAL(c) == BPF_A) ? A_ATOM : (BPF_RVAL(c) == BPF_X) ? X_ATOM : -1;
39676404edcSAsim Jamshed
39776404edcSAsim Jamshed case BPF_LD:
39876404edcSAsim Jamshed case BPF_LDX:
39976404edcSAsim Jamshed return (BPF_MODE(c) == BPF_IND) ? X_ATOM : (BPF_MODE(c) == BPF_MEM) ? s->k : -1;
40076404edcSAsim Jamshed
40176404edcSAsim Jamshed case BPF_ST:
40276404edcSAsim Jamshed return A_ATOM;
40376404edcSAsim Jamshed
40476404edcSAsim Jamshed case BPF_STX:
40576404edcSAsim Jamshed return X_ATOM;
40676404edcSAsim Jamshed
40776404edcSAsim Jamshed case BPF_JMP:
40876404edcSAsim Jamshed case BPF_ALU:
40976404edcSAsim Jamshed if (BPF_SRC(c) == BPF_X)
41076404edcSAsim Jamshed return AX_ATOM;
41176404edcSAsim Jamshed return A_ATOM;
41276404edcSAsim Jamshed
41376404edcSAsim Jamshed case BPF_MISC:
41476404edcSAsim Jamshed return BPF_MISCOP(c) == BPF_TXA ? X_ATOM : A_ATOM;
41576404edcSAsim Jamshed }
41676404edcSAsim Jamshed abort();
41776404edcSAsim Jamshed /* NOTREACHED */
41876404edcSAsim Jamshed }
41976404edcSAsim Jamshed
42076404edcSAsim Jamshed /*
42176404edcSAsim Jamshed * Return the register number that is defined by 's'. We assume that
42276404edcSAsim Jamshed * a single stmt cannot define more than one register. If no register
42376404edcSAsim Jamshed * is defined, return -1.
42476404edcSAsim Jamshed *
42576404edcSAsim Jamshed * The implementation should probably change to an array access.
42676404edcSAsim Jamshed */
atomdef(s)42776404edcSAsim Jamshed static int atomdef(s)
42876404edcSAsim Jamshed struct stmt *s;
42976404edcSAsim Jamshed {
43076404edcSAsim Jamshed if (s->code == NOP)
43176404edcSAsim Jamshed return -1;
43276404edcSAsim Jamshed
43376404edcSAsim Jamshed switch (BPF_CLASS(s->code))
43476404edcSAsim Jamshed {
43576404edcSAsim Jamshed
43676404edcSAsim Jamshed case BPF_LD:
43776404edcSAsim Jamshed case BPF_ALU:
43876404edcSAsim Jamshed return A_ATOM;
43976404edcSAsim Jamshed
44076404edcSAsim Jamshed case BPF_LDX:
44176404edcSAsim Jamshed return X_ATOM;
44276404edcSAsim Jamshed
44376404edcSAsim Jamshed case BPF_ST:
44476404edcSAsim Jamshed case BPF_STX:
44576404edcSAsim Jamshed return s->k;
44676404edcSAsim Jamshed
44776404edcSAsim Jamshed case BPF_MISC:
44876404edcSAsim Jamshed return BPF_MISCOP(s->code) == BPF_TAX ? X_ATOM : A_ATOM;
44976404edcSAsim Jamshed }
45076404edcSAsim Jamshed return -1;
45176404edcSAsim Jamshed }
45276404edcSAsim Jamshed
45376404edcSAsim Jamshed /*
45476404edcSAsim Jamshed * Compute the sets of registers used, defined, and killed by 'b'.
45576404edcSAsim Jamshed *
45676404edcSAsim Jamshed * "Used" means that a statement in 'b' uses the register before any
45776404edcSAsim Jamshed * statement in 'b' defines it, i.e. it uses the value left in
45876404edcSAsim Jamshed * that register by a predecessor block of this block.
45976404edcSAsim Jamshed * "Defined" means that a statement in 'b' defines it.
46076404edcSAsim Jamshed * "Killed" means that a statement in 'b' defines it before any
46176404edcSAsim Jamshed * statement in 'b' uses it, i.e. it kills the value left in that
46276404edcSAsim Jamshed * register by a predecessor block of this block.
46376404edcSAsim Jamshed */
compute_local_ud(b)46476404edcSAsim Jamshed static void compute_local_ud(b)
46576404edcSAsim Jamshed struct block *b;
46676404edcSAsim Jamshed {
46776404edcSAsim Jamshed struct slist *s;
46876404edcSAsim Jamshed atomset def = 0, use = 0, kill = 0;
46976404edcSAsim Jamshed int atom;
47076404edcSAsim Jamshed
47176404edcSAsim Jamshed for (s = b->stmts; s; s = s->next)
47276404edcSAsim Jamshed {
47376404edcSAsim Jamshed if (s->s.code == NOP)
47476404edcSAsim Jamshed continue;
47576404edcSAsim Jamshed atom = atomuse(&s->s);
47676404edcSAsim Jamshed if (atom >= 0)
47776404edcSAsim Jamshed {
47876404edcSAsim Jamshed if (atom == AX_ATOM)
47976404edcSAsim Jamshed {
48076404edcSAsim Jamshed if (!ATOMELEM(def, X_ATOM))
48176404edcSAsim Jamshed use |= ATOMMASK(X_ATOM);
48276404edcSAsim Jamshed if (!ATOMELEM(def, A_ATOM))
48376404edcSAsim Jamshed use |= ATOMMASK(A_ATOM);
48476404edcSAsim Jamshed }
48576404edcSAsim Jamshed else if (atom < N_ATOMS)
48676404edcSAsim Jamshed {
48776404edcSAsim Jamshed if (!ATOMELEM(def, atom))
48876404edcSAsim Jamshed use |= ATOMMASK(atom);
48976404edcSAsim Jamshed }
49076404edcSAsim Jamshed else
49176404edcSAsim Jamshed abort();
49276404edcSAsim Jamshed }
49376404edcSAsim Jamshed atom = atomdef(&s->s);
49476404edcSAsim Jamshed if (atom >= 0)
49576404edcSAsim Jamshed {
49676404edcSAsim Jamshed if (!ATOMELEM(use, atom))
49776404edcSAsim Jamshed kill |= ATOMMASK(atom);
49876404edcSAsim Jamshed def |= ATOMMASK(atom);
49976404edcSAsim Jamshed }
50076404edcSAsim Jamshed }
50176404edcSAsim Jamshed if (BPF_CLASS(b->s.code) == BPF_JMP)
50276404edcSAsim Jamshed {
50376404edcSAsim Jamshed /*
50476404edcSAsim Jamshed * XXX - what about RET?
50576404edcSAsim Jamshed */
50676404edcSAsim Jamshed atom = atomuse(&b->s);
50776404edcSAsim Jamshed if (atom >= 0)
50876404edcSAsim Jamshed {
50976404edcSAsim Jamshed if (atom == AX_ATOM)
51076404edcSAsim Jamshed {
51176404edcSAsim Jamshed if (!ATOMELEM(def, X_ATOM))
51276404edcSAsim Jamshed use |= ATOMMASK(X_ATOM);
51376404edcSAsim Jamshed if (!ATOMELEM(def, A_ATOM))
51476404edcSAsim Jamshed use |= ATOMMASK(A_ATOM);
51576404edcSAsim Jamshed }
51676404edcSAsim Jamshed else if (atom < N_ATOMS)
51776404edcSAsim Jamshed {
51876404edcSAsim Jamshed if (!ATOMELEM(def, atom))
51976404edcSAsim Jamshed use |= ATOMMASK(atom);
52076404edcSAsim Jamshed }
52176404edcSAsim Jamshed else
52276404edcSAsim Jamshed abort();
52376404edcSAsim Jamshed }
52476404edcSAsim Jamshed }
52576404edcSAsim Jamshed
52676404edcSAsim Jamshed b->def = def;
52776404edcSAsim Jamshed b->kill = kill;
52876404edcSAsim Jamshed b->in_use = use;
52976404edcSAsim Jamshed }
53076404edcSAsim Jamshed
53176404edcSAsim Jamshed /*
53276404edcSAsim Jamshed * Assume graph is already leveled.
53376404edcSAsim Jamshed */
find_ud(root)53476404edcSAsim Jamshed static void find_ud(root)
53576404edcSAsim Jamshed struct block *root;
53676404edcSAsim Jamshed {
53776404edcSAsim Jamshed int i, maxlevel;
53876404edcSAsim Jamshed struct block *p;
53976404edcSAsim Jamshed
54076404edcSAsim Jamshed /*
54176404edcSAsim Jamshed * root->level is the highest level no found;
54276404edcSAsim Jamshed * count down from there.
54376404edcSAsim Jamshed */
54476404edcSAsim Jamshed maxlevel = root->level;
54576404edcSAsim Jamshed for (i = maxlevel; i >= 0; --i)
54676404edcSAsim Jamshed for (p = levels[i]; p; p = p->link)
54776404edcSAsim Jamshed {
54876404edcSAsim Jamshed compute_local_ud(p);
54976404edcSAsim Jamshed p->out_use = 0;
55076404edcSAsim Jamshed }
55176404edcSAsim Jamshed
55276404edcSAsim Jamshed for (i = 1; i <= maxlevel; ++i)
55376404edcSAsim Jamshed {
55476404edcSAsim Jamshed for (p = levels[i]; p; p = p->link)
55576404edcSAsim Jamshed {
55676404edcSAsim Jamshed p->out_use |= JT(p)->in_use | JF(p)->in_use;
55776404edcSAsim Jamshed p->in_use |= p->out_use & ~p->kill;
55876404edcSAsim Jamshed }
55976404edcSAsim Jamshed }
56076404edcSAsim Jamshed }
56176404edcSAsim Jamshed
56276404edcSAsim Jamshed /*
56376404edcSAsim Jamshed * These data structures are used in a Cocke and Shwarz style
56476404edcSAsim Jamshed * value numbering scheme. Since the flowgraph is acyclic,
56576404edcSAsim Jamshed * exit values can be propagated from a node's predecessors
56676404edcSAsim Jamshed * provided it is uniquely defined.
56776404edcSAsim Jamshed */
56876404edcSAsim Jamshed struct valnode
56976404edcSAsim Jamshed {
57076404edcSAsim Jamshed int code;
57176404edcSAsim Jamshed int v0, v1;
57276404edcSAsim Jamshed int val;
57376404edcSAsim Jamshed struct valnode *next;
57476404edcSAsim Jamshed };
57576404edcSAsim Jamshed
57676404edcSAsim Jamshed #define MODULUS 213
57776404edcSAsim Jamshed static __thread struct valnode *hashtbl[MODULUS];
57876404edcSAsim Jamshed static __thread int curval;
57976404edcSAsim Jamshed static __thread int maxval;
58076404edcSAsim Jamshed
58176404edcSAsim Jamshed /* Integer constants mapped with the load immediate opcode. */
58276404edcSAsim Jamshed #define K(i) F(BPF_LD|BPF_IMM|BPF_W, i, 0L)
58376404edcSAsim Jamshed
58476404edcSAsim Jamshed struct vmapinfo
58576404edcSAsim Jamshed {
58676404edcSAsim Jamshed int is_const;
58776404edcSAsim Jamshed bpf_int32 const_val;
58876404edcSAsim Jamshed };
58976404edcSAsim Jamshed
59076404edcSAsim Jamshed __thread struct vmapinfo *vmap;
59176404edcSAsim Jamshed __thread struct valnode *vnode_base;
59276404edcSAsim Jamshed __thread struct valnode *next_vnode;
59376404edcSAsim Jamshed
init_val()59476404edcSAsim Jamshed static void init_val()
59576404edcSAsim Jamshed {
59676404edcSAsim Jamshed curval = 0;
59776404edcSAsim Jamshed next_vnode = vnode_base;
59876404edcSAsim Jamshed memset((char *) vmap, 0, maxval * sizeof(*vmap));
59976404edcSAsim Jamshed memset((char *) hashtbl, 0, sizeof hashtbl);
60076404edcSAsim Jamshed }
60176404edcSAsim Jamshed
60276404edcSAsim Jamshed /* Because we really don't have an IR, this stuff is a little messy. */
F(code,v0,v1)60376404edcSAsim Jamshed static int F(code, v0, v1)
60476404edcSAsim Jamshed int code;
60576404edcSAsim Jamshed int v0, v1;
60676404edcSAsim Jamshed {
60776404edcSAsim Jamshed u_int hash;
60876404edcSAsim Jamshed int val;
60976404edcSAsim Jamshed struct valnode *p;
61076404edcSAsim Jamshed
61176404edcSAsim Jamshed hash = (u_int) code ^ (v0 << 4) ^ (v1 << 8);
61276404edcSAsim Jamshed hash %= MODULUS;
61376404edcSAsim Jamshed
61476404edcSAsim Jamshed for (p = hashtbl[hash]; p; p = p->next)
61576404edcSAsim Jamshed if (p->code == code && p->v0 == v0 && p->v1 == v1)
61676404edcSAsim Jamshed return p->val;
61776404edcSAsim Jamshed
61876404edcSAsim Jamshed val = ++curval;
61976404edcSAsim Jamshed if (BPF_MODE(code) == BPF_IMM && (BPF_CLASS(code) == BPF_LD || BPF_CLASS(code) == BPF_LDX))
62076404edcSAsim Jamshed {
62176404edcSAsim Jamshed vmap[val].const_val = v0;
62276404edcSAsim Jamshed vmap[val].is_const = 1;
62376404edcSAsim Jamshed }
62476404edcSAsim Jamshed p = next_vnode++;
62576404edcSAsim Jamshed p->val = val;
62676404edcSAsim Jamshed p->code = code;
62776404edcSAsim Jamshed p->v0 = v0;
62876404edcSAsim Jamshed p->v1 = v1;
62976404edcSAsim Jamshed p->next = hashtbl[hash];
63076404edcSAsim Jamshed hashtbl[hash] = p;
63176404edcSAsim Jamshed
63276404edcSAsim Jamshed return val;
63376404edcSAsim Jamshed }
63476404edcSAsim Jamshed
vstore(s,valp,newval,alter)63576404edcSAsim Jamshed static inline void vstore(s, valp, newval, alter)
63676404edcSAsim Jamshed struct stmt *s;
63776404edcSAsim Jamshed int *valp;
63876404edcSAsim Jamshed int newval;
63976404edcSAsim Jamshed int alter;
64076404edcSAsim Jamshed {
64176404edcSAsim Jamshed if (alter && *valp == newval)
64276404edcSAsim Jamshed s->code = NOP;
64376404edcSAsim Jamshed else
64476404edcSAsim Jamshed *valp = newval;
64576404edcSAsim Jamshed }
64676404edcSAsim Jamshed
fold_op(s,v0,v1)64776404edcSAsim Jamshed static void fold_op(s, v0, v1)
64876404edcSAsim Jamshed struct stmt *s;
64976404edcSAsim Jamshed int v0, v1;
65076404edcSAsim Jamshed {
65176404edcSAsim Jamshed bpf_u_int32 a, b;
65276404edcSAsim Jamshed
65376404edcSAsim Jamshed a = vmap[v0].const_val;
65476404edcSAsim Jamshed b = vmap[v1].const_val;
65576404edcSAsim Jamshed
65676404edcSAsim Jamshed switch (BPF_OP(s->code))
65776404edcSAsim Jamshed {
65876404edcSAsim Jamshed case BPF_ADD:
65976404edcSAsim Jamshed a += b;
66076404edcSAsim Jamshed break;
66176404edcSAsim Jamshed
66276404edcSAsim Jamshed case BPF_SUB:
66376404edcSAsim Jamshed a -= b;
66476404edcSAsim Jamshed break;
66576404edcSAsim Jamshed
66676404edcSAsim Jamshed case BPF_MUL:
66776404edcSAsim Jamshed a *= b;
66876404edcSAsim Jamshed break;
66976404edcSAsim Jamshed
67076404edcSAsim Jamshed case BPF_DIV:
67176404edcSAsim Jamshed if (b == 0)
67276404edcSAsim Jamshed bpf_error("division by zero");
67376404edcSAsim Jamshed a /= b;
67476404edcSAsim Jamshed break;
67576404edcSAsim Jamshed
67676404edcSAsim Jamshed case BPF_AND:
67776404edcSAsim Jamshed a &= b;
67876404edcSAsim Jamshed break;
67976404edcSAsim Jamshed
68076404edcSAsim Jamshed case BPF_OR:
68176404edcSAsim Jamshed a |= b;
68276404edcSAsim Jamshed break;
68376404edcSAsim Jamshed
68476404edcSAsim Jamshed case BPF_LSH:
68576404edcSAsim Jamshed a <<= b;
68676404edcSAsim Jamshed break;
68776404edcSAsim Jamshed
68876404edcSAsim Jamshed case BPF_RSH:
68976404edcSAsim Jamshed a >>= b;
69076404edcSAsim Jamshed break;
69176404edcSAsim Jamshed
69276404edcSAsim Jamshed case BPF_NEG:
69376404edcSAsim Jamshed a = -a;
69476404edcSAsim Jamshed break;
69576404edcSAsim Jamshed
69676404edcSAsim Jamshed default:
69776404edcSAsim Jamshed abort();
69876404edcSAsim Jamshed }
69976404edcSAsim Jamshed s->k = a;
70076404edcSAsim Jamshed s->code = BPF_LD | BPF_IMM;
70176404edcSAsim Jamshed done = 0;
70276404edcSAsim Jamshed }
70376404edcSAsim Jamshed
this_op(s)70476404edcSAsim Jamshed static inline struct slist *this_op(s)
70576404edcSAsim Jamshed struct slist *s;
70676404edcSAsim Jamshed {
70776404edcSAsim Jamshed while (s != 0 && s->s.code == NOP)
70876404edcSAsim Jamshed s = s->next;
70976404edcSAsim Jamshed return s;
71076404edcSAsim Jamshed }
71176404edcSAsim Jamshed
opt_not(b)71276404edcSAsim Jamshed static void opt_not(b)
71376404edcSAsim Jamshed struct block *b;
71476404edcSAsim Jamshed {
71576404edcSAsim Jamshed struct block *tmp = JT(b);
71676404edcSAsim Jamshed
71776404edcSAsim Jamshed JT(b) = JF(b);
71876404edcSAsim Jamshed JF(b) = tmp;
71976404edcSAsim Jamshed }
72076404edcSAsim Jamshed
opt_peep(b)72176404edcSAsim Jamshed static void opt_peep(b)
72276404edcSAsim Jamshed struct block *b;
72376404edcSAsim Jamshed {
72476404edcSAsim Jamshed struct slist *s;
72576404edcSAsim Jamshed struct slist *next, *last;
72676404edcSAsim Jamshed int val;
72776404edcSAsim Jamshed
72876404edcSAsim Jamshed s = b->stmts;
72976404edcSAsim Jamshed if (s == 0)
73076404edcSAsim Jamshed return;
73176404edcSAsim Jamshed
73276404edcSAsim Jamshed last = s;
73376404edcSAsim Jamshed for ( /*empty */ ; /*empty */ ; s = next)
73476404edcSAsim Jamshed {
73576404edcSAsim Jamshed /*
73676404edcSAsim Jamshed * Skip over nops.
73776404edcSAsim Jamshed */
73876404edcSAsim Jamshed s = this_op(s);
73976404edcSAsim Jamshed if (s == 0)
74076404edcSAsim Jamshed break; /* nothing left in the block */
74176404edcSAsim Jamshed
74276404edcSAsim Jamshed /*
74376404edcSAsim Jamshed * Find the next real instruction after that one
74476404edcSAsim Jamshed * (skipping nops).
74576404edcSAsim Jamshed */
74676404edcSAsim Jamshed next = this_op(s->next);
74776404edcSAsim Jamshed if (next == 0)
74876404edcSAsim Jamshed break; /* no next instruction */
74976404edcSAsim Jamshed last = next;
75076404edcSAsim Jamshed
75176404edcSAsim Jamshed /*
75276404edcSAsim Jamshed * st M[k] --> st M[k]
75376404edcSAsim Jamshed * ldx M[k] tax
75476404edcSAsim Jamshed */
75576404edcSAsim Jamshed if (s->s.code == BPF_ST && next->s.code == (BPF_LDX | BPF_MEM) && s->s.k == next->s.k)
75676404edcSAsim Jamshed {
75776404edcSAsim Jamshed done = 0;
75876404edcSAsim Jamshed next->s.code = BPF_MISC | BPF_TAX;
75976404edcSAsim Jamshed }
76076404edcSAsim Jamshed /*
76176404edcSAsim Jamshed * ld #k --> ldx #k
76276404edcSAsim Jamshed * tax txa
76376404edcSAsim Jamshed */
76476404edcSAsim Jamshed if (s->s.code == (BPF_LD | BPF_IMM) && next->s.code == (BPF_MISC | BPF_TAX))
76576404edcSAsim Jamshed {
76676404edcSAsim Jamshed s->s.code = BPF_LDX | BPF_IMM;
76776404edcSAsim Jamshed next->s.code = BPF_MISC | BPF_TXA;
76876404edcSAsim Jamshed done = 0;
76976404edcSAsim Jamshed }
77076404edcSAsim Jamshed /*
77176404edcSAsim Jamshed * This is an ugly special case, but it happens
77276404edcSAsim Jamshed * when you say tcp[k] or udp[k] where k is a constant.
77376404edcSAsim Jamshed */
77476404edcSAsim Jamshed if (s->s.code == (BPF_LD | BPF_IMM))
77576404edcSAsim Jamshed {
77676404edcSAsim Jamshed struct slist *add, *tax, *ild;
77776404edcSAsim Jamshed
77876404edcSAsim Jamshed /*
77976404edcSAsim Jamshed * Check that X isn't used on exit from this
78076404edcSAsim Jamshed * block (which the optimizer might cause).
78176404edcSAsim Jamshed * We know the code generator won't generate
78276404edcSAsim Jamshed * any local dependencies.
78376404edcSAsim Jamshed */
78476404edcSAsim Jamshed if (ATOMELEM(b->out_use, X_ATOM))
78576404edcSAsim Jamshed continue;
78676404edcSAsim Jamshed
78776404edcSAsim Jamshed /*
78876404edcSAsim Jamshed * Check that the instruction following the ldi
78976404edcSAsim Jamshed * is an addx, or it's an ldxms with an addx
79076404edcSAsim Jamshed * following it (with 0 or more nops between the
79176404edcSAsim Jamshed * ldxms and addx).
79276404edcSAsim Jamshed */
79376404edcSAsim Jamshed if (next->s.code != (BPF_LDX | BPF_MSH | BPF_B))
79476404edcSAsim Jamshed add = next;
79576404edcSAsim Jamshed else
79676404edcSAsim Jamshed add = this_op(next->next);
79776404edcSAsim Jamshed if (add == 0 || add->s.code != (BPF_ALU | BPF_ADD | BPF_X))
79876404edcSAsim Jamshed continue;
79976404edcSAsim Jamshed
80076404edcSAsim Jamshed /*
80176404edcSAsim Jamshed * Check that a tax follows that (with 0 or more
80276404edcSAsim Jamshed * nops between them).
80376404edcSAsim Jamshed */
80476404edcSAsim Jamshed tax = this_op(add->next);
80576404edcSAsim Jamshed if (tax == 0 || tax->s.code != (BPF_MISC | BPF_TAX))
80676404edcSAsim Jamshed continue;
80776404edcSAsim Jamshed
80876404edcSAsim Jamshed /*
80976404edcSAsim Jamshed * Check that an ild follows that (with 0 or more
81076404edcSAsim Jamshed * nops between them).
81176404edcSAsim Jamshed */
81276404edcSAsim Jamshed ild = this_op(tax->next);
81376404edcSAsim Jamshed if (ild == 0 || BPF_CLASS(ild->s.code) != BPF_LD || BPF_MODE(ild->s.code) != BPF_IND)
81476404edcSAsim Jamshed continue;
81576404edcSAsim Jamshed /*
81676404edcSAsim Jamshed * We want to turn this sequence:
81776404edcSAsim Jamshed *
81876404edcSAsim Jamshed * (004) ldi #0x2 {s}
81976404edcSAsim Jamshed * (005) ldxms [14] {next} -- optional
82076404edcSAsim Jamshed * (006) addx {add}
82176404edcSAsim Jamshed * (007) tax {tax}
82276404edcSAsim Jamshed * (008) ild [x+0] {ild}
82376404edcSAsim Jamshed *
82476404edcSAsim Jamshed * into this sequence:
82576404edcSAsim Jamshed *
82676404edcSAsim Jamshed * (004) nop
82776404edcSAsim Jamshed * (005) ldxms [14]
82876404edcSAsim Jamshed * (006) nop
82976404edcSAsim Jamshed * (007) nop
83076404edcSAsim Jamshed * (008) ild [x+2]
83176404edcSAsim Jamshed *
83276404edcSAsim Jamshed * XXX We need to check that X is not
83376404edcSAsim Jamshed * subsequently used, because we want to change
83476404edcSAsim Jamshed * what'll be in it after this sequence.
83576404edcSAsim Jamshed *
83676404edcSAsim Jamshed * We know we can eliminate the accumulator
83776404edcSAsim Jamshed * modifications earlier in the sequence since
83876404edcSAsim Jamshed * it is defined by the last stmt of this sequence
83976404edcSAsim Jamshed * (i.e., the last statement of the sequence loads
84076404edcSAsim Jamshed * a value into the accumulator, so we can eliminate
84176404edcSAsim Jamshed * earlier operations on the accumulator).
84276404edcSAsim Jamshed */
84376404edcSAsim Jamshed ild->s.k += s->s.k;
84476404edcSAsim Jamshed s->s.code = NOP;
84576404edcSAsim Jamshed add->s.code = NOP;
84676404edcSAsim Jamshed tax->s.code = NOP;
84776404edcSAsim Jamshed done = 0;
84876404edcSAsim Jamshed }
84976404edcSAsim Jamshed }
85076404edcSAsim Jamshed /*
85176404edcSAsim Jamshed * If the comparison at the end of a block is an equality
85276404edcSAsim Jamshed * comparison against a constant, and nobody uses the value
85376404edcSAsim Jamshed * we leave in the A register at the end of a block, and
85476404edcSAsim Jamshed * the operation preceding the comparison is an arithmetic
85576404edcSAsim Jamshed * operation, we can sometime optimize it away.
85676404edcSAsim Jamshed */
85776404edcSAsim Jamshed if (b->s.code == (BPF_JMP | BPF_JEQ | BPF_K) && !ATOMELEM(b->out_use, A_ATOM))
85876404edcSAsim Jamshed {
85976404edcSAsim Jamshed /*
86076404edcSAsim Jamshed * We can optimize away certain subtractions of the
86176404edcSAsim Jamshed * X register.
86276404edcSAsim Jamshed */
86376404edcSAsim Jamshed if (last->s.code == (BPF_ALU | BPF_SUB | BPF_X))
86476404edcSAsim Jamshed {
86576404edcSAsim Jamshed val = b->val[X_ATOM];
86676404edcSAsim Jamshed if (vmap[val].is_const)
86776404edcSAsim Jamshed {
86876404edcSAsim Jamshed /*
86976404edcSAsim Jamshed * If we have a subtract to do a comparison,
87076404edcSAsim Jamshed * and the X register is a known constant,
87176404edcSAsim Jamshed * we can merge this value into the
87276404edcSAsim Jamshed * comparison:
87376404edcSAsim Jamshed *
87476404edcSAsim Jamshed * sub x -> nop
87576404edcSAsim Jamshed * jeq #y jeq #(x+y)
87676404edcSAsim Jamshed */
87776404edcSAsim Jamshed b->s.k += vmap[val].const_val;
87876404edcSAsim Jamshed last->s.code = NOP;
87976404edcSAsim Jamshed done = 0;
88076404edcSAsim Jamshed }
88176404edcSAsim Jamshed else if (b->s.k == 0)
88276404edcSAsim Jamshed {
88376404edcSAsim Jamshed /*
88476404edcSAsim Jamshed * If the X register isn't a constant,
88576404edcSAsim Jamshed * and the comparison in the test is
88676404edcSAsim Jamshed * against 0, we can compare with the
88776404edcSAsim Jamshed * X register, instead:
88876404edcSAsim Jamshed *
88976404edcSAsim Jamshed * sub x -> nop
89076404edcSAsim Jamshed * jeq #0 jeq x
89176404edcSAsim Jamshed */
89276404edcSAsim Jamshed last->s.code = NOP;
89376404edcSAsim Jamshed b->s.code = BPF_JMP | BPF_JEQ | BPF_X;
89476404edcSAsim Jamshed done = 0;
89576404edcSAsim Jamshed }
89676404edcSAsim Jamshed }
89776404edcSAsim Jamshed /*
89876404edcSAsim Jamshed * Likewise, a constant subtract can be simplified:
89976404edcSAsim Jamshed *
90076404edcSAsim Jamshed * sub #x -> nop
90176404edcSAsim Jamshed * jeq #y -> jeq #(x+y)
90276404edcSAsim Jamshed */
90376404edcSAsim Jamshed else if (last->s.code == (BPF_ALU | BPF_SUB | BPF_K))
90476404edcSAsim Jamshed {
90576404edcSAsim Jamshed last->s.code = NOP;
90676404edcSAsim Jamshed b->s.k += last->s.k;
90776404edcSAsim Jamshed done = 0;
90876404edcSAsim Jamshed }
90976404edcSAsim Jamshed /*
91076404edcSAsim Jamshed * And, similarly, a constant AND can be simplified
91176404edcSAsim Jamshed * if we're testing against 0, i.e.:
91276404edcSAsim Jamshed *
91376404edcSAsim Jamshed * and #k nop
91476404edcSAsim Jamshed * jeq #0 -> jset #k
91576404edcSAsim Jamshed */
91676404edcSAsim Jamshed else if (last->s.code == (BPF_ALU | BPF_AND | BPF_K) && b->s.k == 0)
91776404edcSAsim Jamshed {
91876404edcSAsim Jamshed b->s.k = last->s.k;
91976404edcSAsim Jamshed b->s.code = BPF_JMP | BPF_K | BPF_JSET;
92076404edcSAsim Jamshed last->s.code = NOP;
92176404edcSAsim Jamshed done = 0;
92276404edcSAsim Jamshed opt_not(b);
92376404edcSAsim Jamshed }
92476404edcSAsim Jamshed }
92576404edcSAsim Jamshed /*
92676404edcSAsim Jamshed * jset #0 -> never
92776404edcSAsim Jamshed * jset #ffffffff -> always
92876404edcSAsim Jamshed */
92976404edcSAsim Jamshed if (b->s.code == (BPF_JMP | BPF_K | BPF_JSET))
93076404edcSAsim Jamshed {
93176404edcSAsim Jamshed if (b->s.k == 0)
93276404edcSAsim Jamshed JT(b) = JF(b);
93376404edcSAsim Jamshed if (b->s.k == 0xffffffff)
93476404edcSAsim Jamshed JF(b) = JT(b);
93576404edcSAsim Jamshed }
93676404edcSAsim Jamshed /*
93776404edcSAsim Jamshed * If we're comparing against the index register, and the index
93876404edcSAsim Jamshed * register is a known constant, we can just compare against that
93976404edcSAsim Jamshed * constant.
94076404edcSAsim Jamshed */
94176404edcSAsim Jamshed val = b->val[X_ATOM];
94276404edcSAsim Jamshed if (vmap[val].is_const && BPF_SRC(b->s.code) == BPF_X)
94376404edcSAsim Jamshed {
94476404edcSAsim Jamshed bpf_int32 v = vmap[val].const_val;
94576404edcSAsim Jamshed b->s.code &= ~BPF_X;
94676404edcSAsim Jamshed b->s.k = v;
94776404edcSAsim Jamshed }
94876404edcSAsim Jamshed /*
94976404edcSAsim Jamshed * If the accumulator is a known constant, we can compute the
95076404edcSAsim Jamshed * comparison result.
95176404edcSAsim Jamshed */
95276404edcSAsim Jamshed val = b->val[A_ATOM];
95376404edcSAsim Jamshed if (vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K)
95476404edcSAsim Jamshed {
95576404edcSAsim Jamshed bpf_int32 v = vmap[val].const_val;
95676404edcSAsim Jamshed switch (BPF_OP(b->s.code))
95776404edcSAsim Jamshed {
95876404edcSAsim Jamshed
95976404edcSAsim Jamshed case BPF_JEQ:
96076404edcSAsim Jamshed v = v == b->s.k;
96176404edcSAsim Jamshed break;
96276404edcSAsim Jamshed
96376404edcSAsim Jamshed case BPF_JGT:
96476404edcSAsim Jamshed v = (unsigned) v > b->s.k;
96576404edcSAsim Jamshed break;
96676404edcSAsim Jamshed
96776404edcSAsim Jamshed case BPF_JGE:
96876404edcSAsim Jamshed v = (unsigned) v >= b->s.k;
96976404edcSAsim Jamshed break;
97076404edcSAsim Jamshed
97176404edcSAsim Jamshed case BPF_JSET:
97276404edcSAsim Jamshed v &= b->s.k;
97376404edcSAsim Jamshed break;
97476404edcSAsim Jamshed
97576404edcSAsim Jamshed default:
97676404edcSAsim Jamshed abort();
97776404edcSAsim Jamshed }
97876404edcSAsim Jamshed if (JF(b) != JT(b))
97976404edcSAsim Jamshed done = 0;
98076404edcSAsim Jamshed if (v)
98176404edcSAsim Jamshed JF(b) = JT(b);
98276404edcSAsim Jamshed else
98376404edcSAsim Jamshed JT(b) = JF(b);
98476404edcSAsim Jamshed }
98576404edcSAsim Jamshed }
98676404edcSAsim Jamshed
98776404edcSAsim Jamshed /*
98876404edcSAsim Jamshed * Compute the symbolic value of expression of 's', and update
98976404edcSAsim Jamshed * anything it defines in the value table 'val'. If 'alter' is true,
99076404edcSAsim Jamshed * do various optimizations. This code would be cleaner if symbolic
99176404edcSAsim Jamshed * evaluation and code transformations weren't folded together.
99276404edcSAsim Jamshed */
opt_stmt(s,val,alter)99376404edcSAsim Jamshed static void opt_stmt(s, val, alter)
99476404edcSAsim Jamshed struct stmt *s;
99576404edcSAsim Jamshed int val[];
99676404edcSAsim Jamshed int alter;
99776404edcSAsim Jamshed {
99876404edcSAsim Jamshed int op;
99976404edcSAsim Jamshed int v;
100076404edcSAsim Jamshed
100176404edcSAsim Jamshed switch (s->code)
100276404edcSAsim Jamshed {
100376404edcSAsim Jamshed
100476404edcSAsim Jamshed case BPF_LD | BPF_ABS | BPF_W:
100576404edcSAsim Jamshed case BPF_LD | BPF_ABS | BPF_H:
100676404edcSAsim Jamshed case BPF_LD | BPF_ABS | BPF_B:
100776404edcSAsim Jamshed v = F(s->code, s->k, 0L);
100876404edcSAsim Jamshed vstore(s, &val[A_ATOM], v, alter);
100976404edcSAsim Jamshed break;
101076404edcSAsim Jamshed
101176404edcSAsim Jamshed case BPF_LD | BPF_IND | BPF_W:
101276404edcSAsim Jamshed case BPF_LD | BPF_IND | BPF_H:
101376404edcSAsim Jamshed case BPF_LD | BPF_IND | BPF_B:
101476404edcSAsim Jamshed v = val[X_ATOM];
101576404edcSAsim Jamshed if (alter && vmap[v].is_const)
101676404edcSAsim Jamshed {
101776404edcSAsim Jamshed s->code = BPF_LD | BPF_ABS | BPF_SIZE(s->code);
101876404edcSAsim Jamshed s->k += vmap[v].const_val;
101976404edcSAsim Jamshed v = F(s->code, s->k, 0L);
102076404edcSAsim Jamshed done = 0;
102176404edcSAsim Jamshed }
102276404edcSAsim Jamshed else
102376404edcSAsim Jamshed v = F(s->code, s->k, v);
102476404edcSAsim Jamshed vstore(s, &val[A_ATOM], v, alter);
102576404edcSAsim Jamshed break;
102676404edcSAsim Jamshed
102776404edcSAsim Jamshed case BPF_LD | BPF_LEN:
102876404edcSAsim Jamshed v = F(s->code, 0L, 0L);
102976404edcSAsim Jamshed vstore(s, &val[A_ATOM], v, alter);
103076404edcSAsim Jamshed break;
103176404edcSAsim Jamshed
103276404edcSAsim Jamshed case BPF_LD | BPF_IMM:
103376404edcSAsim Jamshed v = K(s->k);
103476404edcSAsim Jamshed vstore(s, &val[A_ATOM], v, alter);
103576404edcSAsim Jamshed break;
103676404edcSAsim Jamshed
103776404edcSAsim Jamshed case BPF_LDX | BPF_IMM:
103876404edcSAsim Jamshed v = K(s->k);
103976404edcSAsim Jamshed vstore(s, &val[X_ATOM], v, alter);
104076404edcSAsim Jamshed break;
104176404edcSAsim Jamshed
104276404edcSAsim Jamshed case BPF_LDX | BPF_MSH | BPF_B:
104376404edcSAsim Jamshed v = F(s->code, s->k, 0L);
104476404edcSAsim Jamshed vstore(s, &val[X_ATOM], v, alter);
104576404edcSAsim Jamshed break;
104676404edcSAsim Jamshed
104776404edcSAsim Jamshed case BPF_ALU | BPF_NEG:
104876404edcSAsim Jamshed if (alter && vmap[val[A_ATOM]].is_const)
104976404edcSAsim Jamshed {
105076404edcSAsim Jamshed s->code = BPF_LD | BPF_IMM;
105176404edcSAsim Jamshed s->k = -vmap[val[A_ATOM]].const_val;
105276404edcSAsim Jamshed val[A_ATOM] = K(s->k);
105376404edcSAsim Jamshed }
105476404edcSAsim Jamshed else
105576404edcSAsim Jamshed val[A_ATOM] = F(s->code, val[A_ATOM], 0L);
105676404edcSAsim Jamshed break;
105776404edcSAsim Jamshed
105876404edcSAsim Jamshed case BPF_ALU | BPF_ADD | BPF_K:
105976404edcSAsim Jamshed case BPF_ALU | BPF_SUB | BPF_K:
106076404edcSAsim Jamshed case BPF_ALU | BPF_MUL | BPF_K:
106176404edcSAsim Jamshed case BPF_ALU | BPF_DIV | BPF_K:
106276404edcSAsim Jamshed case BPF_ALU | BPF_AND | BPF_K:
106376404edcSAsim Jamshed case BPF_ALU | BPF_OR | BPF_K:
106476404edcSAsim Jamshed case BPF_ALU | BPF_LSH | BPF_K:
106576404edcSAsim Jamshed case BPF_ALU | BPF_RSH | BPF_K:
106676404edcSAsim Jamshed op = BPF_OP(s->code);
106776404edcSAsim Jamshed if (alter)
106876404edcSAsim Jamshed {
106976404edcSAsim Jamshed if (s->k == 0)
107076404edcSAsim Jamshed {
107176404edcSAsim Jamshed /* don't optimize away "sub #0"
107276404edcSAsim Jamshed * as it may be needed later to
107376404edcSAsim Jamshed * fixup the generated math code */
107476404edcSAsim Jamshed if (op == BPF_ADD || op == BPF_LSH || op == BPF_RSH || op == BPF_OR)
107576404edcSAsim Jamshed {
107676404edcSAsim Jamshed s->code = NOP;
107776404edcSAsim Jamshed break;
107876404edcSAsim Jamshed }
107976404edcSAsim Jamshed if (op == BPF_MUL || op == BPF_AND)
108076404edcSAsim Jamshed {
108176404edcSAsim Jamshed s->code = BPF_LD | BPF_IMM;
108276404edcSAsim Jamshed val[A_ATOM] = K(s->k);
108376404edcSAsim Jamshed break;
108476404edcSAsim Jamshed }
108576404edcSAsim Jamshed }
108676404edcSAsim Jamshed if (vmap[val[A_ATOM]].is_const)
108776404edcSAsim Jamshed {
108876404edcSAsim Jamshed fold_op(s, val[A_ATOM], K(s->k));
108976404edcSAsim Jamshed val[A_ATOM] = K(s->k);
109076404edcSAsim Jamshed break;
109176404edcSAsim Jamshed }
109276404edcSAsim Jamshed }
109376404edcSAsim Jamshed val[A_ATOM] = F(s->code, val[A_ATOM], K(s->k));
109476404edcSAsim Jamshed break;
109576404edcSAsim Jamshed
109676404edcSAsim Jamshed case BPF_ALU | BPF_ADD | BPF_X:
109776404edcSAsim Jamshed case BPF_ALU | BPF_SUB | BPF_X:
109876404edcSAsim Jamshed case BPF_ALU | BPF_MUL | BPF_X:
109976404edcSAsim Jamshed case BPF_ALU | BPF_DIV | BPF_X:
110076404edcSAsim Jamshed case BPF_ALU | BPF_AND | BPF_X:
110176404edcSAsim Jamshed case BPF_ALU | BPF_OR | BPF_X:
110276404edcSAsim Jamshed case BPF_ALU | BPF_LSH | BPF_X:
110376404edcSAsim Jamshed case BPF_ALU | BPF_RSH | BPF_X:
110476404edcSAsim Jamshed op = BPF_OP(s->code);
110576404edcSAsim Jamshed if (alter && vmap[val[X_ATOM]].is_const)
110676404edcSAsim Jamshed {
110776404edcSAsim Jamshed if (vmap[val[A_ATOM]].is_const)
110876404edcSAsim Jamshed {
110976404edcSAsim Jamshed fold_op(s, val[A_ATOM], val[X_ATOM]);
111076404edcSAsim Jamshed val[A_ATOM] = K(s->k);
111176404edcSAsim Jamshed }
111276404edcSAsim Jamshed else
111376404edcSAsim Jamshed {
111476404edcSAsim Jamshed s->code = BPF_ALU | BPF_K | op;
111576404edcSAsim Jamshed s->k = vmap[val[X_ATOM]].const_val;
111676404edcSAsim Jamshed done = 0;
111776404edcSAsim Jamshed val[A_ATOM] = F(s->code, val[A_ATOM], K(s->k));
111876404edcSAsim Jamshed }
111976404edcSAsim Jamshed break;
112076404edcSAsim Jamshed }
112176404edcSAsim Jamshed /*
112276404edcSAsim Jamshed * Check if we're doing something to an accumulator
112376404edcSAsim Jamshed * that is 0, and simplify. This may not seem like
112476404edcSAsim Jamshed * much of a simplification but it could open up further
112576404edcSAsim Jamshed * optimizations.
112676404edcSAsim Jamshed * XXX We could also check for mul by 1, etc.
112776404edcSAsim Jamshed */
112876404edcSAsim Jamshed if (alter && vmap[val[A_ATOM]].is_const && vmap[val[A_ATOM]].const_val == 0)
112976404edcSAsim Jamshed {
113076404edcSAsim Jamshed if (op == BPF_ADD || op == BPF_OR)
113176404edcSAsim Jamshed {
113276404edcSAsim Jamshed s->code = BPF_MISC | BPF_TXA;
113376404edcSAsim Jamshed vstore(s, &val[A_ATOM], val[X_ATOM], alter);
113476404edcSAsim Jamshed break;
113576404edcSAsim Jamshed }
113676404edcSAsim Jamshed else if (op == BPF_MUL || op == BPF_DIV || op == BPF_AND || op == BPF_LSH || op == BPF_RSH)
113776404edcSAsim Jamshed {
113876404edcSAsim Jamshed s->code = BPF_LD | BPF_IMM;
113976404edcSAsim Jamshed s->k = 0;
114076404edcSAsim Jamshed vstore(s, &val[A_ATOM], K(s->k), alter);
114176404edcSAsim Jamshed break;
114276404edcSAsim Jamshed }
114376404edcSAsim Jamshed else if (op == BPF_NEG)
114476404edcSAsim Jamshed {
114576404edcSAsim Jamshed s->code = NOP;
114676404edcSAsim Jamshed break;
114776404edcSAsim Jamshed }
114876404edcSAsim Jamshed }
114976404edcSAsim Jamshed val[A_ATOM] = F(s->code, val[A_ATOM], val[X_ATOM]);
115076404edcSAsim Jamshed break;
115176404edcSAsim Jamshed
115276404edcSAsim Jamshed case BPF_MISC | BPF_TXA:
115376404edcSAsim Jamshed vstore(s, &val[A_ATOM], val[X_ATOM], alter);
115476404edcSAsim Jamshed break;
115576404edcSAsim Jamshed
115676404edcSAsim Jamshed case BPF_LD | BPF_MEM:
115776404edcSAsim Jamshed v = val[s->k];
115876404edcSAsim Jamshed if (alter && vmap[v].is_const)
115976404edcSAsim Jamshed {
116076404edcSAsim Jamshed s->code = BPF_LD | BPF_IMM;
116176404edcSAsim Jamshed s->k = vmap[v].const_val;
116276404edcSAsim Jamshed done = 0;
116376404edcSAsim Jamshed }
116476404edcSAsim Jamshed vstore(s, &val[A_ATOM], v, alter);
116576404edcSAsim Jamshed break;
116676404edcSAsim Jamshed
116776404edcSAsim Jamshed case BPF_MISC | BPF_TAX:
116876404edcSAsim Jamshed vstore(s, &val[X_ATOM], val[A_ATOM], alter);
116976404edcSAsim Jamshed break;
117076404edcSAsim Jamshed
117176404edcSAsim Jamshed case BPF_LDX | BPF_MEM:
117276404edcSAsim Jamshed v = val[s->k];
117376404edcSAsim Jamshed if (alter && vmap[v].is_const)
117476404edcSAsim Jamshed {
117576404edcSAsim Jamshed s->code = BPF_LDX | BPF_IMM;
117676404edcSAsim Jamshed s->k = vmap[v].const_val;
117776404edcSAsim Jamshed done = 0;
117876404edcSAsim Jamshed }
117976404edcSAsim Jamshed vstore(s, &val[X_ATOM], v, alter);
118076404edcSAsim Jamshed break;
118176404edcSAsim Jamshed
118276404edcSAsim Jamshed case BPF_ST:
118376404edcSAsim Jamshed vstore(s, &val[s->k], val[A_ATOM], alter);
118476404edcSAsim Jamshed break;
118576404edcSAsim Jamshed
118676404edcSAsim Jamshed case BPF_STX:
118776404edcSAsim Jamshed vstore(s, &val[s->k], val[X_ATOM], alter);
118876404edcSAsim Jamshed break;
118976404edcSAsim Jamshed }
119076404edcSAsim Jamshed }
119176404edcSAsim Jamshed
deadstmt(s,last)119276404edcSAsim Jamshed static void deadstmt(s, last)
119376404edcSAsim Jamshed register struct stmt *s;
119476404edcSAsim Jamshed register struct stmt *last[];
119576404edcSAsim Jamshed {
119676404edcSAsim Jamshed register int atom;
119776404edcSAsim Jamshed
119876404edcSAsim Jamshed atom = atomuse(s);
119976404edcSAsim Jamshed if (atom >= 0)
120076404edcSAsim Jamshed {
120176404edcSAsim Jamshed if (atom == AX_ATOM)
120276404edcSAsim Jamshed {
120376404edcSAsim Jamshed last[X_ATOM] = 0;
120476404edcSAsim Jamshed last[A_ATOM] = 0;
120576404edcSAsim Jamshed }
120676404edcSAsim Jamshed else
120776404edcSAsim Jamshed last[atom] = 0;
120876404edcSAsim Jamshed }
120976404edcSAsim Jamshed atom = atomdef(s);
121076404edcSAsim Jamshed if (atom >= 0)
121176404edcSAsim Jamshed {
121276404edcSAsim Jamshed if (last[atom])
121376404edcSAsim Jamshed {
121476404edcSAsim Jamshed done = 0;
121576404edcSAsim Jamshed last[atom]->code = NOP;
121676404edcSAsim Jamshed }
121776404edcSAsim Jamshed last[atom] = s;
121876404edcSAsim Jamshed }
121976404edcSAsim Jamshed }
122076404edcSAsim Jamshed
opt_deadstores(b)122176404edcSAsim Jamshed static void opt_deadstores(b)
122276404edcSAsim Jamshed register struct block *b;
122376404edcSAsim Jamshed {
122476404edcSAsim Jamshed register struct slist *s;
122576404edcSAsim Jamshed register int atom;
122676404edcSAsim Jamshed struct stmt *last[N_ATOMS];
122776404edcSAsim Jamshed
122876404edcSAsim Jamshed memset((char *) last, 0, sizeof last);
122976404edcSAsim Jamshed
123076404edcSAsim Jamshed for (s = b->stmts; s != 0; s = s->next)
123176404edcSAsim Jamshed deadstmt(&s->s, last);
123276404edcSAsim Jamshed deadstmt(&b->s, last);
123376404edcSAsim Jamshed
123476404edcSAsim Jamshed for (atom = 0; atom < N_ATOMS; ++atom)
123576404edcSAsim Jamshed if (last[atom] && !ATOMELEM(b->out_use, atom))
123676404edcSAsim Jamshed {
123776404edcSAsim Jamshed last[atom]->code = NOP;
123876404edcSAsim Jamshed done = 0;
123976404edcSAsim Jamshed }
124076404edcSAsim Jamshed }
124176404edcSAsim Jamshed
opt_blk(b,do_stmts)124276404edcSAsim Jamshed static void opt_blk(b, do_stmts)
124376404edcSAsim Jamshed struct block *b;
124476404edcSAsim Jamshed int do_stmts;
124576404edcSAsim Jamshed {
124676404edcSAsim Jamshed struct slist *s;
124776404edcSAsim Jamshed struct edge *p;
124876404edcSAsim Jamshed int i;
124976404edcSAsim Jamshed bpf_int32 aval, xval;
125076404edcSAsim Jamshed
125176404edcSAsim Jamshed #if YYDEBUG
125276404edcSAsim Jamshed for (s = b->stmts; s && s->next; s = s->next)
125376404edcSAsim Jamshed if (BPF_CLASS(s->s.code) == BPF_JMP)
125476404edcSAsim Jamshed {
125576404edcSAsim Jamshed do_stmts = 0;
125676404edcSAsim Jamshed break;
125776404edcSAsim Jamshed }
125876404edcSAsim Jamshed #endif
125976404edcSAsim Jamshed
126076404edcSAsim Jamshed /*
126176404edcSAsim Jamshed * Initialize the atom values.
126276404edcSAsim Jamshed */
126376404edcSAsim Jamshed p = b->in_edges;
126476404edcSAsim Jamshed if (p == 0)
126576404edcSAsim Jamshed {
126676404edcSAsim Jamshed /*
126776404edcSAsim Jamshed * We have no predecessors, so everything is undefined
126876404edcSAsim Jamshed * upon entry to this block.
126976404edcSAsim Jamshed */
127076404edcSAsim Jamshed memset((char *) b->val, 0, sizeof(b->val));
127176404edcSAsim Jamshed }
127276404edcSAsim Jamshed else
127376404edcSAsim Jamshed {
127476404edcSAsim Jamshed /*
127576404edcSAsim Jamshed * Inherit values from our predecessors.
127676404edcSAsim Jamshed *
127776404edcSAsim Jamshed * First, get the values from the predecessor along the
127876404edcSAsim Jamshed * first edge leading to this node.
127976404edcSAsim Jamshed */
128076404edcSAsim Jamshed memcpy((char *) b->val, (char *) p->pred->val, sizeof(b->val));
128176404edcSAsim Jamshed /*
128276404edcSAsim Jamshed * Now look at all the other nodes leading to this node.
128376404edcSAsim Jamshed * If, for the predecessor along that edge, a register
128476404edcSAsim Jamshed * has a different value from the one we have (i.e.,
128576404edcSAsim Jamshed * control paths are merging, and the merging paths
128676404edcSAsim Jamshed * assign different values to that register), give the
128776404edcSAsim Jamshed * register the undefined value of 0.
128876404edcSAsim Jamshed */
128976404edcSAsim Jamshed while ((p = p->next) != NULL)
129076404edcSAsim Jamshed {
129176404edcSAsim Jamshed for (i = 0; i < N_ATOMS; ++i)
129276404edcSAsim Jamshed if (b->val[i] != p->pred->val[i])
129376404edcSAsim Jamshed b->val[i] = 0;
129476404edcSAsim Jamshed }
129576404edcSAsim Jamshed }
129676404edcSAsim Jamshed aval = b->val[A_ATOM];
129776404edcSAsim Jamshed xval = b->val[X_ATOM];
129876404edcSAsim Jamshed for (s = b->stmts; s; s = s->next)
129976404edcSAsim Jamshed opt_stmt(&s->s, b->val, do_stmts);
130076404edcSAsim Jamshed
130176404edcSAsim Jamshed /*
130276404edcSAsim Jamshed * This is a special case: if we don't use anything from this
130376404edcSAsim Jamshed * block, and we load the accumulator or index register with a
130476404edcSAsim Jamshed * value that is already there, or if this block is a return,
130576404edcSAsim Jamshed * eliminate all the statements.
130676404edcSAsim Jamshed *
130776404edcSAsim Jamshed * XXX - what if it does a store?
130876404edcSAsim Jamshed *
130976404edcSAsim Jamshed * XXX - why does it matter whether we use anything from this
131076404edcSAsim Jamshed * block? If the accumulator or index register doesn't change
131176404edcSAsim Jamshed * its value, isn't that OK even if we use that value?
131276404edcSAsim Jamshed *
131376404edcSAsim Jamshed * XXX - if we load the accumulator with a different value,
131476404edcSAsim Jamshed * and the block ends with a conditional branch, we obviously
131576404edcSAsim Jamshed * can't eliminate it, as the branch depends on that value.
131676404edcSAsim Jamshed * For the index register, the conditional branch only depends
131776404edcSAsim Jamshed * on the index register value if the test is against the index
131876404edcSAsim Jamshed * register value rather than a constant; if nothing uses the
131976404edcSAsim Jamshed * value we put into the index register, and we're not testing
132076404edcSAsim Jamshed * against the index register's value, and there aren't any
132176404edcSAsim Jamshed * other problems that would keep us from eliminating this
132276404edcSAsim Jamshed * block, can we eliminate it?
132376404edcSAsim Jamshed */
132476404edcSAsim Jamshed if (do_stmts &&
132576404edcSAsim Jamshed ((b->out_use == 0 && aval != 0 && b->val[A_ATOM] == aval &&
132676404edcSAsim Jamshed xval != 0 && b->val[X_ATOM] == xval) || BPF_CLASS(b->s.code) == BPF_RET))
132776404edcSAsim Jamshed {
132876404edcSAsim Jamshed if (b->stmts != 0)
132976404edcSAsim Jamshed {
133076404edcSAsim Jamshed b->stmts = 0;
133176404edcSAsim Jamshed done = 0;
133276404edcSAsim Jamshed }
133376404edcSAsim Jamshed }
133476404edcSAsim Jamshed else
133576404edcSAsim Jamshed {
133676404edcSAsim Jamshed opt_peep(b);
133776404edcSAsim Jamshed opt_deadstores(b);
133876404edcSAsim Jamshed }
133976404edcSAsim Jamshed /*
134076404edcSAsim Jamshed * Set up values for branch optimizer.
134176404edcSAsim Jamshed */
134276404edcSAsim Jamshed if (BPF_SRC(b->s.code) == BPF_K)
134376404edcSAsim Jamshed b->oval = K(b->s.k);
134476404edcSAsim Jamshed else
134576404edcSAsim Jamshed b->oval = b->val[X_ATOM];
134676404edcSAsim Jamshed b->et.code = b->s.code;
134776404edcSAsim Jamshed b->ef.code = -b->s.code;
134876404edcSAsim Jamshed }
134976404edcSAsim Jamshed
135076404edcSAsim Jamshed /*
135176404edcSAsim Jamshed * Return true if any register that is used on exit from 'succ', has
135276404edcSAsim Jamshed * an exit value that is different from the corresponding exit value
135376404edcSAsim Jamshed * from 'b'.
135476404edcSAsim Jamshed */
use_conflict(b,succ)135576404edcSAsim Jamshed static int use_conflict(b, succ)
135676404edcSAsim Jamshed struct block *b, *succ;
135776404edcSAsim Jamshed {
135876404edcSAsim Jamshed int atom;
135976404edcSAsim Jamshed atomset use = succ->out_use;
136076404edcSAsim Jamshed
136176404edcSAsim Jamshed if (use == 0)
136276404edcSAsim Jamshed return 0;
136376404edcSAsim Jamshed
136476404edcSAsim Jamshed for (atom = 0; atom < N_ATOMS; ++atom)
136576404edcSAsim Jamshed if (ATOMELEM(use, atom))
136676404edcSAsim Jamshed if (b->val[atom] != succ->val[atom])
136776404edcSAsim Jamshed return 1;
136876404edcSAsim Jamshed return 0;
136976404edcSAsim Jamshed }
137076404edcSAsim Jamshed
fold_edge(child,ep)137176404edcSAsim Jamshed static struct block *fold_edge(child, ep)
137276404edcSAsim Jamshed struct block *child;
137376404edcSAsim Jamshed struct edge *ep;
137476404edcSAsim Jamshed {
137576404edcSAsim Jamshed int sense;
137676404edcSAsim Jamshed int aval0, aval1, oval0, oval1;
137776404edcSAsim Jamshed int code = ep->code;
137876404edcSAsim Jamshed
137976404edcSAsim Jamshed if (code < 0)
138076404edcSAsim Jamshed {
138176404edcSAsim Jamshed code = -code;
138276404edcSAsim Jamshed sense = 0;
138376404edcSAsim Jamshed }
138476404edcSAsim Jamshed else
138576404edcSAsim Jamshed sense = 1;
138676404edcSAsim Jamshed
138776404edcSAsim Jamshed if (child->s.code != code)
138876404edcSAsim Jamshed return 0;
138976404edcSAsim Jamshed
139076404edcSAsim Jamshed aval0 = child->val[A_ATOM];
139176404edcSAsim Jamshed oval0 = child->oval;
139276404edcSAsim Jamshed aval1 = ep->pred->val[A_ATOM];
139376404edcSAsim Jamshed oval1 = ep->pred->oval;
139476404edcSAsim Jamshed
139576404edcSAsim Jamshed if (aval0 != aval1)
139676404edcSAsim Jamshed return 0;
139776404edcSAsim Jamshed
139876404edcSAsim Jamshed if (oval0 == oval1)
139976404edcSAsim Jamshed /*
140076404edcSAsim Jamshed * The operands of the branch instructions are
140176404edcSAsim Jamshed * identical, so the result is true if a true
140276404edcSAsim Jamshed * branch was taken to get here, otherwise false.
140376404edcSAsim Jamshed */
140476404edcSAsim Jamshed return sense ? JT(child) : JF(child);
140576404edcSAsim Jamshed
140676404edcSAsim Jamshed if (sense && code == (BPF_JMP | BPF_JEQ | BPF_K))
140776404edcSAsim Jamshed /*
140876404edcSAsim Jamshed * At this point, we only know the comparison if we
140976404edcSAsim Jamshed * came down the true branch, and it was an equality
141076404edcSAsim Jamshed * comparison with a constant.
141176404edcSAsim Jamshed *
141276404edcSAsim Jamshed * I.e., if we came down the true branch, and the branch
141376404edcSAsim Jamshed * was an equality comparison with a constant, we know the
141476404edcSAsim Jamshed * accumulator contains that constant. If we came down
141576404edcSAsim Jamshed * the false branch, or the comparison wasn't with a
141676404edcSAsim Jamshed * constant, we don't know what was in the accumulator.
141776404edcSAsim Jamshed *
141876404edcSAsim Jamshed * We rely on the fact that distinct constants have distinct
141976404edcSAsim Jamshed * value numbers.
142076404edcSAsim Jamshed */
142176404edcSAsim Jamshed return JF(child);
142276404edcSAsim Jamshed
142376404edcSAsim Jamshed return 0;
142476404edcSAsim Jamshed }
142576404edcSAsim Jamshed
opt_j(ep)142676404edcSAsim Jamshed static void opt_j(ep)
142776404edcSAsim Jamshed struct edge *ep;
142876404edcSAsim Jamshed {
142976404edcSAsim Jamshed register int i, k;
143076404edcSAsim Jamshed register struct block *target;
143176404edcSAsim Jamshed
143276404edcSAsim Jamshed if (JT(ep->succ) == 0)
143376404edcSAsim Jamshed return;
143476404edcSAsim Jamshed
143576404edcSAsim Jamshed if (JT(ep->succ) == JF(ep->succ))
143676404edcSAsim Jamshed {
143776404edcSAsim Jamshed /*
143876404edcSAsim Jamshed * Common branch targets can be eliminated, provided
143976404edcSAsim Jamshed * there is no data dependency.
144076404edcSAsim Jamshed */
144176404edcSAsim Jamshed if (!use_conflict(ep->pred, ep->succ->et.succ))
144276404edcSAsim Jamshed {
144376404edcSAsim Jamshed done = 0;
144476404edcSAsim Jamshed ep->succ = JT(ep->succ);
144576404edcSAsim Jamshed }
144676404edcSAsim Jamshed }
144776404edcSAsim Jamshed /*
144876404edcSAsim Jamshed * For each edge dominator that matches the successor of this
144976404edcSAsim Jamshed * edge, promote the edge successor to the its grandchild.
145076404edcSAsim Jamshed *
145176404edcSAsim Jamshed * XXX We violate the set abstraction here in favor a reasonably
145276404edcSAsim Jamshed * efficient loop.
145376404edcSAsim Jamshed */
145476404edcSAsim Jamshed top:
145576404edcSAsim Jamshed for (i = 0; i < edgewords; ++i)
145676404edcSAsim Jamshed {
145776404edcSAsim Jamshed register bpf_u_int32 x = ep->edom[i];
145876404edcSAsim Jamshed
145976404edcSAsim Jamshed while (x != 0)
146076404edcSAsim Jamshed {
146176404edcSAsim Jamshed k = ffs(x) - 1;
146276404edcSAsim Jamshed x &= ~(1 << k);
146376404edcSAsim Jamshed k += i * BITS_PER_WORD;
146476404edcSAsim Jamshed
146576404edcSAsim Jamshed target = fold_edge(ep->succ, edges[k]);
146676404edcSAsim Jamshed /*
146776404edcSAsim Jamshed * Check that there is no data dependency between
146876404edcSAsim Jamshed * nodes that will be violated if we move the edge.
146976404edcSAsim Jamshed */
147076404edcSAsim Jamshed if (target != 0 && !use_conflict(ep->pred, target))
147176404edcSAsim Jamshed {
147276404edcSAsim Jamshed done = 0;
147376404edcSAsim Jamshed ep->succ = target;
147476404edcSAsim Jamshed if (JT(target) != 0)
147576404edcSAsim Jamshed /*
147676404edcSAsim Jamshed * Start over unless we hit a leaf.
147776404edcSAsim Jamshed */
147876404edcSAsim Jamshed goto top;
147976404edcSAsim Jamshed return;
148076404edcSAsim Jamshed }
148176404edcSAsim Jamshed }
148276404edcSAsim Jamshed }
148376404edcSAsim Jamshed }
148476404edcSAsim Jamshed
148576404edcSAsim Jamshed
or_pullup(b)148676404edcSAsim Jamshed static void or_pullup(b)
148776404edcSAsim Jamshed struct block *b;
148876404edcSAsim Jamshed {
148976404edcSAsim Jamshed int val, at_top;
149076404edcSAsim Jamshed struct block *pull;
149176404edcSAsim Jamshed struct block **diffp, **samep;
149276404edcSAsim Jamshed struct edge *ep;
149376404edcSAsim Jamshed
149476404edcSAsim Jamshed ep = b->in_edges;
149576404edcSAsim Jamshed if (ep == 0)
149676404edcSAsim Jamshed return;
149776404edcSAsim Jamshed
149876404edcSAsim Jamshed /*
149976404edcSAsim Jamshed * Make sure each predecessor loads the same value.
150076404edcSAsim Jamshed * XXX why?
150176404edcSAsim Jamshed */
150276404edcSAsim Jamshed val = ep->pred->val[A_ATOM];
150376404edcSAsim Jamshed for (ep = ep->next; ep != 0; ep = ep->next)
150476404edcSAsim Jamshed if (val != ep->pred->val[A_ATOM])
150576404edcSAsim Jamshed return;
150676404edcSAsim Jamshed
150776404edcSAsim Jamshed if (JT(b->in_edges->pred) == b)
150876404edcSAsim Jamshed diffp = &JT(b->in_edges->pred);
150976404edcSAsim Jamshed else
151076404edcSAsim Jamshed diffp = &JF(b->in_edges->pred);
151176404edcSAsim Jamshed
151276404edcSAsim Jamshed at_top = 1;
151376404edcSAsim Jamshed while (1)
151476404edcSAsim Jamshed {
151576404edcSAsim Jamshed if (*diffp == 0)
151676404edcSAsim Jamshed return;
151776404edcSAsim Jamshed
151876404edcSAsim Jamshed if (JT(*diffp) != JT(b))
151976404edcSAsim Jamshed return;
152076404edcSAsim Jamshed
152176404edcSAsim Jamshed if (!SET_MEMBER((*diffp)->dom, b->id))
152276404edcSAsim Jamshed return;
152376404edcSAsim Jamshed
152476404edcSAsim Jamshed if ((*diffp)->val[A_ATOM] != val)
152576404edcSAsim Jamshed break;
152676404edcSAsim Jamshed
152776404edcSAsim Jamshed diffp = &JF(*diffp);
152876404edcSAsim Jamshed at_top = 0;
152976404edcSAsim Jamshed }
153076404edcSAsim Jamshed samep = &JF(*diffp);
153176404edcSAsim Jamshed while (1)
153276404edcSAsim Jamshed {
153376404edcSAsim Jamshed if (*samep == 0)
153476404edcSAsim Jamshed return;
153576404edcSAsim Jamshed
153676404edcSAsim Jamshed if (JT(*samep) != JT(b))
153776404edcSAsim Jamshed return;
153876404edcSAsim Jamshed
153976404edcSAsim Jamshed if (!SET_MEMBER((*samep)->dom, b->id))
154076404edcSAsim Jamshed return;
154176404edcSAsim Jamshed
154276404edcSAsim Jamshed if ((*samep)->val[A_ATOM] == val)
154376404edcSAsim Jamshed break;
154476404edcSAsim Jamshed
154576404edcSAsim Jamshed /* XXX Need to check that there are no data dependencies
154676404edcSAsim Jamshed between dp0 and dp1. Currently, the code generator
154776404edcSAsim Jamshed will not produce such dependencies. */
154876404edcSAsim Jamshed samep = &JF(*samep);
154976404edcSAsim Jamshed }
155076404edcSAsim Jamshed #ifdef notdef
155176404edcSAsim Jamshed /* XXX This doesn't cover everything. */
155276404edcSAsim Jamshed for (i = 0; i < N_ATOMS; ++i)
155376404edcSAsim Jamshed if ((*samep)->val[i] != pred->val[i])
155476404edcSAsim Jamshed return;
155576404edcSAsim Jamshed #endif
155676404edcSAsim Jamshed /* Pull up the node. */
155776404edcSAsim Jamshed pull = *samep;
155876404edcSAsim Jamshed *samep = JF(pull);
155976404edcSAsim Jamshed JF(pull) = *diffp;
156076404edcSAsim Jamshed
156176404edcSAsim Jamshed /*
156276404edcSAsim Jamshed * At the top of the chain, each predecessor needs to point at the
156376404edcSAsim Jamshed * pulled up node. Inside the chain, there is only one predecessor
156476404edcSAsim Jamshed * to worry about.
156576404edcSAsim Jamshed */
156676404edcSAsim Jamshed if (at_top)
156776404edcSAsim Jamshed {
156876404edcSAsim Jamshed for (ep = b->in_edges; ep != 0; ep = ep->next)
156976404edcSAsim Jamshed {
157076404edcSAsim Jamshed if (JT(ep->pred) == b)
157176404edcSAsim Jamshed JT(ep->pred) = pull;
157276404edcSAsim Jamshed else
157376404edcSAsim Jamshed JF(ep->pred) = pull;
157476404edcSAsim Jamshed }
157576404edcSAsim Jamshed }
157676404edcSAsim Jamshed else
157776404edcSAsim Jamshed *diffp = pull;
157876404edcSAsim Jamshed
157976404edcSAsim Jamshed done = 0;
158076404edcSAsim Jamshed }
158176404edcSAsim Jamshed
and_pullup(b)158276404edcSAsim Jamshed static void and_pullup(b)
158376404edcSAsim Jamshed struct block *b;
158476404edcSAsim Jamshed {
158576404edcSAsim Jamshed int val, at_top;
158676404edcSAsim Jamshed struct block *pull;
158776404edcSAsim Jamshed struct block **diffp, **samep;
158876404edcSAsim Jamshed struct edge *ep;
158976404edcSAsim Jamshed
159076404edcSAsim Jamshed ep = b->in_edges;
159176404edcSAsim Jamshed if (ep == 0)
159276404edcSAsim Jamshed return;
159376404edcSAsim Jamshed
159476404edcSAsim Jamshed /*
159576404edcSAsim Jamshed * Make sure each predecessor loads the same value.
159676404edcSAsim Jamshed */
159776404edcSAsim Jamshed val = ep->pred->val[A_ATOM];
159876404edcSAsim Jamshed for (ep = ep->next; ep != 0; ep = ep->next)
159976404edcSAsim Jamshed if (val != ep->pred->val[A_ATOM])
160076404edcSAsim Jamshed return;
160176404edcSAsim Jamshed
160276404edcSAsim Jamshed if (JT(b->in_edges->pred) == b)
160376404edcSAsim Jamshed diffp = &JT(b->in_edges->pred);
160476404edcSAsim Jamshed else
160576404edcSAsim Jamshed diffp = &JF(b->in_edges->pred);
160676404edcSAsim Jamshed
160776404edcSAsim Jamshed at_top = 1;
160876404edcSAsim Jamshed while (1)
160976404edcSAsim Jamshed {
161076404edcSAsim Jamshed if (*diffp == 0)
161176404edcSAsim Jamshed return;
161276404edcSAsim Jamshed
161376404edcSAsim Jamshed if (JF(*diffp) != JF(b))
161476404edcSAsim Jamshed return;
161576404edcSAsim Jamshed
161676404edcSAsim Jamshed if (!SET_MEMBER((*diffp)->dom, b->id))
161776404edcSAsim Jamshed return;
161876404edcSAsim Jamshed
161976404edcSAsim Jamshed if ((*diffp)->val[A_ATOM] != val)
162076404edcSAsim Jamshed break;
162176404edcSAsim Jamshed
162276404edcSAsim Jamshed diffp = &JT(*diffp);
162376404edcSAsim Jamshed at_top = 0;
162476404edcSAsim Jamshed }
162576404edcSAsim Jamshed samep = &JT(*diffp);
162676404edcSAsim Jamshed while (1)
162776404edcSAsim Jamshed {
162876404edcSAsim Jamshed if (*samep == 0)
162976404edcSAsim Jamshed return;
163076404edcSAsim Jamshed
163176404edcSAsim Jamshed if (JF(*samep) != JF(b))
163276404edcSAsim Jamshed return;
163376404edcSAsim Jamshed
163476404edcSAsim Jamshed if (!SET_MEMBER((*samep)->dom, b->id))
163576404edcSAsim Jamshed return;
163676404edcSAsim Jamshed
163776404edcSAsim Jamshed if ((*samep)->val[A_ATOM] == val)
163876404edcSAsim Jamshed break;
163976404edcSAsim Jamshed
164076404edcSAsim Jamshed /* XXX Need to check that there are no data dependencies
164176404edcSAsim Jamshed between diffp and samep. Currently, the code generator
164276404edcSAsim Jamshed will not produce such dependencies. */
164376404edcSAsim Jamshed samep = &JT(*samep);
164476404edcSAsim Jamshed }
164576404edcSAsim Jamshed #ifdef notdef
164676404edcSAsim Jamshed /* XXX This doesn't cover everything. */
164776404edcSAsim Jamshed for (i = 0; i < N_ATOMS; ++i)
164876404edcSAsim Jamshed if ((*samep)->val[i] != pred->val[i])
164976404edcSAsim Jamshed return;
165076404edcSAsim Jamshed #endif
165176404edcSAsim Jamshed /* Pull up the node. */
165276404edcSAsim Jamshed pull = *samep;
165376404edcSAsim Jamshed *samep = JT(pull);
165476404edcSAsim Jamshed JT(pull) = *diffp;
165576404edcSAsim Jamshed
165676404edcSAsim Jamshed /*
165776404edcSAsim Jamshed * At the top of the chain, each predecessor needs to point at the
165876404edcSAsim Jamshed * pulled up node. Inside the chain, there is only one predecessor
165976404edcSAsim Jamshed * to worry about.
166076404edcSAsim Jamshed */
166176404edcSAsim Jamshed if (at_top)
166276404edcSAsim Jamshed {
166376404edcSAsim Jamshed for (ep = b->in_edges; ep != 0; ep = ep->next)
166476404edcSAsim Jamshed {
166576404edcSAsim Jamshed if (JT(ep->pred) == b)
166676404edcSAsim Jamshed JT(ep->pred) = pull;
166776404edcSAsim Jamshed else
166876404edcSAsim Jamshed JF(ep->pred) = pull;
166976404edcSAsim Jamshed }
167076404edcSAsim Jamshed }
167176404edcSAsim Jamshed else
167276404edcSAsim Jamshed *diffp = pull;
167376404edcSAsim Jamshed
167476404edcSAsim Jamshed done = 0;
167576404edcSAsim Jamshed }
167676404edcSAsim Jamshed
opt_blks(root,do_stmts)167776404edcSAsim Jamshed static void opt_blks(root, do_stmts)
167876404edcSAsim Jamshed struct block *root;
167976404edcSAsim Jamshed int do_stmts;
168076404edcSAsim Jamshed {
168176404edcSAsim Jamshed int i, maxlevel;
168276404edcSAsim Jamshed struct block *p;
168376404edcSAsim Jamshed
168476404edcSAsim Jamshed init_val();
168576404edcSAsim Jamshed maxlevel = root->level;
168676404edcSAsim Jamshed
168776404edcSAsim Jamshed find_inedges(root);
168876404edcSAsim Jamshed for (i = maxlevel; i >= 0; --i)
168976404edcSAsim Jamshed for (p = levels[i]; p; p = p->link)
169076404edcSAsim Jamshed opt_blk(p, do_stmts);
169176404edcSAsim Jamshed
169276404edcSAsim Jamshed if (do_stmts)
169376404edcSAsim Jamshed /*
169476404edcSAsim Jamshed * No point trying to move branches; it can't possibly
169576404edcSAsim Jamshed * make a difference at this point.
169676404edcSAsim Jamshed */
169776404edcSAsim Jamshed return;
169876404edcSAsim Jamshed
169976404edcSAsim Jamshed for (i = 1; i <= maxlevel; ++i)
170076404edcSAsim Jamshed {
170176404edcSAsim Jamshed for (p = levels[i]; p; p = p->link)
170276404edcSAsim Jamshed {
170376404edcSAsim Jamshed opt_j(&p->et);
170476404edcSAsim Jamshed opt_j(&p->ef);
170576404edcSAsim Jamshed }
170676404edcSAsim Jamshed }
170776404edcSAsim Jamshed
170876404edcSAsim Jamshed find_inedges(root);
170976404edcSAsim Jamshed for (i = 1; i <= maxlevel; ++i)
171076404edcSAsim Jamshed {
171176404edcSAsim Jamshed for (p = levels[i]; p; p = p->link)
171276404edcSAsim Jamshed {
171376404edcSAsim Jamshed or_pullup(p);
171476404edcSAsim Jamshed and_pullup(p);
171576404edcSAsim Jamshed }
171676404edcSAsim Jamshed }
171776404edcSAsim Jamshed }
171876404edcSAsim Jamshed
link_inedge(parent,child)171976404edcSAsim Jamshed static inline void link_inedge(parent, child)
172076404edcSAsim Jamshed struct edge *parent;
172176404edcSAsim Jamshed struct block *child;
172276404edcSAsim Jamshed {
172376404edcSAsim Jamshed parent->next = child->in_edges;
172476404edcSAsim Jamshed child->in_edges = parent;
172576404edcSAsim Jamshed }
172676404edcSAsim Jamshed
find_inedges(root)172776404edcSAsim Jamshed static void find_inedges(root)
172876404edcSAsim Jamshed struct block *root;
172976404edcSAsim Jamshed {
173076404edcSAsim Jamshed int i;
173176404edcSAsim Jamshed struct block *b;
173276404edcSAsim Jamshed
173376404edcSAsim Jamshed for (i = 0; i < n_blocks; ++i)
173476404edcSAsim Jamshed blocks[i]->in_edges = 0;
173576404edcSAsim Jamshed
173676404edcSAsim Jamshed /*
173776404edcSAsim Jamshed * Traverse the graph, adding each edge to the predecessor
173876404edcSAsim Jamshed * list of its successors. Skip the leaves (i.e. level 0).
173976404edcSAsim Jamshed */
174076404edcSAsim Jamshed for (i = root->level; i > 0; --i)
174176404edcSAsim Jamshed {
174276404edcSAsim Jamshed for (b = levels[i]; b != 0; b = b->link)
174376404edcSAsim Jamshed {
174476404edcSAsim Jamshed link_inedge(&b->et, JT(b));
174576404edcSAsim Jamshed link_inedge(&b->ef, JF(b));
174676404edcSAsim Jamshed }
174776404edcSAsim Jamshed }
174876404edcSAsim Jamshed }
174976404edcSAsim Jamshed
opt_root(b)175076404edcSAsim Jamshed static void opt_root(b)
175176404edcSAsim Jamshed struct block **b;
175276404edcSAsim Jamshed {
175376404edcSAsim Jamshed struct slist *tmp, *s;
175476404edcSAsim Jamshed
175576404edcSAsim Jamshed s = (*b)->stmts;
175676404edcSAsim Jamshed (*b)->stmts = 0;
175776404edcSAsim Jamshed while (BPF_CLASS((*b)->s.code) == BPF_JMP && JT(*b) == JF(*b))
175876404edcSAsim Jamshed *b = JT(*b);
175976404edcSAsim Jamshed
176076404edcSAsim Jamshed tmp = (*b)->stmts;
176176404edcSAsim Jamshed if (tmp != 0)
176276404edcSAsim Jamshed sappend(s, tmp);
176376404edcSAsim Jamshed (*b)->stmts = s;
176476404edcSAsim Jamshed
176576404edcSAsim Jamshed /*
176676404edcSAsim Jamshed * If the root node is a return, then there is no
176776404edcSAsim Jamshed * point executing any statements (since the bpf machine
176876404edcSAsim Jamshed * has no side effects).
176976404edcSAsim Jamshed */
177076404edcSAsim Jamshed if (BPF_CLASS((*b)->s.code) == BPF_RET)
177176404edcSAsim Jamshed (*b)->stmts = 0;
177276404edcSAsim Jamshed }
177376404edcSAsim Jamshed
opt_loop(root,do_stmts)177476404edcSAsim Jamshed static void opt_loop(root, do_stmts)
177576404edcSAsim Jamshed struct block *root;
177676404edcSAsim Jamshed int do_stmts;
177776404edcSAsim Jamshed {
177876404edcSAsim Jamshed
177976404edcSAsim Jamshed #ifdef BDEBUG
178076404edcSAsim Jamshed if (dflag > 1)
178176404edcSAsim Jamshed {
178276404edcSAsim Jamshed printf("opt_loop(root, %d) begin\n", do_stmts);
178376404edcSAsim Jamshed opt_dump(root);
178476404edcSAsim Jamshed }
178576404edcSAsim Jamshed #endif
178676404edcSAsim Jamshed do
178776404edcSAsim Jamshed {
178876404edcSAsim Jamshed done = 1;
178976404edcSAsim Jamshed find_levels(root);
179076404edcSAsim Jamshed find_dom(root);
179176404edcSAsim Jamshed find_closure(root);
179276404edcSAsim Jamshed find_ud(root);
179376404edcSAsim Jamshed find_edom(root);
179476404edcSAsim Jamshed opt_blks(root, do_stmts);
179576404edcSAsim Jamshed #ifdef BDEBUG
179676404edcSAsim Jamshed if (dflag > 1)
179776404edcSAsim Jamshed {
179876404edcSAsim Jamshed printf("opt_loop(root, %d) bottom, done=%d\n", do_stmts, done);
179976404edcSAsim Jamshed opt_dump(root);
180076404edcSAsim Jamshed }
180176404edcSAsim Jamshed #endif
180276404edcSAsim Jamshed } while (!done);
180376404edcSAsim Jamshed }
180476404edcSAsim Jamshed
180576404edcSAsim Jamshed /*
180676404edcSAsim Jamshed * Optimize the filter code in its dag representation.
180776404edcSAsim Jamshed */
bpf_optimize(rootp)180876404edcSAsim Jamshed void bpf_optimize(rootp)
180976404edcSAsim Jamshed struct block **rootp;
181076404edcSAsim Jamshed {
181176404edcSAsim Jamshed struct block *root;
181276404edcSAsim Jamshed
181376404edcSAsim Jamshed root = *rootp;
181476404edcSAsim Jamshed
181576404edcSAsim Jamshed opt_init(root);
181676404edcSAsim Jamshed opt_loop(root, 0);
181776404edcSAsim Jamshed opt_loop(root, 1);
181876404edcSAsim Jamshed intern_blocks(root);
181976404edcSAsim Jamshed #ifdef BDEBUG
182076404edcSAsim Jamshed if (dflag > 1)
182176404edcSAsim Jamshed {
182276404edcSAsim Jamshed printf("after intern_blocks()\n");
182376404edcSAsim Jamshed opt_dump(root);
182476404edcSAsim Jamshed }
182576404edcSAsim Jamshed #endif
182676404edcSAsim Jamshed opt_root(rootp);
182776404edcSAsim Jamshed #ifdef BDEBUG
182876404edcSAsim Jamshed if (dflag > 1)
182976404edcSAsim Jamshed {
183076404edcSAsim Jamshed printf("after opt_root()\n");
183176404edcSAsim Jamshed opt_dump(root);
183276404edcSAsim Jamshed }
183376404edcSAsim Jamshed #endif
183476404edcSAsim Jamshed opt_cleanup();
183576404edcSAsim Jamshed }
183676404edcSAsim Jamshed
make_marks(p)183776404edcSAsim Jamshed static void make_marks(p)
183876404edcSAsim Jamshed struct block *p;
183976404edcSAsim Jamshed {
184076404edcSAsim Jamshed if (!isMarked(p))
184176404edcSAsim Jamshed {
184276404edcSAsim Jamshed Mark(p);
184376404edcSAsim Jamshed if (BPF_CLASS(p->s.code) != BPF_RET)
184476404edcSAsim Jamshed {
184576404edcSAsim Jamshed make_marks(JT(p));
184676404edcSAsim Jamshed make_marks(JF(p));
184776404edcSAsim Jamshed }
184876404edcSAsim Jamshed }
184976404edcSAsim Jamshed }
185076404edcSAsim Jamshed
185176404edcSAsim Jamshed /*
185276404edcSAsim Jamshed * Mark code array such that isMarked(i) is true
185376404edcSAsim Jamshed * only for nodes that are alive.
185476404edcSAsim Jamshed */
mark_code(p)185576404edcSAsim Jamshed static void mark_code(p)
185676404edcSAsim Jamshed struct block *p;
185776404edcSAsim Jamshed {
185876404edcSAsim Jamshed cur_mark += 1;
185976404edcSAsim Jamshed make_marks(p);
186076404edcSAsim Jamshed }
186176404edcSAsim Jamshed
186276404edcSAsim Jamshed /*
186376404edcSAsim Jamshed * True iff the two stmt lists load the same value from the packet into
186476404edcSAsim Jamshed * the accumulator.
186576404edcSAsim Jamshed */
eq_slist(x,y)186676404edcSAsim Jamshed static int eq_slist(x, y)
186776404edcSAsim Jamshed struct slist *x, *y;
186876404edcSAsim Jamshed {
186976404edcSAsim Jamshed while (1)
187076404edcSAsim Jamshed {
187176404edcSAsim Jamshed while (x && x->s.code == NOP)
187276404edcSAsim Jamshed x = x->next;
187376404edcSAsim Jamshed while (y && y->s.code == NOP)
187476404edcSAsim Jamshed y = y->next;
187576404edcSAsim Jamshed if (x == 0)
187676404edcSAsim Jamshed return y == 0;
187776404edcSAsim Jamshed if (y == 0)
187876404edcSAsim Jamshed return x == 0;
187976404edcSAsim Jamshed if (x->s.code != y->s.code || x->s.k != y->s.k)
188076404edcSAsim Jamshed return 0;
188176404edcSAsim Jamshed x = x->next;
188276404edcSAsim Jamshed y = y->next;
188376404edcSAsim Jamshed }
188476404edcSAsim Jamshed }
188576404edcSAsim Jamshed
eq_blk(b0,b1)188676404edcSAsim Jamshed static inline int eq_blk(b0, b1)
188776404edcSAsim Jamshed struct block *b0, *b1;
188876404edcSAsim Jamshed {
188976404edcSAsim Jamshed if (b0->s.code == b1->s.code &&
189076404edcSAsim Jamshed b0->s.k == b1->s.k && b0->et.succ == b1->et.succ && b0->ef.succ == b1->ef.succ)
189176404edcSAsim Jamshed return eq_slist(b0->stmts, b1->stmts);
189276404edcSAsim Jamshed return 0;
189376404edcSAsim Jamshed }
189476404edcSAsim Jamshed
intern_blocks(root)189576404edcSAsim Jamshed static void intern_blocks(root)
189676404edcSAsim Jamshed struct block *root;
189776404edcSAsim Jamshed {
189876404edcSAsim Jamshed struct block *p;
189976404edcSAsim Jamshed int i, j;
190076404edcSAsim Jamshed int done1; /* don't shadow global */
190176404edcSAsim Jamshed top:
190276404edcSAsim Jamshed done1 = 1;
190376404edcSAsim Jamshed for (i = 0; i < n_blocks; ++i)
190476404edcSAsim Jamshed blocks[i]->link = 0;
190576404edcSAsim Jamshed
190676404edcSAsim Jamshed mark_code(root);
190776404edcSAsim Jamshed
190876404edcSAsim Jamshed for (i = n_blocks - 1; --i >= 0;)
190976404edcSAsim Jamshed {
191076404edcSAsim Jamshed if (!isMarked(blocks[i]))
191176404edcSAsim Jamshed continue;
191276404edcSAsim Jamshed for (j = i + 1; j < n_blocks; ++j)
191376404edcSAsim Jamshed {
191476404edcSAsim Jamshed if (!isMarked(blocks[j]))
191576404edcSAsim Jamshed continue;
191676404edcSAsim Jamshed if (eq_blk(blocks[i], blocks[j]))
191776404edcSAsim Jamshed {
191876404edcSAsim Jamshed blocks[i]->link = blocks[j]->link ? blocks[j]->link : blocks[j];
191976404edcSAsim Jamshed break;
192076404edcSAsim Jamshed }
192176404edcSAsim Jamshed }
192276404edcSAsim Jamshed }
192376404edcSAsim Jamshed for (i = 0; i < n_blocks; ++i)
192476404edcSAsim Jamshed {
192576404edcSAsim Jamshed p = blocks[i];
192676404edcSAsim Jamshed if (JT(p) == 0)
192776404edcSAsim Jamshed continue;
192876404edcSAsim Jamshed if (JT(p)->link)
192976404edcSAsim Jamshed {
193076404edcSAsim Jamshed done1 = 0;
193176404edcSAsim Jamshed JT(p) = JT(p)->link;
193276404edcSAsim Jamshed }
193376404edcSAsim Jamshed if (JF(p)->link)
193476404edcSAsim Jamshed {
193576404edcSAsim Jamshed done1 = 0;
193676404edcSAsim Jamshed JF(p) = JF(p)->link;
193776404edcSAsim Jamshed }
193876404edcSAsim Jamshed }
193976404edcSAsim Jamshed if (!done1)
194076404edcSAsim Jamshed goto top;
194176404edcSAsim Jamshed }
194276404edcSAsim Jamshed
opt_cleanup()194376404edcSAsim Jamshed static void opt_cleanup()
194476404edcSAsim Jamshed {
194576404edcSAsim Jamshed free((void *) vnode_base);
194676404edcSAsim Jamshed free((void *) vmap);
194776404edcSAsim Jamshed free((void *) edges);
194876404edcSAsim Jamshed free((void *) space);
194976404edcSAsim Jamshed free((void *) levels);
195076404edcSAsim Jamshed free((void *) blocks);
195176404edcSAsim Jamshed }
195276404edcSAsim Jamshed
195376404edcSAsim Jamshed /*
195476404edcSAsim Jamshed * Return the number of stmts in 's'.
195576404edcSAsim Jamshed */
slength(s)195676404edcSAsim Jamshed static int slength(s)
195776404edcSAsim Jamshed struct slist *s;
195876404edcSAsim Jamshed {
195976404edcSAsim Jamshed int n = 0;
196076404edcSAsim Jamshed
196176404edcSAsim Jamshed for (; s; s = s->next)
196276404edcSAsim Jamshed if (s->s.code != NOP)
196376404edcSAsim Jamshed ++n;
196476404edcSAsim Jamshed return n;
196576404edcSAsim Jamshed }
196676404edcSAsim Jamshed
196776404edcSAsim Jamshed /*
196876404edcSAsim Jamshed * Return the number of nodes reachable by 'p'.
196976404edcSAsim Jamshed * All nodes should be initially unmarked.
197076404edcSAsim Jamshed */
count_blocks(p)197176404edcSAsim Jamshed static int count_blocks(p)
197276404edcSAsim Jamshed struct block *p;
197376404edcSAsim Jamshed {
197476404edcSAsim Jamshed if (p == 0 || isMarked(p))
197576404edcSAsim Jamshed return 0;
197676404edcSAsim Jamshed Mark(p);
197776404edcSAsim Jamshed return count_blocks(JT(p)) + count_blocks(JF(p)) + 1;
197876404edcSAsim Jamshed }
197976404edcSAsim Jamshed
198076404edcSAsim Jamshed /*
198176404edcSAsim Jamshed * Do a depth first search on the flow graph, numbering the
198276404edcSAsim Jamshed * the basic blocks, and entering them into the 'blocks' array.`
198376404edcSAsim Jamshed */
number_blks_r(p)198476404edcSAsim Jamshed static void number_blks_r(p)
198576404edcSAsim Jamshed struct block *p;
198676404edcSAsim Jamshed {
198776404edcSAsim Jamshed int n;
198876404edcSAsim Jamshed
198976404edcSAsim Jamshed if (p == 0 || isMarked(p))
199076404edcSAsim Jamshed return;
199176404edcSAsim Jamshed
199276404edcSAsim Jamshed Mark(p);
199376404edcSAsim Jamshed n = n_blocks++;
199476404edcSAsim Jamshed p->id = n;
199576404edcSAsim Jamshed blocks[n] = p;
199676404edcSAsim Jamshed
199776404edcSAsim Jamshed number_blks_r(JT(p));
199876404edcSAsim Jamshed number_blks_r(JF(p));
199976404edcSAsim Jamshed }
200076404edcSAsim Jamshed
200176404edcSAsim Jamshed /*
200276404edcSAsim Jamshed * Return the number of stmts in the flowgraph reachable by 'p'.
200376404edcSAsim Jamshed * The nodes should be unmarked before calling.
200476404edcSAsim Jamshed *
200576404edcSAsim Jamshed * Note that "stmts" means "instructions", and that this includes
200676404edcSAsim Jamshed *
200776404edcSAsim Jamshed * side-effect statements in 'p' (slength(p->stmts));
200876404edcSAsim Jamshed *
200976404edcSAsim Jamshed * statements in the true branch from 'p' (count_stmts(JT(p)));
201076404edcSAsim Jamshed *
201176404edcSAsim Jamshed * statements in the false branch from 'p' (count_stmts(JF(p)));
201276404edcSAsim Jamshed *
201376404edcSAsim Jamshed * the conditional jump itself (1);
201476404edcSAsim Jamshed *
201576404edcSAsim Jamshed * an extra long jump if the true branch requires it (p->longjt);
201676404edcSAsim Jamshed *
201776404edcSAsim Jamshed * an extra long jump if the false branch requires it (p->longjf).
201876404edcSAsim Jamshed */
count_stmts(p)201976404edcSAsim Jamshed static int count_stmts(p)
202076404edcSAsim Jamshed struct block *p;
202176404edcSAsim Jamshed {
202276404edcSAsim Jamshed int n;
202376404edcSAsim Jamshed
202476404edcSAsim Jamshed if (p == 0 || isMarked(p))
202576404edcSAsim Jamshed return 0;
202676404edcSAsim Jamshed Mark(p);
202776404edcSAsim Jamshed n = count_stmts(JT(p)) + count_stmts(JF(p));
202876404edcSAsim Jamshed return slength(p->stmts) + n + 1 + p->longjt + p->longjf;
202976404edcSAsim Jamshed }
203076404edcSAsim Jamshed
203176404edcSAsim Jamshed /*
203276404edcSAsim Jamshed * Allocate memory. All allocation is done before optimization
203376404edcSAsim Jamshed * is begun. A linear bound on the size of all data structures is computed
203476404edcSAsim Jamshed * from the total number of blocks and/or statements.
203576404edcSAsim Jamshed */
opt_init(root)203676404edcSAsim Jamshed static void opt_init(root)
203776404edcSAsim Jamshed struct block *root;
203876404edcSAsim Jamshed {
203976404edcSAsim Jamshed bpf_u_int32 *p;
204076404edcSAsim Jamshed int i, n, max_stmts;
204176404edcSAsim Jamshed
204276404edcSAsim Jamshed /*
204376404edcSAsim Jamshed * First, count the blocks, so we can malloc an array to map
204476404edcSAsim Jamshed * block number to block. Then, put the blocks into the array.
204576404edcSAsim Jamshed */
204676404edcSAsim Jamshed unMarkAll();
204776404edcSAsim Jamshed n = count_blocks(root);
204876404edcSAsim Jamshed blocks = (struct block **) calloc(n, sizeof(*blocks));
204976404edcSAsim Jamshed if (blocks == NULL)
205076404edcSAsim Jamshed bpf_error("malloc");
205176404edcSAsim Jamshed unMarkAll();
205276404edcSAsim Jamshed n_blocks = 0;
205376404edcSAsim Jamshed number_blks_r(root);
205476404edcSAsim Jamshed
205576404edcSAsim Jamshed n_edges = 2 * n_blocks;
205676404edcSAsim Jamshed edges = (struct edge **) calloc(n_edges, sizeof(*edges));
205776404edcSAsim Jamshed if (edges == NULL)
205876404edcSAsim Jamshed bpf_error("malloc");
205976404edcSAsim Jamshed
206076404edcSAsim Jamshed /*
206176404edcSAsim Jamshed * The number of levels is bounded by the number of nodes.
206276404edcSAsim Jamshed */
206376404edcSAsim Jamshed levels = (struct block **) calloc(n_blocks, sizeof(*levels));
206476404edcSAsim Jamshed if (levels == NULL)
206576404edcSAsim Jamshed bpf_error("malloc");
206676404edcSAsim Jamshed
206776404edcSAsim Jamshed edgewords = n_edges / (8 * sizeof(bpf_u_int32)) + 1;
206876404edcSAsim Jamshed nodewords = n_blocks / (8 * sizeof(bpf_u_int32)) + 1;
206976404edcSAsim Jamshed
207076404edcSAsim Jamshed /* XXX */
207176404edcSAsim Jamshed space = (bpf_u_int32 *) malloc(2 * n_blocks * nodewords * sizeof(*space)
207276404edcSAsim Jamshed + n_edges * edgewords * sizeof(*space));
207376404edcSAsim Jamshed if (space == NULL)
207476404edcSAsim Jamshed bpf_error("malloc");
207576404edcSAsim Jamshed p = space;
207676404edcSAsim Jamshed all_dom_sets = p;
207776404edcSAsim Jamshed for (i = 0; i < n; ++i)
207876404edcSAsim Jamshed {
207976404edcSAsim Jamshed blocks[i]->dom = p;
208076404edcSAsim Jamshed p += nodewords;
208176404edcSAsim Jamshed }
208276404edcSAsim Jamshed all_closure_sets = p;
208376404edcSAsim Jamshed for (i = 0; i < n; ++i)
208476404edcSAsim Jamshed {
208576404edcSAsim Jamshed blocks[i]->closure = p;
208676404edcSAsim Jamshed p += nodewords;
208776404edcSAsim Jamshed }
208876404edcSAsim Jamshed all_edge_sets = p;
208976404edcSAsim Jamshed for (i = 0; i < n; ++i)
209076404edcSAsim Jamshed {
209176404edcSAsim Jamshed register struct block *b = blocks[i];
209276404edcSAsim Jamshed
209376404edcSAsim Jamshed b->et.edom = p;
209476404edcSAsim Jamshed p += edgewords;
209576404edcSAsim Jamshed b->ef.edom = p;
209676404edcSAsim Jamshed p += edgewords;
209776404edcSAsim Jamshed b->et.id = i;
209876404edcSAsim Jamshed edges[i] = &b->et;
209976404edcSAsim Jamshed b->ef.id = n_blocks + i;
210076404edcSAsim Jamshed edges[n_blocks + i] = &b->ef;
210176404edcSAsim Jamshed b->et.pred = b;
210276404edcSAsim Jamshed b->ef.pred = b;
210376404edcSAsim Jamshed }
210476404edcSAsim Jamshed max_stmts = 0;
210576404edcSAsim Jamshed for (i = 0; i < n; ++i)
210676404edcSAsim Jamshed max_stmts += slength(blocks[i]->stmts) + 1;
210776404edcSAsim Jamshed /*
210876404edcSAsim Jamshed * We allocate at most 3 value numbers per statement,
210976404edcSAsim Jamshed * so this is an upper bound on the number of valnodes
211076404edcSAsim Jamshed * we'll need.
211176404edcSAsim Jamshed */
211276404edcSAsim Jamshed maxval = 3 * max_stmts;
211376404edcSAsim Jamshed vmap = (struct vmapinfo *) calloc(maxval, sizeof(*vmap));
211476404edcSAsim Jamshed vnode_base = (struct valnode *) calloc(maxval, sizeof(*vnode_base));
211576404edcSAsim Jamshed if (vmap == NULL || vnode_base == NULL)
211676404edcSAsim Jamshed bpf_error("malloc");
211776404edcSAsim Jamshed }
211876404edcSAsim Jamshed
211976404edcSAsim Jamshed /*
212076404edcSAsim Jamshed * Some pointers used to convert the basic block form of the code,
212176404edcSAsim Jamshed * into the array form that BPF requires. 'fstart' will point to
212276404edcSAsim Jamshed * the malloc'd array while 'ftail' is used during the recursive traversal.
212376404edcSAsim Jamshed */
212476404edcSAsim Jamshed static __thread struct bpf_insn *fstart;
212576404edcSAsim Jamshed static __thread struct bpf_insn *ftail;
212676404edcSAsim Jamshed
212776404edcSAsim Jamshed #ifdef BDEBUG
212876404edcSAsim Jamshed int bids[1000];
212976404edcSAsim Jamshed #endif
213076404edcSAsim Jamshed
213176404edcSAsim Jamshed /*
213276404edcSAsim Jamshed * Returns true if successful. Returns false if a branch has
213376404edcSAsim Jamshed * an offset that is too large. If so, we have marked that
213476404edcSAsim Jamshed * branch so that on a subsequent iteration, it will be treated
213576404edcSAsim Jamshed * properly.
213676404edcSAsim Jamshed */
convert_code_r(p)213776404edcSAsim Jamshed static int convert_code_r(p)
213876404edcSAsim Jamshed struct block *p;
213976404edcSAsim Jamshed {
214076404edcSAsim Jamshed struct bpf_insn *dst;
214176404edcSAsim Jamshed struct slist *src;
214276404edcSAsim Jamshed int slen;
214376404edcSAsim Jamshed u_int off;
214476404edcSAsim Jamshed int extrajmps; /* number of extra jumps inserted */
214576404edcSAsim Jamshed struct slist **offset = NULL;
214676404edcSAsim Jamshed
214776404edcSAsim Jamshed if (p == 0 || isMarked(p))
214876404edcSAsim Jamshed return (1);
214976404edcSAsim Jamshed Mark(p);
215076404edcSAsim Jamshed
215176404edcSAsim Jamshed if (convert_code_r(JF(p)) == 0)
215276404edcSAsim Jamshed return (0);
215376404edcSAsim Jamshed if (convert_code_r(JT(p)) == 0)
215476404edcSAsim Jamshed return (0);
215576404edcSAsim Jamshed
215676404edcSAsim Jamshed slen = slength(p->stmts);
215776404edcSAsim Jamshed dst = ftail -= (slen + 1 + p->longjt + p->longjf);
215876404edcSAsim Jamshed /* inflate length by any extra jumps */
215976404edcSAsim Jamshed
216076404edcSAsim Jamshed p->offset = dst - fstart;
216176404edcSAsim Jamshed
216276404edcSAsim Jamshed /* generate offset[] for convenience */
216376404edcSAsim Jamshed if (slen)
216476404edcSAsim Jamshed {
216576404edcSAsim Jamshed offset = (struct slist **) calloc(slen, sizeof(struct slist *));
216676404edcSAsim Jamshed if (!offset)
216776404edcSAsim Jamshed {
216876404edcSAsim Jamshed bpf_error("not enough core");
216976404edcSAsim Jamshed /*NOTREACHED*/}
217076404edcSAsim Jamshed }
217176404edcSAsim Jamshed src = p->stmts;
217276404edcSAsim Jamshed for (off = 0; off < slen && src; off++)
217376404edcSAsim Jamshed {
217476404edcSAsim Jamshed #if YYDEBUG
217576404edcSAsim Jamshed printf("off=%d src=%x\n", off, src);
217676404edcSAsim Jamshed #endif
217776404edcSAsim Jamshed offset[off] = src;
217876404edcSAsim Jamshed src = src->next;
217976404edcSAsim Jamshed }
218076404edcSAsim Jamshed
218176404edcSAsim Jamshed off = 0;
218276404edcSAsim Jamshed for (src = p->stmts; src; src = src->next)
218376404edcSAsim Jamshed {
218476404edcSAsim Jamshed if (src->s.code == NOP)
218576404edcSAsim Jamshed continue;
218676404edcSAsim Jamshed dst->code = (u_short) src->s.code;
218776404edcSAsim Jamshed dst->k = src->s.k;
218876404edcSAsim Jamshed
218976404edcSAsim Jamshed /* fill block-local relative jump */
219076404edcSAsim Jamshed if (BPF_CLASS(src->s.code) != BPF_JMP || src->s.code == (BPF_JMP | BPF_JA))
219176404edcSAsim Jamshed {
219276404edcSAsim Jamshed #if YYDEBUG
219376404edcSAsim Jamshed if (src->s.jt || src->s.jf)
219476404edcSAsim Jamshed {
219576404edcSAsim Jamshed bpf_error("illegal jmp destination");
219676404edcSAsim Jamshed /*NOTREACHED*/}
219776404edcSAsim Jamshed #endif
219876404edcSAsim Jamshed goto filled;
219976404edcSAsim Jamshed }
220076404edcSAsim Jamshed if (off == slen - 2) /*??? */
220176404edcSAsim Jamshed goto filled;
220276404edcSAsim Jamshed
220376404edcSAsim Jamshed {
220476404edcSAsim Jamshed int i;
220576404edcSAsim Jamshed int jt, jf;
220676404edcSAsim Jamshed const char *ljerr = "%s for block-local relative jump: off=%d";
220776404edcSAsim Jamshed
220876404edcSAsim Jamshed #if YYDEBUG
220976404edcSAsim Jamshed printf("code=%x off=%d %x %x\n", src->s.code, off, src->s.jt, src->s.jf);
221076404edcSAsim Jamshed #endif
221176404edcSAsim Jamshed
221276404edcSAsim Jamshed if (!src->s.jt || !src->s.jf)
221376404edcSAsim Jamshed {
221476404edcSAsim Jamshed bpf_error(ljerr, "no jmp destination", off);
221576404edcSAsim Jamshed /*NOTREACHED*/}
221676404edcSAsim Jamshed
221776404edcSAsim Jamshed jt = jf = 0;
221876404edcSAsim Jamshed for (i = 0; i < slen; i++)
221976404edcSAsim Jamshed {
222076404edcSAsim Jamshed if (offset[i] == src->s.jt)
222176404edcSAsim Jamshed {
222276404edcSAsim Jamshed if (jt)
222376404edcSAsim Jamshed {
222476404edcSAsim Jamshed bpf_error(ljerr, "multiple matches", off);
222576404edcSAsim Jamshed /*NOTREACHED*/}
222676404edcSAsim Jamshed
222776404edcSAsim Jamshed dst->jt = i - off - 1;
222876404edcSAsim Jamshed jt++;
222976404edcSAsim Jamshed }
223076404edcSAsim Jamshed if (offset[i] == src->s.jf)
223176404edcSAsim Jamshed {
223276404edcSAsim Jamshed if (jf)
223376404edcSAsim Jamshed {
223476404edcSAsim Jamshed bpf_error(ljerr, "multiple matches", off);
223576404edcSAsim Jamshed /*NOTREACHED*/}
223676404edcSAsim Jamshed dst->jf = i - off - 1;
223776404edcSAsim Jamshed jf++;
223876404edcSAsim Jamshed }
223976404edcSAsim Jamshed }
224076404edcSAsim Jamshed if (!jt || !jf)
224176404edcSAsim Jamshed {
224276404edcSAsim Jamshed bpf_error(ljerr, "no destination found", off);
224376404edcSAsim Jamshed /*NOTREACHED*/}
224476404edcSAsim Jamshed }
224576404edcSAsim Jamshed filled:
224676404edcSAsim Jamshed ++dst;
224776404edcSAsim Jamshed ++off;
224876404edcSAsim Jamshed }
224976404edcSAsim Jamshed if (offset)
225076404edcSAsim Jamshed free(offset);
225176404edcSAsim Jamshed
225276404edcSAsim Jamshed #ifdef BDEBUG
225376404edcSAsim Jamshed bids[dst - fstart] = p->id + 1;
225476404edcSAsim Jamshed #endif
225576404edcSAsim Jamshed dst->code = (u_short) p->s.code;
225676404edcSAsim Jamshed dst->k = p->s.k;
225776404edcSAsim Jamshed if (JT(p))
225876404edcSAsim Jamshed {
225976404edcSAsim Jamshed extrajmps = 0;
226076404edcSAsim Jamshed off = JT(p)->offset - (p->offset + slen) - 1;
226176404edcSAsim Jamshed if (off >= 256)
226276404edcSAsim Jamshed {
226376404edcSAsim Jamshed /* offset too large for branch, must add a jump */
226476404edcSAsim Jamshed if (p->longjt == 0)
226576404edcSAsim Jamshed {
226676404edcSAsim Jamshed /* mark this instruction and retry */
226776404edcSAsim Jamshed p->longjt++;
226876404edcSAsim Jamshed return (0);
226976404edcSAsim Jamshed }
227076404edcSAsim Jamshed /* branch if T to following jump */
227176404edcSAsim Jamshed dst->jt = extrajmps;
227276404edcSAsim Jamshed extrajmps++;
227376404edcSAsim Jamshed dst[extrajmps].code = BPF_JMP | BPF_JA;
227476404edcSAsim Jamshed dst[extrajmps].k = off - extrajmps;
227576404edcSAsim Jamshed }
227676404edcSAsim Jamshed else
227776404edcSAsim Jamshed dst->jt = off;
227876404edcSAsim Jamshed off = JF(p)->offset - (p->offset + slen) - 1;
227976404edcSAsim Jamshed if (off >= 256)
228076404edcSAsim Jamshed {
228176404edcSAsim Jamshed /* offset too large for branch, must add a jump */
228276404edcSAsim Jamshed if (p->longjf == 0)
228376404edcSAsim Jamshed {
228476404edcSAsim Jamshed /* mark this instruction and retry */
228576404edcSAsim Jamshed p->longjf++;
228676404edcSAsim Jamshed return (0);
228776404edcSAsim Jamshed }
228876404edcSAsim Jamshed /* branch if F to following jump */
228976404edcSAsim Jamshed /* if two jumps are inserted, F goes to second one */
229076404edcSAsim Jamshed dst->jf = extrajmps;
229176404edcSAsim Jamshed extrajmps++;
229276404edcSAsim Jamshed dst[extrajmps].code = BPF_JMP | BPF_JA;
229376404edcSAsim Jamshed dst[extrajmps].k = off - extrajmps;
229476404edcSAsim Jamshed }
229576404edcSAsim Jamshed else
229676404edcSAsim Jamshed dst->jf = off;
229776404edcSAsim Jamshed }
229876404edcSAsim Jamshed return (1);
229976404edcSAsim Jamshed }
230076404edcSAsim Jamshed
230176404edcSAsim Jamshed
230276404edcSAsim Jamshed /*
230376404edcSAsim Jamshed * Convert flowgraph intermediate representation to the
230476404edcSAsim Jamshed * BPF array representation. Set *lenp to the number of instructions.
230576404edcSAsim Jamshed *
230676404edcSAsim Jamshed * This routine does *NOT* leak the memory pointed to by fp. It *must
230776404edcSAsim Jamshed * not* do free(fp) before returning fp; doing so would make no sense,
230876404edcSAsim Jamshed * as the BPF array pointed to by the return value of icode_to_fcode()
230976404edcSAsim Jamshed * must be valid - it's being returned for use in a bpf_program structure.
231076404edcSAsim Jamshed *
231176404edcSAsim Jamshed * If it appears that icode_to_fcode() is leaking, the problem is that
231276404edcSAsim Jamshed * the program using pcap_compile() is failing to free the memory in
231376404edcSAsim Jamshed * the BPF program when it's done - the leak is in the program, not in
231476404edcSAsim Jamshed * the routine that happens to be allocating the memory. (By analogy, if
231576404edcSAsim Jamshed * a program calls fopen() without ever calling fclose() on the FILE *,
231676404edcSAsim Jamshed * it will leak the FILE structure; the leak is not in fopen(), it's in
231776404edcSAsim Jamshed * the program.) Change the program to use pcap_freecode() when it's
231876404edcSAsim Jamshed * done with the filter program. See the pcap man page.
231976404edcSAsim Jamshed */
icode_to_fcode(root,lenp)232076404edcSAsim Jamshed struct bpf_insn *icode_to_fcode(root, lenp)
232176404edcSAsim Jamshed struct block *root;
232276404edcSAsim Jamshed int *lenp;
232376404edcSAsim Jamshed {
232476404edcSAsim Jamshed int n;
232576404edcSAsim Jamshed struct bpf_insn *fp;
232676404edcSAsim Jamshed
232776404edcSAsim Jamshed /*
232876404edcSAsim Jamshed * Loop doing convert_code_r() until no branches remain
232976404edcSAsim Jamshed * with too-large offsets.
233076404edcSAsim Jamshed */
233176404edcSAsim Jamshed while (1)
233276404edcSAsim Jamshed {
233376404edcSAsim Jamshed unMarkAll();
233476404edcSAsim Jamshed n = *lenp = count_stmts(root);
233576404edcSAsim Jamshed
233676404edcSAsim Jamshed fp = (struct bpf_insn *) malloc(sizeof(*fp) * n);
233776404edcSAsim Jamshed if (fp == NULL)
233876404edcSAsim Jamshed bpf_error("malloc");
233976404edcSAsim Jamshed memset((char *) fp, 0, sizeof(*fp) * n);
234076404edcSAsim Jamshed fstart = fp;
234176404edcSAsim Jamshed ftail = fp + n;
234276404edcSAsim Jamshed
234376404edcSAsim Jamshed unMarkAll();
234476404edcSAsim Jamshed if (convert_code_r(root))
234576404edcSAsim Jamshed break;
234676404edcSAsim Jamshed free(fp);
234776404edcSAsim Jamshed }
234876404edcSAsim Jamshed
234976404edcSAsim Jamshed return fp;
235076404edcSAsim Jamshed }
235176404edcSAsim Jamshed
235276404edcSAsim Jamshed #ifdef BDEBUG
opt_dump(root)235376404edcSAsim Jamshed static void opt_dump(root)
235476404edcSAsim Jamshed struct block *root;
235576404edcSAsim Jamshed {
235676404edcSAsim Jamshed struct bpf_program f;
235776404edcSAsim Jamshed
235876404edcSAsim Jamshed memset(bids, 0, sizeof bids);
235976404edcSAsim Jamshed f.bf_insns = icode_to_fcode(root, &f.bf_len);
236076404edcSAsim Jamshed bpf_dump(&f, 1);
236176404edcSAsim Jamshed putchar('\n');
236276404edcSAsim Jamshed free((char *) f.bf_insns);
236376404edcSAsim Jamshed }
236476404edcSAsim Jamshed #endif
2365