xref: /openbsd-src/lib/libpcap/optimize.c (revision 146262ea791a2220a609c41b0b0e51b0a23d9c67)
1*146262eaSjsg /*	$OpenBSD: optimize.c,v 1.23 2024/04/08 02:51:14 jsg Exp $	*/
2df930be7Sderaadt 
3df930be7Sderaadt /*
49b113833Smickey  * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994, 1995, 1996
5df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
6df930be7Sderaadt  *
7df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
8df930be7Sderaadt  * modification, are permitted provided that: (1) source code distributions
9df930be7Sderaadt  * retain the above copyright notice and this paragraph in its entirety, (2)
10df930be7Sderaadt  * distributions including binary code include the above copyright notice and
11df930be7Sderaadt  * this paragraph in its entirety in the documentation or other materials
12df930be7Sderaadt  * provided with the distribution, and (3) all advertising materials mentioning
13df930be7Sderaadt  * features or use of this software display the following acknowledgement:
14df930be7Sderaadt  * ``This product includes software developed by the University of California,
15df930be7Sderaadt  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16df930be7Sderaadt  * the University nor the names of its contributors may be used to endorse
17df930be7Sderaadt  * or promote products derived from this software without specific prior
18df930be7Sderaadt  * written permission.
19df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20df930be7Sderaadt  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21df930be7Sderaadt  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22df930be7Sderaadt  *
23df930be7Sderaadt  *  Optimization module for tcpdump intermediate representation.
24df930be7Sderaadt  */
25df930be7Sderaadt 
26df930be7Sderaadt #include <sys/types.h>
27df930be7Sderaadt #include <sys/time.h>
28df930be7Sderaadt 
29df930be7Sderaadt #include <stdio.h>
30df930be7Sderaadt #include <stdlib.h>
3149639a4cSderaadt #include <stdint.h>
323a9b5ec4Smmcc #include <string.h>
33df930be7Sderaadt 
3401efc7efSderaadt #include "pcap-int.h"
3501efc7efSderaadt 
3601efc7efSderaadt #include "gencode.h"
3701efc7efSderaadt 
389b113833Smickey #ifdef HAVE_OS_PROTO_H
399b113833Smickey #include "os-proto.h"
409b113833Smickey #endif
419b113833Smickey 
429b113833Smickey #ifdef BDEBUG
439b113833Smickey extern int dflag;
44df930be7Sderaadt #endif
45df930be7Sderaadt 
46df930be7Sderaadt #define A_ATOM BPF_MEMWORDS
47df930be7Sderaadt #define X_ATOM (BPF_MEMWORDS+1)
48df930be7Sderaadt 
49df930be7Sderaadt #define NOP -1
50df930be7Sderaadt 
51df930be7Sderaadt /*
52df930be7Sderaadt  * This define is used to represent *both* the accumulator and
53df930be7Sderaadt  * x register in use-def computations.
54df930be7Sderaadt  * Currently, the use-def code assumes only one definition per instruction.
55df930be7Sderaadt  */
56df930be7Sderaadt #define AX_ATOM N_ATOMS
57df930be7Sderaadt 
58df930be7Sderaadt /*
59df930be7Sderaadt  * A flag to indicate that further optimization is needed.
60df930be7Sderaadt  * Iterative passes are continued until a given pass yields no
61df930be7Sderaadt  * branch movement.
62df930be7Sderaadt  */
63df930be7Sderaadt static int done;
64df930be7Sderaadt 
65df930be7Sderaadt /*
66df930be7Sderaadt  * A block is marked if only if its mark equals the current mark.
67df930be7Sderaadt  * Rather than traverse the code array, marking each item, 'cur_mark' is
68df930be7Sderaadt  * incremented.  This automatically makes each element unmarked.
69df930be7Sderaadt  */
70df930be7Sderaadt static int cur_mark;
71df930be7Sderaadt #define isMarked(p) ((p)->mark == cur_mark)
72df930be7Sderaadt #define unMarkAll() cur_mark += 1
73df930be7Sderaadt #define Mark(p) ((p)->mark = cur_mark)
74df930be7Sderaadt 
75df930be7Sderaadt static void opt_init(struct block *);
76df930be7Sderaadt static void opt_cleanup(void);
77df930be7Sderaadt 
78df930be7Sderaadt static void make_marks(struct block *);
79df930be7Sderaadt static void mark_code(struct block *);
80df930be7Sderaadt 
81df930be7Sderaadt static void intern_blocks(struct block *);
82df930be7Sderaadt 
83df930be7Sderaadt static int eq_slist(struct slist *, struct slist *);
84df930be7Sderaadt 
85df930be7Sderaadt static void find_levels_r(struct block *);
86df930be7Sderaadt 
87df930be7Sderaadt static void find_levels(struct block *);
88df930be7Sderaadt static void find_dom(struct block *);
89df930be7Sderaadt static void propedom(struct edge *);
90df930be7Sderaadt static void find_edom(struct block *);
91df930be7Sderaadt static void find_closure(struct block *);
92df930be7Sderaadt static int atomuse(struct stmt *);
93df930be7Sderaadt static int atomdef(struct stmt *);
94df930be7Sderaadt static void compute_local_ud(struct block *);
95df930be7Sderaadt static void find_ud(struct block *);
96df930be7Sderaadt static void init_val(void);
979b113833Smickey static int F(int, int, int);
988df16311Stholo static __inline void vstore(struct stmt *, int *, int, int);
99df930be7Sderaadt static void opt_blk(struct block *, int);
100df930be7Sderaadt static int use_conflict(struct block *, struct block *);
101df930be7Sderaadt static void opt_j(struct edge *);
102df930be7Sderaadt static void or_pullup(struct block *);
103df930be7Sderaadt static void and_pullup(struct block *);
104df930be7Sderaadt static void opt_blks(struct block *, int);
1058df16311Stholo static __inline void link_inedge(struct edge *, struct block *);
106df930be7Sderaadt static void find_inedges(struct block *);
107df930be7Sderaadt static void opt_root(struct block **);
108df930be7Sderaadt static void opt_loop(struct block *, int);
1099b113833Smickey static void fold_op(struct stmt *, int, int);
1108df16311Stholo static __inline struct slist *this_op(struct slist *);
111df930be7Sderaadt static void opt_not(struct block *);
112df930be7Sderaadt static void opt_peep(struct block *);
1139b113833Smickey static void opt_stmt(struct stmt *, int[], int);
114df930be7Sderaadt static void deadstmt(struct stmt *, struct stmt *[]);
115df930be7Sderaadt static void opt_deadstores(struct block *);
116df930be7Sderaadt static void opt_blk(struct block *, int);
117df930be7Sderaadt static int use_conflict(struct block *, struct block *);
118df930be7Sderaadt static void opt_j(struct edge *);
119df930be7Sderaadt static struct block *fold_edge(struct block *, struct edge *);
1208df16311Stholo static __inline int eq_blk(struct block *, struct block *);
121df930be7Sderaadt static int slength(struct slist *);
122df930be7Sderaadt static int count_blocks(struct block *);
123df930be7Sderaadt static void number_blks_r(struct block *);
124df930be7Sderaadt static int count_stmts(struct block *);
1259b113833Smickey static int convert_code_r(struct block *);
1269b113833Smickey #ifdef BDEBUG
1279b113833Smickey static void opt_dump(struct block *);
1289b113833Smickey #endif
129df930be7Sderaadt 
130df930be7Sderaadt static int n_blocks;
131df930be7Sderaadt struct block **blocks;
132df930be7Sderaadt static int n_edges;
133df930be7Sderaadt struct edge **edges;
134df930be7Sderaadt 
135df930be7Sderaadt /*
136df930be7Sderaadt  * A bit vector set representation of the dominators.
137df930be7Sderaadt  * We round up the set size to the next power of two.
138df930be7Sderaadt  */
139df930be7Sderaadt static int nodewords;
140df930be7Sderaadt static int edgewords;
141df930be7Sderaadt struct block **levels;
14249639a4cSderaadt bpf_u_int32 *space1;
14349639a4cSderaadt bpf_u_int32 *space2;
1449b113833Smickey #define BITS_PER_WORD (8*sizeof(bpf_u_int32))
145df930be7Sderaadt /*
146df930be7Sderaadt  * True if a is in uset {p}
147df930be7Sderaadt  */
148df930be7Sderaadt #define SET_MEMBER(p, a) \
149df930be7Sderaadt ((p)[(unsigned)(a) / BITS_PER_WORD] & (1 << ((unsigned)(a) % BITS_PER_WORD)))
150df930be7Sderaadt 
151df930be7Sderaadt /*
152df930be7Sderaadt  * Add 'a' to uset p.
153df930be7Sderaadt  */
154df930be7Sderaadt #define SET_INSERT(p, a) \
155df930be7Sderaadt (p)[(unsigned)(a) / BITS_PER_WORD] |= (1 << ((unsigned)(a) % BITS_PER_WORD))
156df930be7Sderaadt 
157df930be7Sderaadt /*
158df930be7Sderaadt  * Delete 'a' from uset p.
159df930be7Sderaadt  */
160df930be7Sderaadt #define SET_DELETE(p, a) \
161df930be7Sderaadt (p)[(unsigned)(a) / BITS_PER_WORD] &= ~(1 << ((unsigned)(a) % BITS_PER_WORD))
162df930be7Sderaadt 
163df930be7Sderaadt /*
164df930be7Sderaadt  * a := a intersect b
165df930be7Sderaadt  */
166df930be7Sderaadt #define SET_INTERSECT(a, b, n)\
167df930be7Sderaadt {\
168d0438536Smmcc 	bpf_u_int32 *_x = a, *_y = b;\
169d0438536Smmcc 	int _n = n;\
170df930be7Sderaadt 	while (--_n >= 0) *_x++ &= *_y++;\
171df930be7Sderaadt }
172df930be7Sderaadt 
173df930be7Sderaadt /*
174df930be7Sderaadt  * a := a - b
175df930be7Sderaadt  */
176df930be7Sderaadt #define SET_SUBTRACT(a, b, n)\
177df930be7Sderaadt {\
178d0438536Smmcc 	bpf_u_int32 *_x = a, *_y = b;\
179d0438536Smmcc 	int _n = n;\
180df930be7Sderaadt 	while (--_n >= 0) *_x++ &=~ *_y++;\
181df930be7Sderaadt }
182df930be7Sderaadt 
183df930be7Sderaadt /*
184df930be7Sderaadt  * a := a union b
185df930be7Sderaadt  */
186df930be7Sderaadt #define SET_UNION(a, b, n)\
187df930be7Sderaadt {\
188d0438536Smmcc 	bpf_u_int32 *_x = a, *_y = b;\
189d0438536Smmcc 	int _n = n;\
190df930be7Sderaadt 	while (--_n >= 0) *_x++ |= *_y++;\
191df930be7Sderaadt }
192df930be7Sderaadt 
193df930be7Sderaadt static uset all_dom_sets;
194df930be7Sderaadt static uset all_closure_sets;
195df930be7Sderaadt static uset all_edge_sets;
196df930be7Sderaadt 
197df930be7Sderaadt #ifndef MAX
198df930be7Sderaadt #define MAX(a,b) ((a)>(b)?(a):(b))
199df930be7Sderaadt #endif
200df930be7Sderaadt 
201df930be7Sderaadt static void
find_levels_r(struct block * b)20219fef815Sderaadt find_levels_r(struct block *b)
203df930be7Sderaadt {
204df930be7Sderaadt 	int level;
205df930be7Sderaadt 
206df930be7Sderaadt 	if (isMarked(b))
207df930be7Sderaadt 		return;
208df930be7Sderaadt 
209df930be7Sderaadt 	Mark(b);
210df930be7Sderaadt 	b->link = 0;
211df930be7Sderaadt 
212df930be7Sderaadt 	if (JT(b)) {
213df930be7Sderaadt 		find_levels_r(JT(b));
214df930be7Sderaadt 		find_levels_r(JF(b));
215df930be7Sderaadt 		level = MAX(JT(b)->level, JF(b)->level) + 1;
216df930be7Sderaadt 	} else
217df930be7Sderaadt 		level = 0;
218df930be7Sderaadt 	b->level = level;
219df930be7Sderaadt 	b->link = levels[level];
220df930be7Sderaadt 	levels[level] = b;
221df930be7Sderaadt }
222df930be7Sderaadt 
223df930be7Sderaadt /*
224df930be7Sderaadt  * Level graph.  The levels go from 0 at the leaves to
225df930be7Sderaadt  * N_LEVELS at the root.  The levels[] array points to the
226df930be7Sderaadt  * first node of the level list, whose elements are linked
227df930be7Sderaadt  * with the 'link' field of the struct block.
228df930be7Sderaadt  */
229df930be7Sderaadt static void
find_levels(struct block * root)23019fef815Sderaadt find_levels(struct block *root)
231df930be7Sderaadt {
232df930be7Sderaadt 	memset((char *)levels, 0, n_blocks * sizeof(*levels));
233df930be7Sderaadt 	unMarkAll();
234df930be7Sderaadt 	find_levels_r(root);
235df930be7Sderaadt }
236df930be7Sderaadt 
237df930be7Sderaadt /*
238df930be7Sderaadt  * Find dominator relationships.
239df930be7Sderaadt  * Assumes graph has been leveled.
240df930be7Sderaadt  */
241df930be7Sderaadt static void
find_dom(struct block * root)24219fef815Sderaadt find_dom(struct block *root)
243df930be7Sderaadt {
244df930be7Sderaadt 	int i;
245df930be7Sderaadt 	struct block *b;
2469b113833Smickey 	bpf_u_int32 *x;
247df930be7Sderaadt 
248df930be7Sderaadt 	/*
249df930be7Sderaadt 	 * Initialize sets to contain all nodes.
250df930be7Sderaadt 	 */
251df930be7Sderaadt 	x = all_dom_sets;
252df930be7Sderaadt 	i = n_blocks * nodewords;
253df930be7Sderaadt 	while (--i >= 0)
254df930be7Sderaadt 		*x++ = ~0;
255df930be7Sderaadt 	/* Root starts off empty. */
256df930be7Sderaadt 	for (i = nodewords; --i >= 0;)
257df930be7Sderaadt 		root->dom[i] = 0;
258df930be7Sderaadt 
259df930be7Sderaadt 	/* root->level is the highest level no found. */
260df930be7Sderaadt 	for (i = root->level; i >= 0; --i) {
261df930be7Sderaadt 		for (b = levels[i]; b; b = b->link) {
262df930be7Sderaadt 			SET_INSERT(b->dom, b->id);
263df930be7Sderaadt 			if (JT(b) == 0)
264df930be7Sderaadt 				continue;
265df930be7Sderaadt 			SET_INTERSECT(JT(b)->dom, b->dom, nodewords);
266df930be7Sderaadt 			SET_INTERSECT(JF(b)->dom, b->dom, nodewords);
267df930be7Sderaadt 		}
268df930be7Sderaadt 	}
269df930be7Sderaadt }
270df930be7Sderaadt 
271df930be7Sderaadt static void
propedom(struct edge * ep)27219fef815Sderaadt propedom(struct edge *ep)
273df930be7Sderaadt {
274df930be7Sderaadt 	SET_INSERT(ep->edom, ep->id);
275df930be7Sderaadt 	if (ep->succ) {
276df930be7Sderaadt 		SET_INTERSECT(ep->succ->et.edom, ep->edom, edgewords);
277df930be7Sderaadt 		SET_INTERSECT(ep->succ->ef.edom, ep->edom, edgewords);
278df930be7Sderaadt 	}
279df930be7Sderaadt }
280df930be7Sderaadt 
281df930be7Sderaadt /*
282df930be7Sderaadt  * Compute edge dominators.
283df930be7Sderaadt  * Assumes graph has been leveled and predecessors established.
284df930be7Sderaadt  */
285df930be7Sderaadt static void
find_edom(struct block * root)28619fef815Sderaadt find_edom(struct block *root)
287df930be7Sderaadt {
288df930be7Sderaadt 	int i;
289df930be7Sderaadt 	uset x;
290df930be7Sderaadt 	struct block *b;
291df930be7Sderaadt 
292df930be7Sderaadt 	x = all_edge_sets;
293df930be7Sderaadt 	for (i = n_edges * edgewords; --i >= 0; )
294df930be7Sderaadt 		x[i] = ~0;
295df930be7Sderaadt 
296df930be7Sderaadt 	/* root->level is the highest level no found. */
297df930be7Sderaadt 	memset(root->et.edom, 0, edgewords * sizeof(*(uset)0));
298df930be7Sderaadt 	memset(root->ef.edom, 0, edgewords * sizeof(*(uset)0));
299df930be7Sderaadt 	for (i = root->level; i >= 0; --i) {
300df930be7Sderaadt 		for (b = levels[i]; b != 0; b = b->link) {
301df930be7Sderaadt 			propedom(&b->et);
302df930be7Sderaadt 			propedom(&b->ef);
303df930be7Sderaadt 		}
304df930be7Sderaadt 	}
305df930be7Sderaadt }
306df930be7Sderaadt 
307df930be7Sderaadt /*
308df930be7Sderaadt  * Find the backwards transitive closure of the flow graph.  These sets
309df930be7Sderaadt  * are backwards in the sense that we find the set of nodes that reach
310df930be7Sderaadt  * a given node, not the set of nodes that can be reached by a node.
311df930be7Sderaadt  *
312df930be7Sderaadt  * Assumes graph has been leveled.
313df930be7Sderaadt  */
314df930be7Sderaadt static void
find_closure(struct block * root)31519fef815Sderaadt find_closure(struct block *root)
316df930be7Sderaadt {
317df930be7Sderaadt 	int i;
318df930be7Sderaadt 	struct block *b;
319df930be7Sderaadt 
320df930be7Sderaadt 	/*
321df930be7Sderaadt 	 * Initialize sets to contain no nodes.
322df930be7Sderaadt 	 */
323df930be7Sderaadt 	memset((char *)all_closure_sets, 0,
324df930be7Sderaadt 	      n_blocks * nodewords * sizeof(*all_closure_sets));
325df930be7Sderaadt 
326df930be7Sderaadt 	/* root->level is the highest level no found. */
327df930be7Sderaadt 	for (i = root->level; i >= 0; --i) {
328df930be7Sderaadt 		for (b = levels[i]; b; b = b->link) {
329df930be7Sderaadt 			SET_INSERT(b->closure, b->id);
330df930be7Sderaadt 			if (JT(b) == 0)
331df930be7Sderaadt 				continue;
332df930be7Sderaadt 			SET_UNION(JT(b)->closure, b->closure, nodewords);
333df930be7Sderaadt 			SET_UNION(JF(b)->closure, b->closure, nodewords);
334df930be7Sderaadt 		}
335df930be7Sderaadt 	}
336df930be7Sderaadt }
337df930be7Sderaadt 
338df930be7Sderaadt /*
339df930be7Sderaadt  * Return the register number that is used by s.  If A and X are both
340df930be7Sderaadt  * used, return AX_ATOM.  If no register is used, return -1.
341df930be7Sderaadt  *
342df930be7Sderaadt  * The implementation should probably change to an array access.
343df930be7Sderaadt  */
344df930be7Sderaadt static int
atomuse(struct stmt * s)34519fef815Sderaadt atomuse(struct stmt *s)
346df930be7Sderaadt {
347d0438536Smmcc 	int c = s->code;
348df930be7Sderaadt 
349df930be7Sderaadt 	if (c == NOP)
350df930be7Sderaadt 		return -1;
351df930be7Sderaadt 
352df930be7Sderaadt 	switch (BPF_CLASS(c)) {
353df930be7Sderaadt 
354df930be7Sderaadt 	case BPF_RET:
355df930be7Sderaadt 		return (BPF_RVAL(c) == BPF_A) ? A_ATOM :
356df930be7Sderaadt 			(BPF_RVAL(c) == BPF_X) ? X_ATOM : -1;
357df930be7Sderaadt 
358df930be7Sderaadt 	case BPF_LD:
359df930be7Sderaadt 	case BPF_LDX:
360df930be7Sderaadt 		return (BPF_MODE(c) == BPF_IND) ? X_ATOM :
361df930be7Sderaadt 			(BPF_MODE(c) == BPF_MEM) ? s->k : -1;
362df930be7Sderaadt 
363df930be7Sderaadt 	case BPF_ST:
364df930be7Sderaadt 		return A_ATOM;
365df930be7Sderaadt 
366df930be7Sderaadt 	case BPF_STX:
367df930be7Sderaadt 		return X_ATOM;
368df930be7Sderaadt 
369df930be7Sderaadt 	case BPF_JMP:
370df930be7Sderaadt 	case BPF_ALU:
371df930be7Sderaadt 		if (BPF_SRC(c) == BPF_X)
372df930be7Sderaadt 			return AX_ATOM;
373df930be7Sderaadt 		return A_ATOM;
374df930be7Sderaadt 
375df930be7Sderaadt 	case BPF_MISC:
376df930be7Sderaadt 		return BPF_MISCOP(c) == BPF_TXA ? X_ATOM : A_ATOM;
377df930be7Sderaadt 	}
378df930be7Sderaadt 	abort();
379df930be7Sderaadt 	/* NOTREACHED */
380df930be7Sderaadt }
381df930be7Sderaadt 
382df930be7Sderaadt /*
383df930be7Sderaadt  * Return the register number that is defined by 's'.  We assume that
384df930be7Sderaadt  * a single stmt cannot define more than one register.  If no register
385df930be7Sderaadt  * is defined, return -1.
386df930be7Sderaadt  *
387df930be7Sderaadt  * The implementation should probably change to an array access.
388df930be7Sderaadt  */
389df930be7Sderaadt static int
atomdef(struct stmt * s)39019fef815Sderaadt atomdef(struct stmt *s)
391df930be7Sderaadt {
392df930be7Sderaadt 	if (s->code == NOP)
393df930be7Sderaadt 		return -1;
394df930be7Sderaadt 
395df930be7Sderaadt 	switch (BPF_CLASS(s->code)) {
396df930be7Sderaadt 
397df930be7Sderaadt 	case BPF_LD:
398df930be7Sderaadt 	case BPF_ALU:
399df930be7Sderaadt 		return A_ATOM;
400df930be7Sderaadt 
401df930be7Sderaadt 	case BPF_LDX:
402df930be7Sderaadt 		return X_ATOM;
403df930be7Sderaadt 
404df930be7Sderaadt 	case BPF_ST:
405df930be7Sderaadt 	case BPF_STX:
406df930be7Sderaadt 		return s->k;
407df930be7Sderaadt 
408df930be7Sderaadt 	case BPF_MISC:
409df930be7Sderaadt 		return BPF_MISCOP(s->code) == BPF_TAX ? X_ATOM : A_ATOM;
410df930be7Sderaadt 	}
411df930be7Sderaadt 	return -1;
412df930be7Sderaadt }
413df930be7Sderaadt 
414df930be7Sderaadt static void
compute_local_ud(struct block * b)41519fef815Sderaadt compute_local_ud(struct block *b)
416df930be7Sderaadt {
417df930be7Sderaadt 	struct slist *s;
418df930be7Sderaadt 	atomset def = 0, use = 0, kill = 0;
419df930be7Sderaadt 	int atom;
420df930be7Sderaadt 
421df930be7Sderaadt 	for (s = b->stmts; s; s = s->next) {
422df930be7Sderaadt 		if (s->s.code == NOP)
423df930be7Sderaadt 			continue;
424df930be7Sderaadt 		atom = atomuse(&s->s);
425df930be7Sderaadt 		if (atom >= 0) {
426df930be7Sderaadt 			if (atom == AX_ATOM) {
427df930be7Sderaadt 				if (!ATOMELEM(def, X_ATOM))
428df930be7Sderaadt 					use |= ATOMMASK(X_ATOM);
429df930be7Sderaadt 				if (!ATOMELEM(def, A_ATOM))
430df930be7Sderaadt 					use |= ATOMMASK(A_ATOM);
431df930be7Sderaadt 			}
432df930be7Sderaadt 			else if (atom < N_ATOMS) {
433df930be7Sderaadt 				if (!ATOMELEM(def, atom))
434df930be7Sderaadt 					use |= ATOMMASK(atom);
435df930be7Sderaadt 			}
436df930be7Sderaadt 			else
437df930be7Sderaadt 				abort();
438df930be7Sderaadt 		}
439df930be7Sderaadt 		atom = atomdef(&s->s);
440df930be7Sderaadt 		if (atom >= 0) {
441df930be7Sderaadt 			if (!ATOMELEM(use, atom))
442df930be7Sderaadt 				kill |= ATOMMASK(atom);
443df930be7Sderaadt 			def |= ATOMMASK(atom);
444df930be7Sderaadt 		}
445df930be7Sderaadt 	}
446df930be7Sderaadt 	if (!ATOMELEM(def, A_ATOM) && BPF_CLASS(b->s.code) == BPF_JMP)
447df930be7Sderaadt 		use |= ATOMMASK(A_ATOM);
448df930be7Sderaadt 
449df930be7Sderaadt 	b->def = def;
450df930be7Sderaadt 	b->kill = kill;
451df930be7Sderaadt 	b->in_use = use;
452df930be7Sderaadt }
453df930be7Sderaadt 
454df930be7Sderaadt /*
455df930be7Sderaadt  * Assume graph is already leveled.
456df930be7Sderaadt  */
457df930be7Sderaadt static void
find_ud(struct block * root)45819fef815Sderaadt find_ud(struct block *root)
459df930be7Sderaadt {
460df930be7Sderaadt 	int i, maxlevel;
461df930be7Sderaadt 	struct block *p;
462df930be7Sderaadt 
463df930be7Sderaadt 	/*
464df930be7Sderaadt 	 * root->level is the highest level no found;
465df930be7Sderaadt 	 * count down from there.
466df930be7Sderaadt 	 */
467df930be7Sderaadt 	maxlevel = root->level;
468df930be7Sderaadt 	for (i = maxlevel; i >= 0; --i)
469df930be7Sderaadt 		for (p = levels[i]; p; p = p->link) {
470df930be7Sderaadt 			compute_local_ud(p);
471df930be7Sderaadt 			p->out_use = 0;
472df930be7Sderaadt 		}
473df930be7Sderaadt 
474df930be7Sderaadt 	for (i = 1; i <= maxlevel; ++i) {
475df930be7Sderaadt 		for (p = levels[i]; p; p = p->link) {
476df930be7Sderaadt 			p->out_use |= JT(p)->in_use | JF(p)->in_use;
477df930be7Sderaadt 			p->in_use |= p->out_use &~ p->kill;
478df930be7Sderaadt 		}
479df930be7Sderaadt 	}
480df930be7Sderaadt }
481df930be7Sderaadt 
482df930be7Sderaadt /*
483df930be7Sderaadt  * These data structures are used in a Cocke and Shwarz style
484df930be7Sderaadt  * value numbering scheme.  Since the flowgraph is acyclic,
485df930be7Sderaadt  * exit values can be propagated from a node's predecessors
486df930be7Sderaadt  * provided it is uniquely defined.
487df930be7Sderaadt  */
488df930be7Sderaadt struct valnode {
489df930be7Sderaadt 	int code;
4909b113833Smickey 	int v0, v1;
4919b113833Smickey 	int val;
492df930be7Sderaadt 	struct valnode *next;
493df930be7Sderaadt };
494df930be7Sderaadt 
495df930be7Sderaadt #define MODULUS 213
496df930be7Sderaadt static struct valnode *hashtbl[MODULUS];
497df930be7Sderaadt static int curval;
498df930be7Sderaadt static int maxval;
499df930be7Sderaadt 
500df930be7Sderaadt /* Integer constants mapped with the load immediate opcode. */
501df930be7Sderaadt #define K(i) F(BPF_LD|BPF_IMM|BPF_W, i, 0L)
502df930be7Sderaadt 
503df930be7Sderaadt struct vmapinfo {
504df930be7Sderaadt 	int is_const;
5059b113833Smickey 	bpf_int32 const_val;
506df930be7Sderaadt };
507df930be7Sderaadt 
508df930be7Sderaadt struct vmapinfo *vmap;
509df930be7Sderaadt struct valnode *vnode_base;
510df930be7Sderaadt struct valnode *next_vnode;
511df930be7Sderaadt 
512df930be7Sderaadt static void
init_val(void)513*146262eaSjsg init_val(void)
514df930be7Sderaadt {
515df930be7Sderaadt 	curval = 0;
516df930be7Sderaadt 	next_vnode = vnode_base;
517df930be7Sderaadt 	memset((char *)vmap, 0, maxval * sizeof(*vmap));
518df930be7Sderaadt 	memset((char *)hashtbl, 0, sizeof hashtbl);
519df930be7Sderaadt }
520df930be7Sderaadt 
521df930be7Sderaadt /* Because we really don't have an IR, this stuff is a little messy. */
5229b113833Smickey static int
F(int code,int v0,int v1)52319fef815Sderaadt F(int code, int v0, int v1)
524df930be7Sderaadt {
525df930be7Sderaadt 	u_int hash;
526df930be7Sderaadt 	int val;
527df930be7Sderaadt 	struct valnode *p;
528df930be7Sderaadt 
529df930be7Sderaadt 	hash = (u_int)code ^ (v0 << 4) ^ (v1 << 8);
530df930be7Sderaadt 	hash %= MODULUS;
531df930be7Sderaadt 
532df930be7Sderaadt 	for (p = hashtbl[hash]; p; p = p->next)
533df930be7Sderaadt 		if (p->code == code && p->v0 == v0 && p->v1 == v1)
534df930be7Sderaadt 			return p->val;
535df930be7Sderaadt 
536df930be7Sderaadt 	val = ++curval;
537df930be7Sderaadt 	if (BPF_MODE(code) == BPF_IMM &&
538df930be7Sderaadt 	    (BPF_CLASS(code) == BPF_LD || BPF_CLASS(code) == BPF_LDX)) {
539df930be7Sderaadt 		vmap[val].const_val = v0;
540df930be7Sderaadt 		vmap[val].is_const = 1;
541df930be7Sderaadt 	}
542df930be7Sderaadt 	p = next_vnode++;
543df930be7Sderaadt 	p->val = val;
544df930be7Sderaadt 	p->code = code;
545df930be7Sderaadt 	p->v0 = v0;
546df930be7Sderaadt 	p->v1 = v1;
547df930be7Sderaadt 	p->next = hashtbl[hash];
548df930be7Sderaadt 	hashtbl[hash] = p;
549df930be7Sderaadt 
550df930be7Sderaadt 	return val;
551df930be7Sderaadt }
552df930be7Sderaadt 
5538df16311Stholo static __inline void
vstore(struct stmt * s,int * valp,int newval,int alter)55419fef815Sderaadt vstore(struct stmt *s, int *valp, int newval, int alter)
555df930be7Sderaadt {
556df930be7Sderaadt 	if (alter && *valp == newval)
557df930be7Sderaadt 		s->code = NOP;
558df930be7Sderaadt 	else
559df930be7Sderaadt 		*valp = newval;
560df930be7Sderaadt }
561df930be7Sderaadt 
562df930be7Sderaadt static void
fold_op(struct stmt * s,int v0,int v1)56319fef815Sderaadt fold_op(struct stmt *s, int v0, int v1)
564df930be7Sderaadt {
5659b113833Smickey 	bpf_int32 a, b;
566df930be7Sderaadt 
567df930be7Sderaadt 	a = vmap[v0].const_val;
568df930be7Sderaadt 	b = vmap[v1].const_val;
569df930be7Sderaadt 
570df930be7Sderaadt 	switch (BPF_OP(s->code)) {
571df930be7Sderaadt 	case BPF_ADD:
572df930be7Sderaadt 		a += b;
573df930be7Sderaadt 		break;
574df930be7Sderaadt 
575df930be7Sderaadt 	case BPF_SUB:
576df930be7Sderaadt 		a -= b;
577df930be7Sderaadt 		break;
578df930be7Sderaadt 
579df930be7Sderaadt 	case BPF_MUL:
580df930be7Sderaadt 		a *= b;
581df930be7Sderaadt 		break;
582df930be7Sderaadt 
583df930be7Sderaadt 	case BPF_DIV:
584df930be7Sderaadt 		if (b == 0)
585df930be7Sderaadt 			bpf_error("division by zero");
586df930be7Sderaadt 		a /= b;
587df930be7Sderaadt 		break;
588df930be7Sderaadt 
589df930be7Sderaadt 	case BPF_AND:
590df930be7Sderaadt 		a &= b;
591df930be7Sderaadt 		break;
592df930be7Sderaadt 
593df930be7Sderaadt 	case BPF_OR:
594df930be7Sderaadt 		a |= b;
595df930be7Sderaadt 		break;
596df930be7Sderaadt 
597df930be7Sderaadt 	case BPF_LSH:
598df930be7Sderaadt 		a <<= b;
599df930be7Sderaadt 		break;
600df930be7Sderaadt 
601df930be7Sderaadt 	case BPF_RSH:
602df930be7Sderaadt 		a >>= b;
603df930be7Sderaadt 		break;
604df930be7Sderaadt 
605df930be7Sderaadt 	case BPF_NEG:
606df930be7Sderaadt 		a = -a;
607df930be7Sderaadt 		break;
608df930be7Sderaadt 
609df930be7Sderaadt 	default:
610df930be7Sderaadt 		abort();
611df930be7Sderaadt 	}
612df930be7Sderaadt 	s->k = a;
613df930be7Sderaadt 	s->code = BPF_LD|BPF_IMM;
614df930be7Sderaadt 	done = 0;
615df930be7Sderaadt }
616df930be7Sderaadt 
6178df16311Stholo static __inline struct slist *
this_op(struct slist * s)61819fef815Sderaadt this_op(struct slist *s)
619df930be7Sderaadt {
620df930be7Sderaadt 	while (s != 0 && s->s.code == NOP)
621df930be7Sderaadt 		s = s->next;
622df930be7Sderaadt 	return s;
623df930be7Sderaadt }
624df930be7Sderaadt 
625df930be7Sderaadt static void
opt_not(struct block * b)62619fef815Sderaadt opt_not(struct block *b)
627df930be7Sderaadt {
628df930be7Sderaadt 	struct block *tmp = JT(b);
629df930be7Sderaadt 
630df930be7Sderaadt 	JT(b) = JF(b);
631df930be7Sderaadt 	JF(b) = tmp;
632df930be7Sderaadt }
633df930be7Sderaadt 
634df930be7Sderaadt static void
opt_peep(struct block * b)63519fef815Sderaadt opt_peep(struct block *b)
636df930be7Sderaadt {
637df930be7Sderaadt 	struct slist *s;
638df930be7Sderaadt 	struct slist *next, *last;
639df930be7Sderaadt 	int val;
640df930be7Sderaadt 
641df930be7Sderaadt 	s = b->stmts;
642df930be7Sderaadt 	if (s == 0)
643df930be7Sderaadt 		return;
644df930be7Sderaadt 
645df930be7Sderaadt 	last = s;
646df930be7Sderaadt 	while (1) {
647df930be7Sderaadt 		s = this_op(s);
648df930be7Sderaadt 		if (s == 0)
649df930be7Sderaadt 			break;
650df930be7Sderaadt 		next = this_op(s->next);
651df930be7Sderaadt 		if (next == 0)
652df930be7Sderaadt 			break;
653df930be7Sderaadt 		last = next;
654df930be7Sderaadt 
655df930be7Sderaadt 		/*
656df930be7Sderaadt 		 * st  M[k]	-->	st  M[k]
657df930be7Sderaadt 		 * ldx M[k]		tax
658df930be7Sderaadt 		 */
659df930be7Sderaadt 		if (s->s.code == BPF_ST &&
660df930be7Sderaadt 		    next->s.code == (BPF_LDX|BPF_MEM) &&
661df930be7Sderaadt 		    s->s.k == next->s.k) {
662df930be7Sderaadt 			done = 0;
663df930be7Sderaadt 			next->s.code = BPF_MISC|BPF_TAX;
664df930be7Sderaadt 		}
665df930be7Sderaadt 		/*
666df930be7Sderaadt 		 * ld  #k	-->	ldx  #k
667df930be7Sderaadt 		 * tax			txa
668df930be7Sderaadt 		 */
669df930be7Sderaadt 		if (s->s.code == (BPF_LD|BPF_IMM) &&
670df930be7Sderaadt 		    next->s.code == (BPF_MISC|BPF_TAX)) {
671df930be7Sderaadt 			s->s.code = BPF_LDX|BPF_IMM;
672df930be7Sderaadt 			next->s.code = BPF_MISC|BPF_TXA;
673df930be7Sderaadt 			done = 0;
674df930be7Sderaadt 		}
675df930be7Sderaadt 		/*
676df930be7Sderaadt 		 * This is an ugly special case, but it happens
677df930be7Sderaadt 		 * when you say tcp[k] or udp[k] where k is a constant.
678df930be7Sderaadt 		 */
679df930be7Sderaadt 		if (s->s.code == (BPF_LD|BPF_IMM)) {
680df930be7Sderaadt 			struct slist *add, *tax, *ild;
681df930be7Sderaadt 
682df930be7Sderaadt 			/*
683df930be7Sderaadt 			 * Check that X isn't used on exit from this
684df930be7Sderaadt 			 * block (which the optimizer might cause).
685df930be7Sderaadt 			 * We know the code generator won't generate
686df930be7Sderaadt 			 * any local dependencies.
687df930be7Sderaadt 			 */
688df930be7Sderaadt 			if (ATOMELEM(b->out_use, X_ATOM))
689df930be7Sderaadt 				break;
690df930be7Sderaadt 
691df930be7Sderaadt 			if (next->s.code != (BPF_LDX|BPF_MSH|BPF_B))
692df930be7Sderaadt 				add = next;
693df930be7Sderaadt 			else
694df930be7Sderaadt 				add = this_op(next->next);
695df930be7Sderaadt 			if (add == 0 || add->s.code != (BPF_ALU|BPF_ADD|BPF_X))
696df930be7Sderaadt 				break;
697df930be7Sderaadt 
698df930be7Sderaadt 			tax = this_op(add->next);
699df930be7Sderaadt 			if (tax == 0 || tax->s.code != (BPF_MISC|BPF_TAX))
700df930be7Sderaadt 				break;
701df930be7Sderaadt 
702df930be7Sderaadt 			ild = this_op(tax->next);
703df930be7Sderaadt 			if (ild == 0 || BPF_CLASS(ild->s.code) != BPF_LD ||
704df930be7Sderaadt 			    BPF_MODE(ild->s.code) != BPF_IND)
705df930be7Sderaadt 				break;
706df930be7Sderaadt 			/*
707df930be7Sderaadt 			 * XXX We need to check that X is not
708df930be7Sderaadt 			 * subsequently used.  We know we can eliminate the
709df930be7Sderaadt 			 * accumulator modifications since it is defined
710df930be7Sderaadt 			 * by the last stmt of this sequence.
711df930be7Sderaadt 			 *
712df930be7Sderaadt 			 * We want to turn this sequence:
713df930be7Sderaadt 			 *
714df930be7Sderaadt 			 * (004) ldi     #0x2		{s}
715df930be7Sderaadt 			 * (005) ldxms   [14]		{next}  -- optional
716df930be7Sderaadt 			 * (006) addx			{add}
717df930be7Sderaadt 			 * (007) tax			{tax}
718df930be7Sderaadt 			 * (008) ild     [x+0]		{ild}
719df930be7Sderaadt 			 *
720df930be7Sderaadt 			 * into this sequence:
721df930be7Sderaadt 			 *
722df930be7Sderaadt 			 * (004) nop
723df930be7Sderaadt 			 * (005) ldxms   [14]
724df930be7Sderaadt 			 * (006) nop
725df930be7Sderaadt 			 * (007) nop
726df930be7Sderaadt 			 * (008) ild     [x+2]
727df930be7Sderaadt 			 *
728df930be7Sderaadt 			 */
729df930be7Sderaadt 			ild->s.k += s->s.k;
730df930be7Sderaadt 			s->s.code = NOP;
731df930be7Sderaadt 			add->s.code = NOP;
732df930be7Sderaadt 			tax->s.code = NOP;
733df930be7Sderaadt 			done = 0;
734df930be7Sderaadt 		}
735df930be7Sderaadt 		s = next;
736df930be7Sderaadt 	}
737df930be7Sderaadt 	/*
738df930be7Sderaadt 	 * If we have a subtract to do a comparison, and the X register
739df930be7Sderaadt 	 * is a known constant, we can merge this value into the
740df930be7Sderaadt 	 * comparison.
741df930be7Sderaadt 	 */
742df930be7Sderaadt 	if (last->s.code == (BPF_ALU|BPF_SUB|BPF_X) &&
743df930be7Sderaadt 	    !ATOMELEM(b->out_use, A_ATOM)) {
744df930be7Sderaadt 		val = b->val[X_ATOM];
745df930be7Sderaadt 		if (vmap[val].is_const) {
7469b113833Smickey 			int op;
7479b113833Smickey 
748df930be7Sderaadt 			b->s.k += vmap[val].const_val;
7499b113833Smickey 			op = BPF_OP(b->s.code);
7509b113833Smickey 			if (op == BPF_JGT || op == BPF_JGE) {
7519b113833Smickey 				struct block *t = JT(b);
7529b113833Smickey 				JT(b) = JF(b);
7539b113833Smickey 				JF(b) = t;
7549b113833Smickey 				b->s.k += 0x80000000;
7559b113833Smickey 			}
756df930be7Sderaadt 			last->s.code = NOP;
757df930be7Sderaadt 			done = 0;
758df930be7Sderaadt 		} else if (b->s.k == 0) {
759df930be7Sderaadt 			/*
760df930be7Sderaadt 			 * sub x  ->	nop
761df930be7Sderaadt 			 * j  #0	j  x
762df930be7Sderaadt 			 */
763df930be7Sderaadt 			last->s.code = NOP;
764df930be7Sderaadt 			b->s.code = BPF_CLASS(b->s.code) | BPF_OP(b->s.code) |
765df930be7Sderaadt 				BPF_X;
766df930be7Sderaadt 			done = 0;
767df930be7Sderaadt 		}
768df930be7Sderaadt 	}
769df930be7Sderaadt 	/*
770df930be7Sderaadt 	 * Likewise, a constant subtract can be simplified.
771df930be7Sderaadt 	 */
772df930be7Sderaadt 	else if (last->s.code == (BPF_ALU|BPF_SUB|BPF_K) &&
773df930be7Sderaadt 		 !ATOMELEM(b->out_use, A_ATOM)) {
7749b113833Smickey 		int op;
7759b113833Smickey 
776df930be7Sderaadt 		b->s.k += last->s.k;
777df930be7Sderaadt 		last->s.code = NOP;
7789b113833Smickey 		op = BPF_OP(b->s.code);
7799b113833Smickey 		if (op == BPF_JGT || op == BPF_JGE) {
7809b113833Smickey 			struct block *t = JT(b);
7819b113833Smickey 			JT(b) = JF(b);
7829b113833Smickey 			JF(b) = t;
7839b113833Smickey 			b->s.k += 0x80000000;
7849b113833Smickey 		}
785df930be7Sderaadt 		done = 0;
786df930be7Sderaadt 	}
787df930be7Sderaadt 	/*
788df930be7Sderaadt 	 * and #k	nop
789df930be7Sderaadt 	 * jeq #0  ->	jset #k
790df930be7Sderaadt 	 */
791df930be7Sderaadt 	if (last->s.code == (BPF_ALU|BPF_AND|BPF_K) &&
792df930be7Sderaadt 	    !ATOMELEM(b->out_use, A_ATOM) && b->s.k == 0) {
793df930be7Sderaadt 		b->s.k = last->s.k;
794df930be7Sderaadt 		b->s.code = BPF_JMP|BPF_K|BPF_JSET;
795df930be7Sderaadt 		last->s.code = NOP;
796df930be7Sderaadt 		done = 0;
797df930be7Sderaadt 		opt_not(b);
798df930be7Sderaadt 	}
799df930be7Sderaadt 	/*
800df930be7Sderaadt 	 * If the accumulator is a known constant, we can compute the
801df930be7Sderaadt 	 * comparison result.
802df930be7Sderaadt 	 */
803df930be7Sderaadt 	val = b->val[A_ATOM];
804df930be7Sderaadt 	if (vmap[val].is_const && BPF_SRC(b->s.code) == BPF_K) {
8059b113833Smickey 		bpf_int32 v = vmap[val].const_val;
806df930be7Sderaadt 		switch (BPF_OP(b->s.code)) {
807df930be7Sderaadt 
808df930be7Sderaadt 		case BPF_JEQ:
809df930be7Sderaadt 			v = v == b->s.k;
810df930be7Sderaadt 			break;
811df930be7Sderaadt 
812df930be7Sderaadt 		case BPF_JGT:
8139b113833Smickey 			v = (unsigned)v > b->s.k;
814df930be7Sderaadt 			break;
815df930be7Sderaadt 
816df930be7Sderaadt 		case BPF_JGE:
8179b113833Smickey 			v = (unsigned)v >= b->s.k;
818df930be7Sderaadt 			break;
819df930be7Sderaadt 
820df930be7Sderaadt 		case BPF_JSET:
821df930be7Sderaadt 			v &= b->s.k;
822df930be7Sderaadt 			break;
823df930be7Sderaadt 
824df930be7Sderaadt 		default:
825df930be7Sderaadt 			abort();
826df930be7Sderaadt 		}
827df930be7Sderaadt 		if (JF(b) != JT(b))
828df930be7Sderaadt 			done = 0;
829df930be7Sderaadt 		if (v)
830df930be7Sderaadt 			JF(b) = JT(b);
831df930be7Sderaadt 		else
832df930be7Sderaadt 			JT(b) = JF(b);
833df930be7Sderaadt 	}
834df930be7Sderaadt }
835df930be7Sderaadt 
836df930be7Sderaadt /*
837df930be7Sderaadt  * Compute the symbolic value of expression of 's', and update
838df930be7Sderaadt  * anything it defines in the value table 'val'.  If 'alter' is true,
839df930be7Sderaadt  * do various optimizations.  This code would be cleaner if symbolic
840df930be7Sderaadt  * evaluation and code transformations weren't folded together.
841df930be7Sderaadt  */
842df930be7Sderaadt static void
opt_stmt(struct stmt * s,int val[],int alter)84319fef815Sderaadt opt_stmt(struct stmt *s, int val[], int alter)
844df930be7Sderaadt {
845df930be7Sderaadt 	int op;
8469b113833Smickey 	int v;
847df930be7Sderaadt 
848df930be7Sderaadt 	switch (s->code) {
849df930be7Sderaadt 
850df930be7Sderaadt 	case BPF_LD|BPF_ABS|BPF_W:
851df930be7Sderaadt 	case BPF_LD|BPF_ABS|BPF_H:
852df930be7Sderaadt 	case BPF_LD|BPF_ABS|BPF_B:
853df930be7Sderaadt 		v = F(s->code, s->k, 0L);
854df930be7Sderaadt 		vstore(s, &val[A_ATOM], v, alter);
855df930be7Sderaadt 		break;
856df930be7Sderaadt 
857df930be7Sderaadt 	case BPF_LD|BPF_IND|BPF_W:
858df930be7Sderaadt 	case BPF_LD|BPF_IND|BPF_H:
859df930be7Sderaadt 	case BPF_LD|BPF_IND|BPF_B:
860df930be7Sderaadt 		v = val[X_ATOM];
861df930be7Sderaadt 		if (alter && vmap[v].is_const) {
862df930be7Sderaadt 			s->code = BPF_LD|BPF_ABS|BPF_SIZE(s->code);
863df930be7Sderaadt 			s->k += vmap[v].const_val;
864df930be7Sderaadt 			v = F(s->code, s->k, 0L);
865df930be7Sderaadt 			done = 0;
866df930be7Sderaadt 		}
867df930be7Sderaadt 		else
868df930be7Sderaadt 			v = F(s->code, s->k, v);
869df930be7Sderaadt 		vstore(s, &val[A_ATOM], v, alter);
870df930be7Sderaadt 		break;
871df930be7Sderaadt 
872df930be7Sderaadt 	case BPF_LD|BPF_LEN:
873a8e9f808Sdlg 	case BPF_LD|BPF_RND:
874df930be7Sderaadt 		v = F(s->code, 0L, 0L);
875df930be7Sderaadt 		vstore(s, &val[A_ATOM], v, alter);
876df930be7Sderaadt 		break;
877df930be7Sderaadt 
878df930be7Sderaadt 	case BPF_LD|BPF_IMM:
879df930be7Sderaadt 		v = K(s->k);
880df930be7Sderaadt 		vstore(s, &val[A_ATOM], v, alter);
881df930be7Sderaadt 		break;
882df930be7Sderaadt 
883df930be7Sderaadt 	case BPF_LDX|BPF_IMM:
884df930be7Sderaadt 		v = K(s->k);
885df930be7Sderaadt 		vstore(s, &val[X_ATOM], v, alter);
886df930be7Sderaadt 		break;
887df930be7Sderaadt 
888df930be7Sderaadt 	case BPF_LDX|BPF_MSH|BPF_B:
889df930be7Sderaadt 		v = F(s->code, s->k, 0L);
890df930be7Sderaadt 		vstore(s, &val[X_ATOM], v, alter);
891df930be7Sderaadt 		break;
892df930be7Sderaadt 
893df930be7Sderaadt 	case BPF_ALU|BPF_NEG:
894df930be7Sderaadt 		if (alter && vmap[val[A_ATOM]].is_const) {
895df930be7Sderaadt 			s->code = BPF_LD|BPF_IMM;
896df930be7Sderaadt 			s->k = -vmap[val[A_ATOM]].const_val;
897df930be7Sderaadt 			val[A_ATOM] = K(s->k);
898df930be7Sderaadt 		}
899df930be7Sderaadt 		else
900df930be7Sderaadt 			val[A_ATOM] = F(s->code, val[A_ATOM], 0L);
901df930be7Sderaadt 		break;
902df930be7Sderaadt 
903df930be7Sderaadt 	case BPF_ALU|BPF_ADD|BPF_K:
904df930be7Sderaadt 	case BPF_ALU|BPF_SUB|BPF_K:
905df930be7Sderaadt 	case BPF_ALU|BPF_MUL|BPF_K:
906df930be7Sderaadt 	case BPF_ALU|BPF_DIV|BPF_K:
907df930be7Sderaadt 	case BPF_ALU|BPF_AND|BPF_K:
908df930be7Sderaadt 	case BPF_ALU|BPF_OR|BPF_K:
909df930be7Sderaadt 	case BPF_ALU|BPF_LSH|BPF_K:
910df930be7Sderaadt 	case BPF_ALU|BPF_RSH|BPF_K:
911df930be7Sderaadt 		op = BPF_OP(s->code);
912df930be7Sderaadt 		if (alter) {
913df930be7Sderaadt 			if (s->k == 0) {
914df930be7Sderaadt 				if (op == BPF_ADD || op == BPF_SUB ||
915df930be7Sderaadt 				    op == BPF_LSH || op == BPF_RSH ||
916df930be7Sderaadt 				    op == BPF_OR) {
917df930be7Sderaadt 					s->code = NOP;
918df930be7Sderaadt 					break;
919df930be7Sderaadt 				}
920df930be7Sderaadt 				if (op == BPF_MUL || op == BPF_AND) {
921df930be7Sderaadt 					s->code = BPF_LD|BPF_IMM;
922df930be7Sderaadt 					val[A_ATOM] = K(s->k);
923df930be7Sderaadt 					break;
924df930be7Sderaadt 				}
925df930be7Sderaadt 			}
926df930be7Sderaadt 			if (vmap[val[A_ATOM]].is_const) {
927df930be7Sderaadt 				fold_op(s, val[A_ATOM], K(s->k));
928df930be7Sderaadt 				val[A_ATOM] = K(s->k);
929df930be7Sderaadt 				break;
930df930be7Sderaadt 			}
931df930be7Sderaadt 		}
932df930be7Sderaadt 		val[A_ATOM] = F(s->code, val[A_ATOM], K(s->k));
933df930be7Sderaadt 		break;
934df930be7Sderaadt 
935df930be7Sderaadt 	case BPF_ALU|BPF_ADD|BPF_X:
936df930be7Sderaadt 	case BPF_ALU|BPF_SUB|BPF_X:
937df930be7Sderaadt 	case BPF_ALU|BPF_MUL|BPF_X:
938df930be7Sderaadt 	case BPF_ALU|BPF_DIV|BPF_X:
939df930be7Sderaadt 	case BPF_ALU|BPF_AND|BPF_X:
940df930be7Sderaadt 	case BPF_ALU|BPF_OR|BPF_X:
941df930be7Sderaadt 	case BPF_ALU|BPF_LSH|BPF_X:
942df930be7Sderaadt 	case BPF_ALU|BPF_RSH|BPF_X:
943df930be7Sderaadt 		op = BPF_OP(s->code);
944df930be7Sderaadt 		if (alter && vmap[val[X_ATOM]].is_const) {
945df930be7Sderaadt 			if (vmap[val[A_ATOM]].is_const) {
946df930be7Sderaadt 				fold_op(s, val[A_ATOM], val[X_ATOM]);
947df930be7Sderaadt 				val[A_ATOM] = K(s->k);
948df930be7Sderaadt 			}
949df930be7Sderaadt 			else {
950df930be7Sderaadt 				s->code = BPF_ALU|BPF_K|op;
951df930be7Sderaadt 				s->k = vmap[val[X_ATOM]].const_val;
952df930be7Sderaadt 				done = 0;
953df930be7Sderaadt 				val[A_ATOM] =
954df930be7Sderaadt 					F(s->code, val[A_ATOM], K(s->k));
955df930be7Sderaadt 			}
956df930be7Sderaadt 			break;
957df930be7Sderaadt 		}
958df930be7Sderaadt 		/*
959df930be7Sderaadt 		 * Check if we're doing something to an accumulator
960df930be7Sderaadt 		 * that is 0, and simplify.  This may not seem like
961df930be7Sderaadt 		 * much of a simplification but it could open up further
962df930be7Sderaadt 		 * optimizations.
963df930be7Sderaadt 		 * XXX We could also check for mul by 1, and -1, etc.
964df930be7Sderaadt 		 */
965df930be7Sderaadt 		if (alter && vmap[val[A_ATOM]].is_const
966df930be7Sderaadt 		    && vmap[val[A_ATOM]].const_val == 0) {
967df930be7Sderaadt 			if (op == BPF_ADD || op == BPF_OR ||
968df930be7Sderaadt 			    op == BPF_LSH || op == BPF_RSH || op == BPF_SUB) {
969df930be7Sderaadt 				s->code = BPF_MISC|BPF_TXA;
970df930be7Sderaadt 				vstore(s, &val[A_ATOM], val[X_ATOM], alter);
971df930be7Sderaadt 				break;
972df930be7Sderaadt 			}
973df930be7Sderaadt 			else if (op == BPF_MUL || op == BPF_DIV ||
974df930be7Sderaadt 				 op == BPF_AND) {
975df930be7Sderaadt 				s->code = BPF_LD|BPF_IMM;
976df930be7Sderaadt 				s->k = 0;
977df930be7Sderaadt 				vstore(s, &val[A_ATOM], K(s->k), alter);
978df930be7Sderaadt 				break;
979df930be7Sderaadt 			}
980df930be7Sderaadt 			else if (op == BPF_NEG) {
981df930be7Sderaadt 				s->code = NOP;
982df930be7Sderaadt 				break;
983df930be7Sderaadt 			}
984df930be7Sderaadt 		}
985df930be7Sderaadt 		val[A_ATOM] = F(s->code, val[A_ATOM], val[X_ATOM]);
986df930be7Sderaadt 		break;
987df930be7Sderaadt 
988df930be7Sderaadt 	case BPF_MISC|BPF_TXA:
989df930be7Sderaadt 		vstore(s, &val[A_ATOM], val[X_ATOM], alter);
990df930be7Sderaadt 		break;
991df930be7Sderaadt 
992df930be7Sderaadt 	case BPF_LD|BPF_MEM:
993df930be7Sderaadt 		v = val[s->k];
994df930be7Sderaadt 		if (alter && vmap[v].is_const) {
995df930be7Sderaadt 			s->code = BPF_LD|BPF_IMM;
996df930be7Sderaadt 			s->k = vmap[v].const_val;
997df930be7Sderaadt 			done = 0;
998df930be7Sderaadt 		}
999df930be7Sderaadt 		vstore(s, &val[A_ATOM], v, alter);
1000df930be7Sderaadt 		break;
1001df930be7Sderaadt 
1002df930be7Sderaadt 	case BPF_MISC|BPF_TAX:
1003df930be7Sderaadt 		vstore(s, &val[X_ATOM], val[A_ATOM], alter);
1004df930be7Sderaadt 		break;
1005df930be7Sderaadt 
1006df930be7Sderaadt 	case BPF_LDX|BPF_MEM:
1007df930be7Sderaadt 		v = val[s->k];
1008df930be7Sderaadt 		if (alter && vmap[v].is_const) {
1009df930be7Sderaadt 			s->code = BPF_LDX|BPF_IMM;
1010df930be7Sderaadt 			s->k = vmap[v].const_val;
1011df930be7Sderaadt 			done = 0;
1012df930be7Sderaadt 		}
1013df930be7Sderaadt 		vstore(s, &val[X_ATOM], v, alter);
1014df930be7Sderaadt 		break;
1015df930be7Sderaadt 
1016df930be7Sderaadt 	case BPF_ST:
1017df930be7Sderaadt 		vstore(s, &val[s->k], val[A_ATOM], alter);
1018df930be7Sderaadt 		break;
1019df930be7Sderaadt 
1020df930be7Sderaadt 	case BPF_STX:
1021df930be7Sderaadt 		vstore(s, &val[s->k], val[X_ATOM], alter);
1022df930be7Sderaadt 		break;
1023df930be7Sderaadt 	}
1024df930be7Sderaadt }
1025df930be7Sderaadt 
1026df930be7Sderaadt static void
deadstmt(struct stmt * s,struct stmt * last[])102719fef815Sderaadt deadstmt(struct stmt *s, struct stmt *last[])
1028df930be7Sderaadt {
1029d0438536Smmcc 	int atom;
1030df930be7Sderaadt 
1031df930be7Sderaadt 	atom = atomuse(s);
1032df930be7Sderaadt 	if (atom >= 0) {
1033df930be7Sderaadt 		if (atom == AX_ATOM) {
1034df930be7Sderaadt 			last[X_ATOM] = 0;
1035df930be7Sderaadt 			last[A_ATOM] = 0;
1036df930be7Sderaadt 		}
1037df930be7Sderaadt 		else
1038df930be7Sderaadt 			last[atom] = 0;
1039df930be7Sderaadt 	}
1040df930be7Sderaadt 	atom = atomdef(s);
1041df930be7Sderaadt 	if (atom >= 0) {
1042df930be7Sderaadt 		if (last[atom]) {
1043df930be7Sderaadt 			done = 0;
1044df930be7Sderaadt 			last[atom]->code = NOP;
1045df930be7Sderaadt 		}
1046df930be7Sderaadt 		last[atom] = s;
1047df930be7Sderaadt 	}
1048df930be7Sderaadt }
1049df930be7Sderaadt 
1050df930be7Sderaadt static void
opt_deadstores(struct block * b)105119fef815Sderaadt opt_deadstores(struct block *b)
1052df930be7Sderaadt {
1053d0438536Smmcc 	struct slist *s;
1054d0438536Smmcc 	int atom;
1055df930be7Sderaadt 	struct stmt *last[N_ATOMS];
1056df930be7Sderaadt 
1057df930be7Sderaadt 	memset((char *)last, 0, sizeof last);
1058df930be7Sderaadt 
1059df930be7Sderaadt 	for (s = b->stmts; s != 0; s = s->next)
1060df930be7Sderaadt 		deadstmt(&s->s, last);
1061df930be7Sderaadt 	deadstmt(&b->s, last);
1062df930be7Sderaadt 
1063df930be7Sderaadt 	for (atom = 0; atom < N_ATOMS; ++atom)
1064df930be7Sderaadt 		if (last[atom] && !ATOMELEM(b->out_use, atom)) {
1065df930be7Sderaadt 			last[atom]->code = NOP;
1066df930be7Sderaadt 			done = 0;
1067df930be7Sderaadt 		}
1068df930be7Sderaadt }
1069df930be7Sderaadt 
1070df930be7Sderaadt static void
opt_blk(struct block * b,int do_stmts)107119fef815Sderaadt opt_blk(struct block *b, int do_stmts)
1072df930be7Sderaadt {
1073df930be7Sderaadt 	struct slist *s;
1074df930be7Sderaadt 	struct edge *p;
1075df930be7Sderaadt 	int i;
10769b113833Smickey 	bpf_int32 aval;
1077df930be7Sderaadt 
1078a9b0695fSjakob #if 0
1079a9b0695fSjakob 	for (s = b->stmts; s && s->next; s = s->next)
1080a9b0695fSjakob 		if (BPF_CLASS(s->s.code) == BPF_JMP) {
1081a9b0695fSjakob 			do_stmts = 0;
1082a9b0695fSjakob 			break;
1083a9b0695fSjakob 		}
1084a9b0695fSjakob #endif
1085a9b0695fSjakob 
1086df930be7Sderaadt 	/*
1087df930be7Sderaadt 	 * Initialize the atom values.
1088df930be7Sderaadt 	 * If we have no predecessors, everything is undefined.
1089df930be7Sderaadt 	 * Otherwise, we inherent our values from our predecessors.
1090df930be7Sderaadt 	 * If any register has an ambiguous value (i.e. control paths are
1091df930be7Sderaadt 	 * merging) give it the undefined value of 0.
1092df930be7Sderaadt 	 */
1093df930be7Sderaadt 	p = b->in_edges;
1094df930be7Sderaadt 	if (p == 0)
1095df930be7Sderaadt 		memset((char *)b->val, 0, sizeof(b->val));
1096df930be7Sderaadt 	else {
1097df930be7Sderaadt 		memcpy((char *)b->val, (char *)p->pred->val, sizeof(b->val));
1098df930be7Sderaadt 		while ((p = p->next) != NULL) {
1099df930be7Sderaadt 			for (i = 0; i < N_ATOMS; ++i)
1100df930be7Sderaadt 				if (b->val[i] != p->pred->val[i])
1101df930be7Sderaadt 					b->val[i] = 0;
1102df930be7Sderaadt 		}
1103df930be7Sderaadt 	}
1104df930be7Sderaadt 	aval = b->val[A_ATOM];
1105df930be7Sderaadt 	for (s = b->stmts; s; s = s->next)
1106df930be7Sderaadt 		opt_stmt(&s->s, b->val, do_stmts);
1107df930be7Sderaadt 
1108df930be7Sderaadt 	/*
1109df930be7Sderaadt 	 * This is a special case: if we don't use anything from this
1110df930be7Sderaadt 	 * block, and we load the accumulator with value that is
11119b113833Smickey 	 * already there, or if this block is a return,
11129b113833Smickey 	 * eliminate all the statements.
1113df930be7Sderaadt 	 */
11149b113833Smickey 	if (do_stmts &&
11159b113833Smickey 	    ((b->out_use == 0 && aval != 0 &&b->val[A_ATOM] == aval) ||
11169b113833Smickey 	     BPF_CLASS(b->s.code) == BPF_RET)) {
11179b113833Smickey 		if (b->stmts != 0) {
1118df930be7Sderaadt 			b->stmts = 0;
11199b113833Smickey 			done = 0;
11209b113833Smickey 		}
11219b113833Smickey 	} else {
1122df930be7Sderaadt 		opt_peep(b);
1123df930be7Sderaadt 		opt_deadstores(b);
1124df930be7Sderaadt 	}
1125df930be7Sderaadt 	/*
1126df930be7Sderaadt 	 * Set up values for branch optimizer.
1127df930be7Sderaadt 	 */
1128df930be7Sderaadt 	if (BPF_SRC(b->s.code) == BPF_K)
1129df930be7Sderaadt 		b->oval = K(b->s.k);
1130df930be7Sderaadt 	else
1131df930be7Sderaadt 		b->oval = b->val[X_ATOM];
1132df930be7Sderaadt 	b->et.code = b->s.code;
1133df930be7Sderaadt 	b->ef.code = -b->s.code;
1134df930be7Sderaadt }
1135df930be7Sderaadt 
1136df930be7Sderaadt /*
1137df930be7Sderaadt  * Return true if any register that is used on exit from 'succ', has
1138df930be7Sderaadt  * an exit value that is different from the corresponding exit value
1139df930be7Sderaadt  * from 'b'.
1140df930be7Sderaadt  */
1141df930be7Sderaadt static int
use_conflict(struct block * b,struct block * succ)114219fef815Sderaadt use_conflict(struct block *b, struct block *succ)
1143df930be7Sderaadt {
1144df930be7Sderaadt 	int atom;
1145df930be7Sderaadt 	atomset use = succ->out_use;
1146df930be7Sderaadt 
1147df930be7Sderaadt 	if (use == 0)
1148df930be7Sderaadt 		return 0;
1149df930be7Sderaadt 
1150df930be7Sderaadt 	for (atom = 0; atom < N_ATOMS; ++atom)
1151df930be7Sderaadt 		if (ATOMELEM(use, atom))
1152df930be7Sderaadt 			if (b->val[atom] != succ->val[atom])
1153df930be7Sderaadt 				return 1;
1154df930be7Sderaadt 	return 0;
1155df930be7Sderaadt }
1156df930be7Sderaadt 
1157df930be7Sderaadt static struct block *
fold_edge(struct block * child,struct edge * ep)115819fef815Sderaadt fold_edge(struct block *child, struct edge *ep)
1159df930be7Sderaadt {
1160df930be7Sderaadt 	int sense;
1161df930be7Sderaadt 	int aval0, aval1, oval0, oval1;
1162df930be7Sderaadt 	int code = ep->code;
1163df930be7Sderaadt 
1164df930be7Sderaadt 	if (code < 0) {
1165df930be7Sderaadt 		code = -code;
1166df930be7Sderaadt 		sense = 0;
1167df930be7Sderaadt 	} else
1168df930be7Sderaadt 		sense = 1;
1169df930be7Sderaadt 
1170df930be7Sderaadt 	if (child->s.code != code)
1171df930be7Sderaadt 		return 0;
1172df930be7Sderaadt 
1173df930be7Sderaadt 	aval0 = child->val[A_ATOM];
1174df930be7Sderaadt 	oval0 = child->oval;
1175df930be7Sderaadt 	aval1 = ep->pred->val[A_ATOM];
1176df930be7Sderaadt 	oval1 = ep->pred->oval;
1177df930be7Sderaadt 
1178df930be7Sderaadt 	if (aval0 != aval1)
1179df930be7Sderaadt 		return 0;
1180df930be7Sderaadt 
1181df930be7Sderaadt 	if (oval0 == oval1)
1182df930be7Sderaadt 		/*
1183df930be7Sderaadt 		 * The operands are identical, so the
1184df930be7Sderaadt 		 * result is true if a true branch was
1185df930be7Sderaadt 		 * taken to get here, otherwise false.
1186df930be7Sderaadt 		 */
1187df930be7Sderaadt 		return sense ? JT(child) : JF(child);
1188df930be7Sderaadt 
1189df930be7Sderaadt 	if (sense && code == (BPF_JMP|BPF_JEQ|BPF_K))
1190df930be7Sderaadt 		/*
1191df930be7Sderaadt 		 * At this point, we only know the comparison if we
1192df930be7Sderaadt 		 * came down the true branch, and it was an equality
1193df930be7Sderaadt 		 * comparison with a constant.  We rely on the fact that
1194df930be7Sderaadt 		 * distinct constants have distinct value numbers.
1195df930be7Sderaadt 		 */
1196df930be7Sderaadt 		return JF(child);
1197df930be7Sderaadt 
1198df930be7Sderaadt 	return 0;
1199df930be7Sderaadt }
1200df930be7Sderaadt 
1201df930be7Sderaadt static void
opt_j(struct edge * ep)120219fef815Sderaadt opt_j(struct edge *ep)
1203df930be7Sderaadt {
1204d0438536Smmcc 	int i, k;
1205d0438536Smmcc 	struct block *target;
1206df930be7Sderaadt 
1207df930be7Sderaadt 	if (JT(ep->succ) == 0)
1208df930be7Sderaadt 		return;
1209df930be7Sderaadt 
1210df930be7Sderaadt 	if (JT(ep->succ) == JF(ep->succ)) {
1211df930be7Sderaadt 		/*
1212df930be7Sderaadt 		 * Common branch targets can be eliminated, provided
1213df930be7Sderaadt 		 * there is no data dependency.
1214df930be7Sderaadt 		 */
1215df930be7Sderaadt 		if (!use_conflict(ep->pred, ep->succ->et.succ)) {
1216df930be7Sderaadt 			done = 0;
1217df930be7Sderaadt 			ep->succ = JT(ep->succ);
1218df930be7Sderaadt 		}
1219df930be7Sderaadt 	}
1220df930be7Sderaadt 	/*
1221df930be7Sderaadt 	 * For each edge dominator that matches the successor of this
1222df930be7Sderaadt 	 * edge, promote the edge successor to the its grandchild.
1223df930be7Sderaadt 	 *
1224df930be7Sderaadt 	 * XXX We violate the set abstraction here in favor a reasonably
1225df930be7Sderaadt 	 * efficient loop.
1226df930be7Sderaadt 	 */
1227df930be7Sderaadt  top:
1228df930be7Sderaadt 	for (i = 0; i < edgewords; ++i) {
1229d0438536Smmcc 		bpf_u_int32 x = ep->edom[i];
1230df930be7Sderaadt 
1231df930be7Sderaadt 		while (x != 0) {
1232df930be7Sderaadt 			k = ffs(x) - 1;
1233df930be7Sderaadt 			x &=~ (1 << k);
1234df930be7Sderaadt 			k += i * BITS_PER_WORD;
1235df930be7Sderaadt 
1236df930be7Sderaadt 			target = fold_edge(ep->succ, edges[k]);
1237df930be7Sderaadt 			/*
1238df930be7Sderaadt 			 * Check that there is no data dependency between
1239df930be7Sderaadt 			 * nodes that will be violated if we move the edge.
1240df930be7Sderaadt 			 */
1241df930be7Sderaadt 			if (target != 0 && !use_conflict(ep->pred, target)) {
1242df930be7Sderaadt 				done = 0;
1243df930be7Sderaadt 				ep->succ = target;
1244df930be7Sderaadt 				if (JT(target) != 0)
1245df930be7Sderaadt 					/*
1246df930be7Sderaadt 					 * Start over unless we hit a leaf.
1247df930be7Sderaadt 					 */
1248df930be7Sderaadt 					goto top;
1249df930be7Sderaadt 				return;
1250df930be7Sderaadt 			}
1251df930be7Sderaadt 		}
1252df930be7Sderaadt 	}
1253df930be7Sderaadt }
1254df930be7Sderaadt 
1255df930be7Sderaadt 
1256df930be7Sderaadt static void
or_pullup(struct block * b)125719fef815Sderaadt or_pullup(struct block *b)
1258df930be7Sderaadt {
1259df930be7Sderaadt 	int val, at_top;
1260df930be7Sderaadt 	struct block *pull;
1261df930be7Sderaadt 	struct block **diffp, **samep;
1262df930be7Sderaadt 	struct edge *ep;
1263df930be7Sderaadt 
1264df930be7Sderaadt 	ep = b->in_edges;
1265df930be7Sderaadt 	if (ep == 0)
1266df930be7Sderaadt 		return;
1267df930be7Sderaadt 
1268df930be7Sderaadt 	/*
1269df930be7Sderaadt 	 * Make sure each predecessor loads the same value.
1270df930be7Sderaadt 	 * XXX why?
1271df930be7Sderaadt 	 */
1272df930be7Sderaadt 	val = ep->pred->val[A_ATOM];
1273df930be7Sderaadt 	for (ep = ep->next; ep != 0; ep = ep->next)
1274df930be7Sderaadt 		if (val != ep->pred->val[A_ATOM])
1275df930be7Sderaadt 			return;
1276df930be7Sderaadt 
1277df930be7Sderaadt 	if (JT(b->in_edges->pred) == b)
1278df930be7Sderaadt 		diffp = &JT(b->in_edges->pred);
1279df930be7Sderaadt 	else
1280df930be7Sderaadt 		diffp = &JF(b->in_edges->pred);
1281df930be7Sderaadt 
1282df930be7Sderaadt 	at_top = 1;
1283df930be7Sderaadt 	while (1) {
1284df930be7Sderaadt 		if (*diffp == 0)
1285df930be7Sderaadt 			return;
1286df930be7Sderaadt 
1287df930be7Sderaadt 		if (JT(*diffp) != JT(b))
1288df930be7Sderaadt 			return;
1289df930be7Sderaadt 
1290df930be7Sderaadt 		if (!SET_MEMBER((*diffp)->dom, b->id))
1291df930be7Sderaadt 			return;
1292df930be7Sderaadt 
1293df930be7Sderaadt 		if ((*diffp)->val[A_ATOM] != val)
1294df930be7Sderaadt 			break;
1295df930be7Sderaadt 
1296df930be7Sderaadt 		diffp = &JF(*diffp);
1297df930be7Sderaadt 		at_top = 0;
1298df930be7Sderaadt 	}
1299df930be7Sderaadt 	samep = &JF(*diffp);
1300df930be7Sderaadt 	while (1) {
1301df930be7Sderaadt 		if (*samep == 0)
1302df930be7Sderaadt 			return;
1303df930be7Sderaadt 
1304df930be7Sderaadt 		if (JT(*samep) != JT(b))
1305df930be7Sderaadt 			return;
1306df930be7Sderaadt 
1307df930be7Sderaadt 		if (!SET_MEMBER((*samep)->dom, b->id))
1308df930be7Sderaadt 			return;
1309df930be7Sderaadt 
1310df930be7Sderaadt 		if ((*samep)->val[A_ATOM] == val)
1311df930be7Sderaadt 			break;
1312df930be7Sderaadt 
1313df930be7Sderaadt 		/* XXX Need to check that there are no data dependencies
1314df930be7Sderaadt 		   between dp0 and dp1.  Currently, the code generator
1315df930be7Sderaadt 		   will not produce such dependencies. */
1316df930be7Sderaadt 		samep = &JF(*samep);
1317df930be7Sderaadt 	}
1318df930be7Sderaadt #ifdef notdef
1319df930be7Sderaadt 	/* XXX This doesn't cover everything. */
1320df930be7Sderaadt 	for (i = 0; i < N_ATOMS; ++i)
1321df930be7Sderaadt 		if ((*samep)->val[i] != pred->val[i])
1322df930be7Sderaadt 			return;
1323df930be7Sderaadt #endif
1324df930be7Sderaadt 	/* Pull up the node. */
1325df930be7Sderaadt 	pull = *samep;
1326df930be7Sderaadt 	*samep = JF(pull);
1327df930be7Sderaadt 	JF(pull) = *diffp;
1328df930be7Sderaadt 
1329df930be7Sderaadt 	/*
1330df930be7Sderaadt 	 * At the top of the chain, each predecessor needs to point at the
1331df930be7Sderaadt 	 * pulled up node.  Inside the chain, there is only one predecessor
1332df930be7Sderaadt 	 * to worry about.
1333df930be7Sderaadt 	 */
1334df930be7Sderaadt 	if (at_top) {
1335df930be7Sderaadt 		for (ep = b->in_edges; ep != 0; ep = ep->next) {
1336df930be7Sderaadt 			if (JT(ep->pred) == b)
1337df930be7Sderaadt 				JT(ep->pred) = pull;
1338df930be7Sderaadt 			else
1339df930be7Sderaadt 				JF(ep->pred) = pull;
1340df930be7Sderaadt 		}
1341df930be7Sderaadt 	}
1342df930be7Sderaadt 	else
1343df930be7Sderaadt 		*diffp = pull;
1344df930be7Sderaadt 
1345df930be7Sderaadt 	done = 0;
1346df930be7Sderaadt }
1347df930be7Sderaadt 
1348df930be7Sderaadt static void
and_pullup(struct block * b)134919fef815Sderaadt and_pullup(struct block *b)
1350df930be7Sderaadt {
1351df930be7Sderaadt 	int val, at_top;
1352df930be7Sderaadt 	struct block *pull;
1353df930be7Sderaadt 	struct block **diffp, **samep;
1354df930be7Sderaadt 	struct edge *ep;
1355df930be7Sderaadt 
1356df930be7Sderaadt 	ep = b->in_edges;
1357df930be7Sderaadt 	if (ep == 0)
1358df930be7Sderaadt 		return;
1359df930be7Sderaadt 
1360df930be7Sderaadt 	/*
1361df930be7Sderaadt 	 * Make sure each predecessor loads the same value.
1362df930be7Sderaadt 	 */
1363df930be7Sderaadt 	val = ep->pred->val[A_ATOM];
1364df930be7Sderaadt 	for (ep = ep->next; ep != 0; ep = ep->next)
1365df930be7Sderaadt 		if (val != ep->pred->val[A_ATOM])
1366df930be7Sderaadt 			return;
1367df930be7Sderaadt 
1368df930be7Sderaadt 	if (JT(b->in_edges->pred) == b)
1369df930be7Sderaadt 		diffp = &JT(b->in_edges->pred);
1370df930be7Sderaadt 	else
1371df930be7Sderaadt 		diffp = &JF(b->in_edges->pred);
1372df930be7Sderaadt 
1373df930be7Sderaadt 	at_top = 1;
1374df930be7Sderaadt 	while (1) {
1375df930be7Sderaadt 		if (*diffp == 0)
1376df930be7Sderaadt 			return;
1377df930be7Sderaadt 
1378df930be7Sderaadt 		if (JF(*diffp) != JF(b))
1379df930be7Sderaadt 			return;
1380df930be7Sderaadt 
1381df930be7Sderaadt 		if (!SET_MEMBER((*diffp)->dom, b->id))
1382df930be7Sderaadt 			return;
1383df930be7Sderaadt 
1384df930be7Sderaadt 		if ((*diffp)->val[A_ATOM] != val)
1385df930be7Sderaadt 			break;
1386df930be7Sderaadt 
1387df930be7Sderaadt 		diffp = &JT(*diffp);
1388df930be7Sderaadt 		at_top = 0;
1389df930be7Sderaadt 	}
1390df930be7Sderaadt 	samep = &JT(*diffp);
1391df930be7Sderaadt 	while (1) {
1392df930be7Sderaadt 		if (*samep == 0)
1393df930be7Sderaadt 			return;
1394df930be7Sderaadt 
1395df930be7Sderaadt 		if (JF(*samep) != JF(b))
1396df930be7Sderaadt 			return;
1397df930be7Sderaadt 
1398df930be7Sderaadt 		if (!SET_MEMBER((*samep)->dom, b->id))
1399df930be7Sderaadt 			return;
1400df930be7Sderaadt 
1401df930be7Sderaadt 		if ((*samep)->val[A_ATOM] == val)
1402df930be7Sderaadt 			break;
1403df930be7Sderaadt 
1404df930be7Sderaadt 		/* XXX Need to check that there are no data dependencies
1405df930be7Sderaadt 		   between diffp and samep.  Currently, the code generator
1406df930be7Sderaadt 		   will not produce such dependencies. */
1407df930be7Sderaadt 		samep = &JT(*samep);
1408df930be7Sderaadt 	}
1409df930be7Sderaadt #ifdef notdef
1410df930be7Sderaadt 	/* XXX This doesn't cover everything. */
1411df930be7Sderaadt 	for (i = 0; i < N_ATOMS; ++i)
1412df930be7Sderaadt 		if ((*samep)->val[i] != pred->val[i])
1413df930be7Sderaadt 			return;
1414df930be7Sderaadt #endif
1415df930be7Sderaadt 	/* Pull up the node. */
1416df930be7Sderaadt 	pull = *samep;
1417df930be7Sderaadt 	*samep = JT(pull);
1418df930be7Sderaadt 	JT(pull) = *diffp;
1419df930be7Sderaadt 
1420df930be7Sderaadt 	/*
1421df930be7Sderaadt 	 * At the top of the chain, each predecessor needs to point at the
1422df930be7Sderaadt 	 * pulled up node.  Inside the chain, there is only one predecessor
1423df930be7Sderaadt 	 * to worry about.
1424df930be7Sderaadt 	 */
1425df930be7Sderaadt 	if (at_top) {
1426df930be7Sderaadt 		for (ep = b->in_edges; ep != 0; ep = ep->next) {
1427df930be7Sderaadt 			if (JT(ep->pred) == b)
1428df930be7Sderaadt 				JT(ep->pred) = pull;
1429df930be7Sderaadt 			else
1430df930be7Sderaadt 				JF(ep->pred) = pull;
1431df930be7Sderaadt 		}
1432df930be7Sderaadt 	}
1433df930be7Sderaadt 	else
1434df930be7Sderaadt 		*diffp = pull;
1435df930be7Sderaadt 
1436df930be7Sderaadt 	done = 0;
1437df930be7Sderaadt }
1438df930be7Sderaadt 
1439df930be7Sderaadt static void
opt_blks(struct block * root,int do_stmts)144019fef815Sderaadt opt_blks(struct block *root, int do_stmts)
1441df930be7Sderaadt {
1442df930be7Sderaadt 	int i, maxlevel;
1443df930be7Sderaadt 	struct block *p;
1444df930be7Sderaadt 
1445df930be7Sderaadt 	init_val();
1446df930be7Sderaadt 	maxlevel = root->level;
1447df930be7Sderaadt 	for (i = maxlevel; i >= 0; --i)
1448df930be7Sderaadt 		for (p = levels[i]; p; p = p->link)
1449df930be7Sderaadt 			opt_blk(p, do_stmts);
1450df930be7Sderaadt 
1451df930be7Sderaadt 	if (do_stmts)
1452df930be7Sderaadt 		/*
1453df930be7Sderaadt 		 * No point trying to move branches; it can't possibly
1454df930be7Sderaadt 		 * make a difference at this point.
1455df930be7Sderaadt 		 */
1456df930be7Sderaadt 		return;
1457df930be7Sderaadt 
1458df930be7Sderaadt 	for (i = 1; i <= maxlevel; ++i) {
1459df930be7Sderaadt 		for (p = levels[i]; p; p = p->link) {
1460df930be7Sderaadt 			opt_j(&p->et);
1461df930be7Sderaadt 			opt_j(&p->ef);
1462df930be7Sderaadt 		}
1463df930be7Sderaadt 	}
1464df930be7Sderaadt 	for (i = 1; i <= maxlevel; ++i) {
1465df930be7Sderaadt 		for (p = levels[i]; p; p = p->link) {
1466df930be7Sderaadt 			or_pullup(p);
1467df930be7Sderaadt 			and_pullup(p);
1468df930be7Sderaadt 		}
1469df930be7Sderaadt 	}
1470df930be7Sderaadt }
1471df930be7Sderaadt 
14728df16311Stholo static __inline void
link_inedge(struct edge * parent,struct block * child)147319fef815Sderaadt link_inedge(struct edge *parent, struct block *child)
1474df930be7Sderaadt {
1475df930be7Sderaadt 	parent->next = child->in_edges;
1476df930be7Sderaadt 	child->in_edges = parent;
1477df930be7Sderaadt }
1478df930be7Sderaadt 
1479df930be7Sderaadt static void
find_inedges(struct block * root)148019fef815Sderaadt find_inedges(struct block *root)
1481df930be7Sderaadt {
1482df930be7Sderaadt 	int i;
1483df930be7Sderaadt 	struct block *b;
1484df930be7Sderaadt 
1485df930be7Sderaadt 	for (i = 0; i < n_blocks; ++i)
1486df930be7Sderaadt 		blocks[i]->in_edges = 0;
1487df930be7Sderaadt 
1488df930be7Sderaadt 	/*
1489df930be7Sderaadt 	 * Traverse the graph, adding each edge to the predecessor
1490df930be7Sderaadt 	 * list of its successors.  Skip the leaves (i.e. level 0).
1491df930be7Sderaadt 	 */
1492df930be7Sderaadt 	for (i = root->level; i > 0; --i) {
1493df930be7Sderaadt 		for (b = levels[i]; b != 0; b = b->link) {
1494df930be7Sderaadt 			link_inedge(&b->et, JT(b));
1495df930be7Sderaadt 			link_inedge(&b->ef, JF(b));
1496df930be7Sderaadt 		}
1497df930be7Sderaadt 	}
1498df930be7Sderaadt }
1499df930be7Sderaadt 
1500df930be7Sderaadt static void
opt_root(struct block ** b)150119fef815Sderaadt opt_root(struct block **b)
1502df930be7Sderaadt {
1503df930be7Sderaadt 	struct slist *tmp, *s;
1504df930be7Sderaadt 
1505df930be7Sderaadt 	s = (*b)->stmts;
1506df930be7Sderaadt 	(*b)->stmts = 0;
1507df930be7Sderaadt 	while (BPF_CLASS((*b)->s.code) == BPF_JMP && JT(*b) == JF(*b))
1508df930be7Sderaadt 		*b = JT(*b);
1509df930be7Sderaadt 
1510df930be7Sderaadt 	tmp = (*b)->stmts;
1511df930be7Sderaadt 	if (tmp != 0)
1512df930be7Sderaadt 		sappend(s, tmp);
1513df930be7Sderaadt 	(*b)->stmts = s;
15149b113833Smickey 
15159b113833Smickey 	/*
15169b113833Smickey 	 * If the root node is a return, then there is no
15179b113833Smickey 	 * point executing any statements (since the bpf machine
15189b113833Smickey 	 * has no side effects).
15199b113833Smickey 	 */
15209b113833Smickey 	if (BPF_CLASS((*b)->s.code) == BPF_RET)
15219b113833Smickey 		(*b)->stmts = 0;
1522df930be7Sderaadt }
1523df930be7Sderaadt 
1524df930be7Sderaadt static void
opt_loop(struct block * root,int do_stmts)152519fef815Sderaadt opt_loop(struct block *root, int do_stmts)
1526df930be7Sderaadt {
1527df930be7Sderaadt 
1528df930be7Sderaadt #ifdef BDEBUG
1529df930be7Sderaadt 	if (dflag > 1)
1530df930be7Sderaadt 		opt_dump(root);
1531df930be7Sderaadt #endif
1532df930be7Sderaadt 	do {
1533df930be7Sderaadt 		done = 1;
1534df930be7Sderaadt 		find_levels(root);
1535df930be7Sderaadt 		find_dom(root);
1536df930be7Sderaadt 		find_closure(root);
1537df930be7Sderaadt 		find_inedges(root);
1538df930be7Sderaadt 		find_ud(root);
1539df930be7Sderaadt 		find_edom(root);
1540df930be7Sderaadt 		opt_blks(root, do_stmts);
1541df930be7Sderaadt #ifdef BDEBUG
1542df930be7Sderaadt 		if (dflag > 1)
1543df930be7Sderaadt 			opt_dump(root);
1544df930be7Sderaadt #endif
1545df930be7Sderaadt 	} while (!done);
1546df930be7Sderaadt }
1547df930be7Sderaadt 
1548df930be7Sderaadt /*
1549df930be7Sderaadt  * Optimize the filter code in its dag representation.
1550df930be7Sderaadt  */
1551df930be7Sderaadt void
bpf_optimize(struct block ** rootp)155219fef815Sderaadt bpf_optimize(struct block **rootp)
1553df930be7Sderaadt {
1554df930be7Sderaadt 	struct block *root;
1555df930be7Sderaadt 
1556df930be7Sderaadt 	root = *rootp;
1557df930be7Sderaadt 
1558df930be7Sderaadt 	opt_init(root);
1559df930be7Sderaadt 	opt_loop(root, 0);
1560df930be7Sderaadt 	opt_loop(root, 1);
1561df930be7Sderaadt 	intern_blocks(root);
1562df930be7Sderaadt 	opt_root(rootp);
1563df930be7Sderaadt 	opt_cleanup();
1564df930be7Sderaadt }
1565df930be7Sderaadt 
1566df930be7Sderaadt static void
make_marks(struct block * p)156719fef815Sderaadt make_marks(struct block *p)
1568df930be7Sderaadt {
1569df930be7Sderaadt 	if (!isMarked(p)) {
1570df930be7Sderaadt 		Mark(p);
1571df930be7Sderaadt 		if (BPF_CLASS(p->s.code) != BPF_RET) {
1572df930be7Sderaadt 			make_marks(JT(p));
1573df930be7Sderaadt 			make_marks(JF(p));
1574df930be7Sderaadt 		}
1575df930be7Sderaadt 	}
1576df930be7Sderaadt }
1577df930be7Sderaadt 
1578df930be7Sderaadt /*
1579df930be7Sderaadt  * Mark code array such that isMarked(i) is true
1580df930be7Sderaadt  * only for nodes that are alive.
1581df930be7Sderaadt  */
1582df930be7Sderaadt static void
mark_code(struct block * p)158319fef815Sderaadt mark_code(struct block *p)
1584df930be7Sderaadt {
1585df930be7Sderaadt 	cur_mark += 1;
1586df930be7Sderaadt 	make_marks(p);
1587df930be7Sderaadt }
1588df930be7Sderaadt 
1589df930be7Sderaadt /*
1590df930be7Sderaadt  * True iff the two stmt lists load the same value from the packet into
1591df930be7Sderaadt  * the accumulator.
1592df930be7Sderaadt  */
1593df930be7Sderaadt static int
eq_slist(struct slist * x,struct slist * y)159419fef815Sderaadt eq_slist(struct slist *x, struct slist *y)
1595df930be7Sderaadt {
1596df930be7Sderaadt 	while (1) {
1597df930be7Sderaadt 		while (x && x->s.code == NOP)
1598df930be7Sderaadt 			x = x->next;
1599df930be7Sderaadt 		while (y && y->s.code == NOP)
1600df930be7Sderaadt 			y = y->next;
1601df930be7Sderaadt 		if (x == 0)
1602df930be7Sderaadt 			return y == 0;
1603df930be7Sderaadt 		if (y == 0)
1604df930be7Sderaadt 			return x == 0;
1605df930be7Sderaadt 		if (x->s.code != y->s.code || x->s.k != y->s.k)
1606df930be7Sderaadt 			return 0;
1607df930be7Sderaadt 		x = x->next;
1608df930be7Sderaadt 		y = y->next;
1609df930be7Sderaadt 	}
1610df930be7Sderaadt }
1611df930be7Sderaadt 
16128df16311Stholo static __inline int
eq_blk(struct block * b0,struct block * b1)161319fef815Sderaadt eq_blk(struct block *b0, struct block *b1)
1614df930be7Sderaadt {
1615df930be7Sderaadt 	if (b0->s.code == b1->s.code &&
1616df930be7Sderaadt 	    b0->s.k == b1->s.k &&
1617df930be7Sderaadt 	    b0->et.succ == b1->et.succ &&
1618df930be7Sderaadt 	    b0->ef.succ == b1->ef.succ)
1619df930be7Sderaadt 		return eq_slist(b0->stmts, b1->stmts);
1620df930be7Sderaadt 	return 0;
1621df930be7Sderaadt }
1622df930be7Sderaadt 
1623df930be7Sderaadt static void
intern_blocks(struct block * root)162419fef815Sderaadt intern_blocks(struct block *root)
1625df930be7Sderaadt {
1626df930be7Sderaadt 	struct block *p;
1627df930be7Sderaadt 	int i, j;
1628df930be7Sderaadt 	int done;
1629df930be7Sderaadt  top:
1630df930be7Sderaadt 	done = 1;
1631df930be7Sderaadt 	for (i = 0; i < n_blocks; ++i)
1632df930be7Sderaadt 		blocks[i]->link = 0;
1633df930be7Sderaadt 
1634df930be7Sderaadt 	mark_code(root);
1635df930be7Sderaadt 
1636df930be7Sderaadt 	for (i = n_blocks - 1; --i >= 0; ) {
1637df930be7Sderaadt 		if (!isMarked(blocks[i]))
1638df930be7Sderaadt 			continue;
1639df930be7Sderaadt 		for (j = i + 1; j < n_blocks; ++j) {
1640df930be7Sderaadt 			if (!isMarked(blocks[j]))
1641df930be7Sderaadt 				continue;
1642df930be7Sderaadt 			if (eq_blk(blocks[i], blocks[j])) {
1643df930be7Sderaadt 				blocks[i]->link = blocks[j]->link ?
1644df930be7Sderaadt 					blocks[j]->link : blocks[j];
1645df930be7Sderaadt 				break;
1646df930be7Sderaadt 			}
1647df930be7Sderaadt 		}
1648df930be7Sderaadt 	}
1649df930be7Sderaadt 	for (i = 0; i < n_blocks; ++i) {
1650df930be7Sderaadt 		p = blocks[i];
1651df930be7Sderaadt 		if (JT(p) == 0)
1652df930be7Sderaadt 			continue;
1653df930be7Sderaadt 		if (JT(p)->link) {
1654df930be7Sderaadt 			done = 0;
1655df930be7Sderaadt 			JT(p) = JT(p)->link;
1656df930be7Sderaadt 		}
1657df930be7Sderaadt 		if (JF(p)->link) {
1658df930be7Sderaadt 			done = 0;
1659df930be7Sderaadt 			JF(p) = JF(p)->link;
1660df930be7Sderaadt 		}
1661df930be7Sderaadt 	}
1662df930be7Sderaadt 	if (!done)
1663df930be7Sderaadt 		goto top;
1664df930be7Sderaadt }
1665df930be7Sderaadt 
1666df930be7Sderaadt static void
opt_cleanup(void)1667*146262eaSjsg opt_cleanup(void)
1668df930be7Sderaadt {
1669df930be7Sderaadt 	free((void *)vnode_base);
1670df930be7Sderaadt 	free((void *)vmap);
1671df930be7Sderaadt 	free((void *)edges);
167249639a4cSderaadt 	free((void *)space1);
167349639a4cSderaadt 	free((void *)space2);
1674df930be7Sderaadt 	free((void *)levels);
1675df930be7Sderaadt 	free((void *)blocks);
1676df930be7Sderaadt }
1677df930be7Sderaadt 
1678df930be7Sderaadt /*
1679df930be7Sderaadt  * Return the number of stmts in 's'.
1680df930be7Sderaadt  */
1681df930be7Sderaadt static int
slength(struct slist * s)168219fef815Sderaadt slength(struct slist *s)
1683df930be7Sderaadt {
1684df930be7Sderaadt 	int n = 0;
1685df930be7Sderaadt 
1686df930be7Sderaadt 	for (; s; s = s->next)
1687df930be7Sderaadt 		if (s->s.code != NOP)
1688df930be7Sderaadt 			++n;
1689df930be7Sderaadt 	return n;
1690df930be7Sderaadt }
1691df930be7Sderaadt 
1692df930be7Sderaadt /*
1693df930be7Sderaadt  * Return the number of nodes reachable by 'p'.
1694df930be7Sderaadt  * All nodes should be initially unmarked.
1695df930be7Sderaadt  */
1696df930be7Sderaadt static int
count_blocks(struct block * p)169719fef815Sderaadt count_blocks(struct block *p)
1698df930be7Sderaadt {
1699df930be7Sderaadt 	if (p == 0 || isMarked(p))
1700df930be7Sderaadt 		return 0;
1701df930be7Sderaadt 	Mark(p);
1702df930be7Sderaadt 	return count_blocks(JT(p)) + count_blocks(JF(p)) + 1;
1703df930be7Sderaadt }
1704df930be7Sderaadt 
1705df930be7Sderaadt /*
1706df930be7Sderaadt  * Do a depth first search on the flow graph, numbering the
1707df930be7Sderaadt  * the basic blocks, and entering them into the 'blocks' array.`
1708df930be7Sderaadt  */
1709df930be7Sderaadt static void
number_blks_r(struct block * p)171019fef815Sderaadt number_blks_r(struct block *p)
1711df930be7Sderaadt {
1712df930be7Sderaadt 	int n;
1713df930be7Sderaadt 
1714df930be7Sderaadt 	if (p == 0 || isMarked(p))
1715df930be7Sderaadt 		return;
1716df930be7Sderaadt 
1717df930be7Sderaadt 	Mark(p);
1718df930be7Sderaadt 	n = n_blocks++;
1719df930be7Sderaadt 	p->id = n;
1720df930be7Sderaadt 	blocks[n] = p;
1721df930be7Sderaadt 
1722df930be7Sderaadt 	number_blks_r(JT(p));
1723df930be7Sderaadt 	number_blks_r(JF(p));
1724df930be7Sderaadt }
1725df930be7Sderaadt 
1726df930be7Sderaadt /*
1727df930be7Sderaadt  * Return the number of stmts in the flowgraph reachable by 'p'.
1728df930be7Sderaadt  * The nodes should be unmarked before calling.
1729df930be7Sderaadt  */
1730df930be7Sderaadt static int
count_stmts(struct block * p)173119fef815Sderaadt count_stmts(struct block *p)
1732df930be7Sderaadt {
1733df930be7Sderaadt 	int n;
1734df930be7Sderaadt 
1735df930be7Sderaadt 	if (p == 0 || isMarked(p))
1736df930be7Sderaadt 		return 0;
1737df930be7Sderaadt 	Mark(p);
1738df930be7Sderaadt 	n = count_stmts(JT(p)) + count_stmts(JF(p));
17393a418d8fSaaron 	return slength(p->stmts) + n + 1 + p->longjt + p->longjf;
1740df930be7Sderaadt }
1741df930be7Sderaadt 
1742df930be7Sderaadt /*
1743df930be7Sderaadt  * Allocate memory.  All allocation is done before optimization
1744df930be7Sderaadt  * is begun.  A linear bound on the size of all data structures is computed
1745df930be7Sderaadt  * from the total number of blocks and/or statements.
1746df930be7Sderaadt  */
1747df930be7Sderaadt static void
opt_init(struct block * root)174819fef815Sderaadt opt_init(struct block *root)
1749df930be7Sderaadt {
17509b113833Smickey 	bpf_u_int32 *p;
1751df930be7Sderaadt 	int i, n, max_stmts;
175249639a4cSderaadt 	size_t size1, size2;
1753df930be7Sderaadt 
1754df930be7Sderaadt 	/*
1755df930be7Sderaadt 	 * First, count the blocks, so we can malloc an array to map
1756df930be7Sderaadt 	 * block number to block.  Then, put the blocks into the array.
1757df930be7Sderaadt 	 */
1758df930be7Sderaadt 	unMarkAll();
1759df930be7Sderaadt 	n = count_blocks(root);
1760b8f389f9Slteo 	blocks = reallocarray(NULL, n, sizeof(*blocks));
176185a9a594Sprovos 	if (blocks == NULL)
176285a9a594Sprovos 		bpf_error("malloc");
176385a9a594Sprovos 
1764df930be7Sderaadt 	unMarkAll();
1765df930be7Sderaadt 	n_blocks = 0;
1766df930be7Sderaadt 	number_blks_r(root);
1767df930be7Sderaadt 
1768df930be7Sderaadt 	n_edges = 2 * n_blocks;
1769b8f389f9Slteo 	edges = reallocarray(NULL, n_edges, sizeof(*edges));
177085a9a594Sprovos 	if (edges == NULL)
177185a9a594Sprovos 		bpf_error("malloc");
1772df930be7Sderaadt 
1773df930be7Sderaadt 	/*
1774df930be7Sderaadt 	 * The number of levels is bounded by the number of nodes.
1775df930be7Sderaadt 	 */
1776b8f389f9Slteo 	levels = reallocarray(NULL, n_blocks, sizeof(*levels));
177785a9a594Sprovos 	if (levels == NULL)
177885a9a594Sprovos 		bpf_error("malloc");
1779df930be7Sderaadt 
17809b113833Smickey 	edgewords = n_edges / (8 * sizeof(bpf_u_int32)) + 1;
17819b113833Smickey 	nodewords = n_blocks / (8 * sizeof(bpf_u_int32)) + 1;
1782df930be7Sderaadt 
178349639a4cSderaadt 	size1 = 2;
178449639a4cSderaadt 	if (n_blocks > SIZE_MAX / size1)
178549639a4cSderaadt 		goto fail1;
178649639a4cSderaadt 	size1 *= n_blocks;
178749639a4cSderaadt 	if (nodewords > SIZE_MAX / size1)
178849639a4cSderaadt 		goto fail1;
178949639a4cSderaadt 	size1 *= nodewords;
179049639a4cSderaadt 	if (sizeof(*space1) > SIZE_MAX / size1)
179149639a4cSderaadt 		goto fail1;
179249639a4cSderaadt 	size1 *= sizeof(*space1);
179385a9a594Sprovos 
179449639a4cSderaadt 	space1 = (bpf_u_int32 *)malloc(size1);
179549639a4cSderaadt 	if (space1 == NULL) {
179649639a4cSderaadt fail1:
179749639a4cSderaadt 		bpf_error("malloc");
179849639a4cSderaadt 	}
179949639a4cSderaadt 
180049639a4cSderaadt 	size2 = n_edges;
180149639a4cSderaadt 	if (edgewords > SIZE_MAX / size2)
180249639a4cSderaadt 		goto fail2;
180349639a4cSderaadt 	size2 *= edgewords;
180449639a4cSderaadt 	if (sizeof(*space2) > SIZE_MAX / size2)
180549639a4cSderaadt 		goto fail2;
180649639a4cSderaadt 	size2 *= sizeof(*space2);
180749639a4cSderaadt 
180849639a4cSderaadt 	space2 = (bpf_u_int32 *)malloc(size2);
180949639a4cSderaadt 	if (space2 == NULL) {
181049639a4cSderaadt fail2:
181149639a4cSderaadt 		free(space1);
181249639a4cSderaadt 		bpf_error("malloc");
181349639a4cSderaadt 	}
181449639a4cSderaadt 
181549639a4cSderaadt 	p = space1;
1816df930be7Sderaadt 	all_dom_sets = p;
1817df930be7Sderaadt 	for (i = 0; i < n; ++i) {
1818df930be7Sderaadt 		blocks[i]->dom = p;
1819df930be7Sderaadt 		p += nodewords;
1820df930be7Sderaadt 	}
1821df930be7Sderaadt 	all_closure_sets = p;
1822df930be7Sderaadt 	for (i = 0; i < n; ++i) {
1823df930be7Sderaadt 		blocks[i]->closure = p;
1824df930be7Sderaadt 		p += nodewords;
1825df930be7Sderaadt 	}
182649639a4cSderaadt 	p = space2;
1827df930be7Sderaadt 	all_edge_sets = p;
1828df930be7Sderaadt 	for (i = 0; i < n; ++i) {
1829d0438536Smmcc 		struct block *b = blocks[i];
1830df930be7Sderaadt 
1831df930be7Sderaadt 		b->et.edom = p;
1832df930be7Sderaadt 		p += edgewords;
1833df930be7Sderaadt 		b->ef.edom = p;
1834df930be7Sderaadt 		p += edgewords;
1835df930be7Sderaadt 		b->et.id = i;
1836df930be7Sderaadt 		edges[i] = &b->et;
1837df930be7Sderaadt 		b->ef.id = n_blocks + i;
1838df930be7Sderaadt 		edges[n_blocks + i] = &b->ef;
1839df930be7Sderaadt 		b->et.pred = b;
1840df930be7Sderaadt 		b->ef.pred = b;
1841df930be7Sderaadt 	}
1842df930be7Sderaadt 	max_stmts = 0;
1843df930be7Sderaadt 	for (i = 0; i < n; ++i)
1844df930be7Sderaadt 		max_stmts += slength(blocks[i]->stmts) + 1;
1845df930be7Sderaadt 	/*
1846df930be7Sderaadt 	 * We allocate at most 3 value numbers per statement,
1847df930be7Sderaadt 	 * so this is an upper bound on the number of valnodes
1848df930be7Sderaadt 	 * we'll need.
1849df930be7Sderaadt 	 */
1850df930be7Sderaadt 	maxval = 3 * max_stmts;
1851b8f389f9Slteo 	vmap = reallocarray(NULL, maxval, sizeof(*vmap));
18528d58530aScanacar 	vnode_base = reallocarray(NULL, maxval, sizeof(*vnode_base));
185385a9a594Sprovos 	if (vmap == NULL || vnode_base == NULL)
185485a9a594Sprovos 		bpf_error("malloc");
1855df930be7Sderaadt }
1856df930be7Sderaadt 
1857df930be7Sderaadt /*
1858df930be7Sderaadt  * Some pointers used to convert the basic block form of the code,
1859df930be7Sderaadt  * into the array form that BPF requires.  'fstart' will point to
1860df930be7Sderaadt  * the malloc'd array while 'ftail' is used during the recursive traversal.
1861df930be7Sderaadt  */
1862df930be7Sderaadt static struct bpf_insn *fstart;
1863df930be7Sderaadt static struct bpf_insn *ftail;
1864df930be7Sderaadt 
1865df930be7Sderaadt #ifdef BDEBUG
1866df930be7Sderaadt int bids[1000];
1867df930be7Sderaadt #endif
1868df930be7Sderaadt 
18699b113833Smickey /*
18709b113833Smickey  * Returns true if successful.  Returns false if a branch has
18719b113833Smickey  * an offset that is too large.  If so, we have marked that
18729b113833Smickey  * branch so that on a subsequent iteration, it will be treated
18739b113833Smickey  * properly.
18749b113833Smickey  */
18759b113833Smickey static int
convert_code_r(struct block * p)187619fef815Sderaadt convert_code_r(struct block *p)
1877df930be7Sderaadt {
1878df930be7Sderaadt 	struct bpf_insn *dst;
1879df930be7Sderaadt 	struct slist *src;
1880df930be7Sderaadt 	int slen;
1881df930be7Sderaadt 	u_int off;
18829b113833Smickey 	int extrajmps;		/* number of extra jumps inserted */
1883a9b0695fSjakob 	struct slist **offset = NULL;
1884df930be7Sderaadt 
1885df930be7Sderaadt 	if (p == 0 || isMarked(p))
18869b113833Smickey 		return (1);
1887df930be7Sderaadt 	Mark(p);
1888df930be7Sderaadt 
18899b113833Smickey 	if (convert_code_r(JF(p)) == 0)
18909b113833Smickey 		return (0);
18919b113833Smickey 	if (convert_code_r(JT(p)) == 0)
18929b113833Smickey 		return (0);
1893df930be7Sderaadt 
1894df930be7Sderaadt 	slen = slength(p->stmts);
18959b113833Smickey 	dst = ftail -= (slen + 1 + p->longjt + p->longjf);
18969b113833Smickey 		/* inflate length by any extra jumps */
1897df930be7Sderaadt 
1898df930be7Sderaadt 	p->offset = dst - fstart;
1899df930be7Sderaadt 
1900a9b0695fSjakob 	/* generate offset[] for convenience  */
1901a9b0695fSjakob 	if (slen) {
1902ad4287e4Sdjm 		offset = calloc(slen, sizeof(struct slist *));
1903a9b0695fSjakob 		if (!offset) {
1904a9b0695fSjakob 			bpf_error("not enough core");
1905a9b0695fSjakob 			/*NOTREACHED*/
1906a9b0695fSjakob 		}
1907a9b0695fSjakob 	}
1908a9b0695fSjakob 	src = p->stmts;
1909a9b0695fSjakob 	for (off = 0; off < slen && src; off++) {
1910a9b0695fSjakob #if 0
1911a9b0695fSjakob 		printf("off=%d src=%x\n", off, src);
1912a9b0695fSjakob #endif
1913a9b0695fSjakob 		offset[off] = src;
1914a9b0695fSjakob 		src = src->next;
1915a9b0695fSjakob 	}
1916a9b0695fSjakob 
1917a9b0695fSjakob 	off = 0;
1918df930be7Sderaadt 	for (src = p->stmts; src; src = src->next) {
1919df930be7Sderaadt 		if (src->s.code == NOP)
1920df930be7Sderaadt 			continue;
1921df930be7Sderaadt 		dst->code = (u_short)src->s.code;
1922df930be7Sderaadt 		dst->k = src->s.k;
1923a9b0695fSjakob 
1924a9b0695fSjakob 		/* fill block-local relative jump */
1925a9b0695fSjakob 		if (BPF_CLASS(src->s.code) != BPF_JMP || src->s.code == (BPF_JMP|BPF_JA)) {
1926a9b0695fSjakob #if 0
1927a9b0695fSjakob 			if (src->s.jt || src->s.jf) {
1928a9b0695fSjakob 				bpf_error("illegal jmp destination");
1929a9b0695fSjakob 				/*NOTREACHED*/
1930df930be7Sderaadt 			}
1931a9b0695fSjakob #endif
1932a9b0695fSjakob 			goto filled;
1933a9b0695fSjakob 		}
1934a9b0695fSjakob 		if (off == slen - 2)	/*???*/
1935a9b0695fSjakob 			goto filled;
1936a9b0695fSjakob 
1937a9b0695fSjakob 	    {
1938a9b0695fSjakob 		int i;
1939a9b0695fSjakob 		int jt, jf;
1940a440ace2Sguenther 		static const char ljerr[] =
1941a440ace2Sguenther 		    "%s for block-local relative jump: off=%d";
1942a9b0695fSjakob 
1943a9b0695fSjakob #if 0
1944a9b0695fSjakob 		printf("code=%x off=%d %x %x\n", src->s.code,
1945a9b0695fSjakob 			off, src->s.jt, src->s.jf);
1946a9b0695fSjakob #endif
1947a9b0695fSjakob 
1948a9b0695fSjakob 		if (!src->s.jt || !src->s.jf) {
1949a9b0695fSjakob 			bpf_error(ljerr, "no jmp destination", off);
1950a9b0695fSjakob 			/*NOTREACHED*/
1951a9b0695fSjakob 		}
1952a9b0695fSjakob 
1953a9b0695fSjakob 		jt = jf = 0;
1954a9b0695fSjakob 		for (i = 0; i < slen; i++) {
1955a9b0695fSjakob 			if (offset[i] == src->s.jt) {
1956a9b0695fSjakob 				if (jt) {
1957a9b0695fSjakob 					bpf_error(ljerr, "multiple matches", off);
1958a9b0695fSjakob 					/*NOTREACHED*/
1959a9b0695fSjakob 				}
1960a9b0695fSjakob 
1961a9b0695fSjakob 				dst->jt = i - off - 1;
1962a9b0695fSjakob 				jt++;
1963a9b0695fSjakob 			}
1964a9b0695fSjakob 			if (offset[i] == src->s.jf) {
1965a9b0695fSjakob 				if (jf) {
1966a9b0695fSjakob 					bpf_error(ljerr, "multiple matches", off);
1967a9b0695fSjakob 					/*NOTREACHED*/
1968a9b0695fSjakob 				}
1969a9b0695fSjakob 				dst->jf = i - off - 1;
1970a9b0695fSjakob 				jf++;
1971a9b0695fSjakob 			}
1972a9b0695fSjakob 		}
1973a9b0695fSjakob 		if (!jt || !jf) {
1974a9b0695fSjakob 			bpf_error(ljerr, "no destination found", off);
1975a9b0695fSjakob 			/*NOTREACHED*/
1976a9b0695fSjakob 		}
1977a9b0695fSjakob 	    }
1978a9b0695fSjakob filled:
1979a9b0695fSjakob 		++dst;
1980a9b0695fSjakob 		++off;
1981a9b0695fSjakob 	}
1982a9b0695fSjakob 	free(offset);
1983a9b0695fSjakob 
1984df930be7Sderaadt #ifdef BDEBUG
1985df930be7Sderaadt 	bids[dst - fstart] = p->id + 1;
1986df930be7Sderaadt #endif
1987df930be7Sderaadt 	dst->code = (u_short)p->s.code;
1988df930be7Sderaadt 	dst->k = p->s.k;
1989df930be7Sderaadt 	if (JT(p)) {
19909b113833Smickey 		extrajmps = 0;
1991df930be7Sderaadt 		off = JT(p)->offset - (p->offset + slen) - 1;
19929b113833Smickey 		if (off >= 256) {
19939b113833Smickey 		    /* offset too large for branch, must add a jump */
19949b113833Smickey 		    if (p->longjt == 0) {
19959b113833Smickey 		    	/* mark this instruction and retry */
19969b113833Smickey 			p->longjt++;
19979b113833Smickey 			return(0);
19989b113833Smickey 		    }
19999b113833Smickey 		    /* branch if T to following jump */
20009b113833Smickey 		    dst->jt = extrajmps;
20019b113833Smickey 		    extrajmps++;
20029b113833Smickey 		    dst[extrajmps].code = BPF_JMP|BPF_JA;
20039b113833Smickey 		    dst[extrajmps].k = off - extrajmps;
20049b113833Smickey 		}
20059b113833Smickey 		else
2006df930be7Sderaadt 		    dst->jt = off;
2007df930be7Sderaadt 		off = JF(p)->offset - (p->offset + slen) - 1;
20089b113833Smickey 		if (off >= 256) {
20099b113833Smickey 		    /* offset too large for branch, must add a jump */
20109b113833Smickey 		    if (p->longjf == 0) {
20119b113833Smickey 		    	/* mark this instruction and retry */
20129b113833Smickey 			p->longjf++;
20139b113833Smickey 			return(0);
20149b113833Smickey 		    }
20159b113833Smickey 		    /* branch if F to following jump */
20169b113833Smickey 		    /* if two jumps are inserted, F goes to second one */
20179b113833Smickey 		    dst->jf = extrajmps;
20189b113833Smickey 		    extrajmps++;
20199b113833Smickey 		    dst[extrajmps].code = BPF_JMP|BPF_JA;
20209b113833Smickey 		    dst[extrajmps].k = off - extrajmps;
20219b113833Smickey 		}
20229b113833Smickey 		else
2023df930be7Sderaadt 		    dst->jf = off;
2024df930be7Sderaadt 	}
20259b113833Smickey 	return (1);
2026df930be7Sderaadt }
2027df930be7Sderaadt 
2028df930be7Sderaadt 
2029df930be7Sderaadt /*
2030df930be7Sderaadt  * Convert flowgraph intermediate representation to the
2031df930be7Sderaadt  * BPF array representation.  Set *lenp to the number of instructions.
2032df930be7Sderaadt  */
2033df930be7Sderaadt struct bpf_insn *
icode_to_fcode(struct block * root,int * lenp)203419fef815Sderaadt icode_to_fcode(struct block *root, int *lenp)
2035df930be7Sderaadt {
2036df930be7Sderaadt 	int n;
2037df930be7Sderaadt 	struct bpf_insn *fp;
2038df930be7Sderaadt 
20399b113833Smickey 	/*
20409b113833Smickey 	 * Loop doing convert_codr_r() until no branches remain
20419b113833Smickey 	 * with too-large offsets.
20429b113833Smickey 	 */
20439b113833Smickey 	while (1) {
2044df930be7Sderaadt 	    unMarkAll();
2045df930be7Sderaadt 	    n = *lenp = count_stmts(root);
2046df930be7Sderaadt 
2047ad4287e4Sdjm 	    fp = calloc(n, sizeof(*fp));
204885a9a594Sprovos 	    if (fp == NULL)
2049ad4287e4Sdjm 		    bpf_error("calloc");
205085a9a594Sprovos 
2051df930be7Sderaadt 	    fstart = fp;
2052df930be7Sderaadt 	    ftail = fp + n;
2053df930be7Sderaadt 
2054df930be7Sderaadt 	    unMarkAll();
20559b113833Smickey 	    if (convert_code_r(root))
20569b113833Smickey 		break;
20579b113833Smickey 	    free(fp);
20589b113833Smickey 	}
2059df930be7Sderaadt 
2060df930be7Sderaadt 	return fp;
2061df930be7Sderaadt }
2062df930be7Sderaadt 
2063df930be7Sderaadt #ifdef BDEBUG
20649b113833Smickey static void
opt_dump(struct block * root)2065*146262eaSjsg opt_dump(struct block *root)
2066df930be7Sderaadt {
2067df930be7Sderaadt 	struct bpf_program f;
2068df930be7Sderaadt 
2069df930be7Sderaadt 	memset(bids, 0, sizeof bids);
2070df930be7Sderaadt 	f.bf_insns = icode_to_fcode(root, &f.bf_len);
2071df930be7Sderaadt 	bpf_dump(&f, 1);
2072df930be7Sderaadt 	putchar('\n');
2073df930be7Sderaadt 	free((char *)f.bf_insns);
2074df930be7Sderaadt }
2075df930be7Sderaadt #endif
2076