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