xref: /plan9-contrib/sys/src/cmd/spin/pangen6.c (revision de2caf28f9ba1a56e70be94a699435d36eb50311)
1312a1df1SDavid du Colombier /***** spin: pangen6.c *****/
2312a1df1SDavid du Colombier 
3*de2caf28SDavid du Colombier /*
4*de2caf28SDavid du Colombier  * This file is part of the public release of Spin. It is subject to the
5*de2caf28SDavid du Colombier  * terms in the LICENSE file that is included in this source directory.
6*de2caf28SDavid du Colombier  * Tool documentation is available at http://spinroot.com
7*de2caf28SDavid du Colombier  */
8312a1df1SDavid du Colombier 
9312a1df1SDavid du Colombier #include "spin.h"
10312a1df1SDavid du Colombier #include "y.tab.h"
11312a1df1SDavid du Colombier 
12312a1df1SDavid du Colombier extern Ordered	 *all_names;
13312a1df1SDavid du Colombier extern FSM_use   *use_free;
14312a1df1SDavid du Colombier extern FSM_state **fsm_tbl;
15*de2caf28SDavid du Colombier extern FSM_state *fsmx;
16312a1df1SDavid du Colombier extern int	 verbose, o_max;
17312a1df1SDavid du Colombier 
18312a1df1SDavid du Colombier static FSM_trans *cur_t;
19312a1df1SDavid du Colombier static FSM_trans *expl_par;
20312a1df1SDavid du Colombier static FSM_trans *expl_var;
21312a1df1SDavid du Colombier static FSM_trans *explicit;
22312a1df1SDavid du Colombier 
23312a1df1SDavid du Colombier extern void rel_use(FSM_use *);
24312a1df1SDavid du Colombier 
25312a1df1SDavid du Colombier #define ulong	unsigned long
26312a1df1SDavid du Colombier 
27312a1df1SDavid du Colombier typedef struct Pair {
28312a1df1SDavid du Colombier 	FSM_state	*h;
29312a1df1SDavid du Colombier 	int		b;
30312a1df1SDavid du Colombier 	struct Pair	*nxt;
31312a1df1SDavid du Colombier } Pair;
32312a1df1SDavid du Colombier 
33312a1df1SDavid du Colombier typedef struct AST {
34312a1df1SDavid du Colombier 	ProcList *p;		/* proctype decl */
35312a1df1SDavid du Colombier 	int	i_st;		/* start state */
36312a1df1SDavid du Colombier 	int	nstates, nwords;
37312a1df1SDavid du Colombier 	int	relevant;
38312a1df1SDavid du Colombier 	Pair	*pairs;		/* entry and exit nodes of proper subgraphs */
39312a1df1SDavid du Colombier 	FSM_state *fsm;		/* proctype body */
40312a1df1SDavid du Colombier 	struct AST *nxt;	/* linked list */
41312a1df1SDavid du Colombier } AST;
42312a1df1SDavid du Colombier 
43312a1df1SDavid du Colombier typedef struct RPN {		/* relevant proctype names */
44312a1df1SDavid du Colombier 	Symbol	*rn;
45312a1df1SDavid du Colombier 	struct RPN *nxt;
46312a1df1SDavid du Colombier } RPN;
47312a1df1SDavid du Colombier 
48312a1df1SDavid du Colombier typedef struct ALIAS {		/* channel aliasing info */
49312a1df1SDavid du Colombier 	Lextok	*cnm;		/* this chan */
50312a1df1SDavid du Colombier 	int	origin;		/* debugging - origin of the alias */
51312a1df1SDavid du Colombier 	struct ALIAS	*alias;	/* can be an alias for these other chans */
52312a1df1SDavid du Colombier 	struct ALIAS	*nxt;	/* linked list */
53312a1df1SDavid du Colombier } ALIAS;
54312a1df1SDavid du Colombier 
55312a1df1SDavid du Colombier typedef struct ChanList {
56312a1df1SDavid du Colombier 	Lextok *s;		/* containing stmnt */
57312a1df1SDavid du Colombier 	Lextok *n;		/* point of reference - could be struct */
58312a1df1SDavid du Colombier 	struct ChanList *nxt;	/* linked list */
59312a1df1SDavid du Colombier } ChanList;
60312a1df1SDavid du Colombier 
61312a1df1SDavid du Colombier /* a chan alias can be created in one of three ways:
62312a1df1SDavid du Colombier 	assignement to chan name
63312a1df1SDavid du Colombier 		a = b -- a is now an alias for b
64312a1df1SDavid du Colombier 	passing chan name as parameter in run
65312a1df1SDavid du Colombier 		run x(b) -- proctype x(chan a)
66312a1df1SDavid du Colombier 	passing chan name through channel
67312a1df1SDavid du Colombier 		x!b -- x?a
68312a1df1SDavid du Colombier  */
69312a1df1SDavid du Colombier 
70312a1df1SDavid du Colombier #define USE		1
71312a1df1SDavid du Colombier #define DEF		2
72312a1df1SDavid du Colombier #define DEREF_DEF	4
73312a1df1SDavid du Colombier #define DEREF_USE	8
74312a1df1SDavid du Colombier 
75312a1df1SDavid du Colombier static AST	*ast;
76312a1df1SDavid du Colombier static ALIAS	*chalcur;
77312a1df1SDavid du Colombier static ALIAS	*chalias;
78312a1df1SDavid du Colombier static ChanList	*chanlist;
79312a1df1SDavid du Colombier static Slicer	*slicer;
80312a1df1SDavid du Colombier static Slicer	*rel_vars;	/* all relevant variables */
81312a1df1SDavid du Colombier static int	AST_Changes;
82312a1df1SDavid du Colombier static int	AST_Round;
83312a1df1SDavid du Colombier static RPN	*rpn;
84312a1df1SDavid du Colombier static int	in_recv = 0;
85312a1df1SDavid du Colombier 
86312a1df1SDavid du Colombier static int	AST_mutual(Lextok *, Lextok *, int);
87312a1df1SDavid du Colombier static void	AST_dominant(void);
88312a1df1SDavid du Colombier static void	AST_hidden(void);
89312a1df1SDavid du Colombier static void	AST_setcur(Lextok *);
90312a1df1SDavid du Colombier static void	check_slice(Lextok *, int);
91312a1df1SDavid du Colombier static void	curtail(AST *);
92312a1df1SDavid du Colombier static void	def_use(Lextok *, int);
93312a1df1SDavid du Colombier static void	name_AST_track(Lextok *, int);
94312a1df1SDavid du Colombier static void	show_expl(void);
95312a1df1SDavid du Colombier 
96312a1df1SDavid du Colombier static int
AST_isini(Lextok * n)97312a1df1SDavid du Colombier AST_isini(Lextok *n)	/* is this an initialized channel */
98312a1df1SDavid du Colombier {	Symbol *s;
99312a1df1SDavid du Colombier 
100312a1df1SDavid du Colombier 	if (!n || !n->sym) return 0;
101312a1df1SDavid du Colombier 
102312a1df1SDavid du Colombier 	s = n->sym;
103312a1df1SDavid du Colombier 
104312a1df1SDavid du Colombier 	if (s->type == CHAN)
105312a1df1SDavid du Colombier 		return (s->ini->ntyp == CHAN); /* freshly instantiated */
106312a1df1SDavid du Colombier 
107312a1df1SDavid du Colombier 	if (s->type == STRUCT && n->rgt)
108312a1df1SDavid du Colombier 		return AST_isini(n->rgt->lft);
109312a1df1SDavid du Colombier 
110312a1df1SDavid du Colombier 	return 0;
111312a1df1SDavid du Colombier }
112312a1df1SDavid du Colombier 
113312a1df1SDavid du Colombier static void
AST_var(Lextok * n,Symbol * s,int toplevel)114312a1df1SDavid du Colombier AST_var(Lextok *n, Symbol *s, int toplevel)
115312a1df1SDavid du Colombier {
116312a1df1SDavid du Colombier 	if (!s) return;
117312a1df1SDavid du Colombier 
118312a1df1SDavid du Colombier 	if (toplevel)
119312a1df1SDavid du Colombier 	{	if (s->context && s->type)
120312a1df1SDavid du Colombier 			printf(":%s:L:", s->context->name);
121312a1df1SDavid du Colombier 		else
122312a1df1SDavid du Colombier 			printf("G:");
123312a1df1SDavid du Colombier 	}
124312a1df1SDavid du Colombier 	printf("%s", s->name); /* array indices ignored */
125312a1df1SDavid du Colombier 
126312a1df1SDavid du Colombier 	if (s->type == STRUCT && n && n->rgt && n->rgt->lft)
127312a1df1SDavid du Colombier 	{	printf(":");
128312a1df1SDavid du Colombier 		AST_var(n->rgt->lft, n->rgt->lft->sym, 0);
129312a1df1SDavid du Colombier 	}
130312a1df1SDavid du Colombier }
131312a1df1SDavid du Colombier 
132312a1df1SDavid du Colombier static void
name_def_indices(Lextok * n,int code)133312a1df1SDavid du Colombier name_def_indices(Lextok *n, int code)
134312a1df1SDavid du Colombier {
135312a1df1SDavid du Colombier 	if (!n || !n->sym) return;
136312a1df1SDavid du Colombier 
13700d97012SDavid du Colombier 	if (n->sym->nel > 1 || n->sym->isarray)
138312a1df1SDavid du Colombier 		def_use(n->lft, code);		/* process the index */
139312a1df1SDavid du Colombier 
140312a1df1SDavid du Colombier 	if (n->sym->type == STRUCT		/* and possible deeper ones */
141312a1df1SDavid du Colombier 	&&  n->rgt)
142312a1df1SDavid du Colombier 		name_def_indices(n->rgt->lft, code);
143312a1df1SDavid du Colombier }
144312a1df1SDavid du Colombier 
145312a1df1SDavid du Colombier static void
name_def_use(Lextok * n,int code)146312a1df1SDavid du Colombier name_def_use(Lextok *n, int code)
147312a1df1SDavid du Colombier {	FSM_use *u;
148312a1df1SDavid du Colombier 
149312a1df1SDavid du Colombier 	if (!n) return;
150312a1df1SDavid du Colombier 
151312a1df1SDavid du Colombier 	if ((code&USE)
152312a1df1SDavid du Colombier 	&&  cur_t->step
153312a1df1SDavid du Colombier 	&&  cur_t->step->n)
154312a1df1SDavid du Colombier 	{	switch (cur_t->step->n->ntyp) {
155312a1df1SDavid du Colombier 		case 'c': /* possible predicate abstraction? */
156312a1df1SDavid du Colombier 			n->sym->colnr |= 2; /* yes */
157312a1df1SDavid du Colombier 			break;
158312a1df1SDavid du Colombier 		default:
159312a1df1SDavid du Colombier 			n->sym->colnr |= 1; /* no  */
160312a1df1SDavid du Colombier 			break;
161312a1df1SDavid du Colombier 		}
162312a1df1SDavid du Colombier 	}
163312a1df1SDavid du Colombier 
164312a1df1SDavid du Colombier 	for (u = cur_t->Val[0]; u; u = u->nxt)
165312a1df1SDavid du Colombier 		if (AST_mutual(n, u->n, 1)
166312a1df1SDavid du Colombier 		&&  u->special == code)
167312a1df1SDavid du Colombier 			return;
168312a1df1SDavid du Colombier 
169312a1df1SDavid du Colombier 	if (use_free)
170312a1df1SDavid du Colombier 	{	u = use_free;
171312a1df1SDavid du Colombier 		use_free = use_free->nxt;
172312a1df1SDavid du Colombier 	} else
173312a1df1SDavid du Colombier 		u = (FSM_use *) emalloc(sizeof(FSM_use));
174312a1df1SDavid du Colombier 
175312a1df1SDavid du Colombier 	u->n = n;
176312a1df1SDavid du Colombier 	u->special = code;
177312a1df1SDavid du Colombier 	u->nxt = cur_t->Val[0];
178312a1df1SDavid du Colombier 	cur_t->Val[0] = u;
179312a1df1SDavid du Colombier 
180312a1df1SDavid du Colombier 	name_def_indices(n, USE|(code&(~DEF)));	/* not def, but perhaps deref */
181312a1df1SDavid du Colombier }
182312a1df1SDavid du Colombier 
183312a1df1SDavid du Colombier static void
def_use(Lextok * now,int code)184312a1df1SDavid du Colombier def_use(Lextok *now, int code)
185312a1df1SDavid du Colombier {	Lextok *v;
186312a1df1SDavid du Colombier 
187312a1df1SDavid du Colombier 	if (now)
188312a1df1SDavid du Colombier 	switch (now->ntyp) {
189312a1df1SDavid du Colombier 	case '!':
190312a1df1SDavid du Colombier 	case UMIN:
191312a1df1SDavid du Colombier 	case '~':
192312a1df1SDavid du Colombier 	case 'c':
193312a1df1SDavid du Colombier 	case ENABLED:
194*de2caf28SDavid du Colombier 	case SET_P:
195*de2caf28SDavid du Colombier 	case GET_P:
196312a1df1SDavid du Colombier 	case ASSERT:
197312a1df1SDavid du Colombier 		def_use(now->lft, USE|code);
198312a1df1SDavid du Colombier 		break;
199312a1df1SDavid du Colombier 
200*de2caf28SDavid du Colombier 	case EVAL:
201*de2caf28SDavid du Colombier 		if (now->lft->ntyp == ',')
202*de2caf28SDavid du Colombier 		{	def_use(now->lft->lft, USE|code);
203*de2caf28SDavid du Colombier 		} else
204*de2caf28SDavid du Colombier 		{	def_use(now->lft, USE|code);
205*de2caf28SDavid du Colombier 		}
206*de2caf28SDavid du Colombier 		break;
207*de2caf28SDavid du Colombier 
208312a1df1SDavid du Colombier 	case LEN:
209312a1df1SDavid du Colombier 	case FULL:
210312a1df1SDavid du Colombier 	case EMPTY:
211312a1df1SDavid du Colombier 	case NFULL:
212312a1df1SDavid du Colombier 	case NEMPTY:
213312a1df1SDavid du Colombier 		def_use(now->lft, DEREF_USE|USE|code);
214312a1df1SDavid du Colombier 		break;
215312a1df1SDavid du Colombier 
216312a1df1SDavid du Colombier 	case '/':
217312a1df1SDavid du Colombier 	case '*':
218312a1df1SDavid du Colombier 	case '-':
219312a1df1SDavid du Colombier 	case '+':
220312a1df1SDavid du Colombier 	case '%':
221312a1df1SDavid du Colombier 	case '&':
222312a1df1SDavid du Colombier 	case '^':
223312a1df1SDavid du Colombier 	case '|':
224312a1df1SDavid du Colombier 	case LE:
225312a1df1SDavid du Colombier 	case GE:
226312a1df1SDavid du Colombier 	case GT:
227312a1df1SDavid du Colombier 	case LT:
228312a1df1SDavid du Colombier 	case NE:
229312a1df1SDavid du Colombier 	case EQ:
230312a1df1SDavid du Colombier 	case OR:
231312a1df1SDavid du Colombier 	case AND:
232312a1df1SDavid du Colombier 	case LSHIFT:
233312a1df1SDavid du Colombier 	case RSHIFT:
234312a1df1SDavid du Colombier 		def_use(now->lft, USE|code);
235312a1df1SDavid du Colombier 		def_use(now->rgt, USE|code);
236312a1df1SDavid du Colombier 		break;
237312a1df1SDavid du Colombier 
238312a1df1SDavid du Colombier 	case ASGN:
239312a1df1SDavid du Colombier 		def_use(now->lft, DEF|code);
240312a1df1SDavid du Colombier 		def_use(now->rgt, USE|code);
241312a1df1SDavid du Colombier 		break;
242312a1df1SDavid du Colombier 
243312a1df1SDavid du Colombier 	case TYPE:	/* name in parameter list */
244312a1df1SDavid du Colombier 		name_def_use(now, code);
245312a1df1SDavid du Colombier 		break;
246312a1df1SDavid du Colombier 
247312a1df1SDavid du Colombier 	case NAME:
248312a1df1SDavid du Colombier 		name_def_use(now, code);
249312a1df1SDavid du Colombier 		break;
250312a1df1SDavid du Colombier 
251312a1df1SDavid du Colombier 	case RUN:
252312a1df1SDavid du Colombier 		name_def_use(now, USE);			/* procname - not really needed */
253312a1df1SDavid du Colombier 		for (v = now->lft; v; v = v->rgt)
254312a1df1SDavid du Colombier 			def_use(v->lft, USE);		/* params */
255312a1df1SDavid du Colombier 		break;
256312a1df1SDavid du Colombier 
257312a1df1SDavid du Colombier 	case 's':
258312a1df1SDavid du Colombier 		def_use(now->lft, DEREF_DEF|DEREF_USE|USE|code);
259312a1df1SDavid du Colombier 		for (v = now->rgt; v; v = v->rgt)
260312a1df1SDavid du Colombier 			def_use(v->lft, USE|code);
261312a1df1SDavid du Colombier 		break;
262312a1df1SDavid du Colombier 
263312a1df1SDavid du Colombier 	case 'r':
264312a1df1SDavid du Colombier 		def_use(now->lft, DEREF_DEF|DEREF_USE|USE|code);
265312a1df1SDavid du Colombier 		for (v = now->rgt; v; v = v->rgt)
266312a1df1SDavid du Colombier 		{	if (v->lft->ntyp == EVAL)
267*de2caf28SDavid du Colombier 			{	if (v->lft->ntyp == ',')
268*de2caf28SDavid du Colombier 				{	def_use(v->lft->lft, code);	/* will add USE */
269*de2caf28SDavid du Colombier 				} else
270*de2caf28SDavid du Colombier 				{	def_use(v->lft, code);	/* will add USE */
271312a1df1SDavid du Colombier 				}
272*de2caf28SDavid du Colombier 			} else if (v->lft->ntyp != CONST)
273*de2caf28SDavid du Colombier 			{	def_use(v->lft, DEF|code);
274*de2caf28SDavid du Colombier 		}	}
275312a1df1SDavid du Colombier 		break;
276312a1df1SDavid du Colombier 
277312a1df1SDavid du Colombier 	case 'R':
278312a1df1SDavid du Colombier 		def_use(now->lft, DEREF_USE|USE|code);
279312a1df1SDavid du Colombier 		for (v = now->rgt; v; v = v->rgt)
280312a1df1SDavid du Colombier 		{	if (v->lft->ntyp == EVAL)
281*de2caf28SDavid du Colombier 			{	if (v->lft->ntyp == ',')
282*de2caf28SDavid du Colombier 				{	def_use(v->lft->lft, code); /* will add USE */
283*de2caf28SDavid du Colombier 				} else
284*de2caf28SDavid du Colombier 				{	def_use(v->lft, code); /* will add USE */
285*de2caf28SDavid du Colombier 		}	}	}
286312a1df1SDavid du Colombier 		break;
287312a1df1SDavid du Colombier 
288312a1df1SDavid du Colombier 	case '?':
289312a1df1SDavid du Colombier 		def_use(now->lft, USE|code);
290312a1df1SDavid du Colombier 		if (now->rgt)
291312a1df1SDavid du Colombier 		{	def_use(now->rgt->lft, code);
292312a1df1SDavid du Colombier 			def_use(now->rgt->rgt, code);
293312a1df1SDavid du Colombier 		}
294312a1df1SDavid du Colombier 		break;
295312a1df1SDavid du Colombier 
296312a1df1SDavid du Colombier 	case PRINT:
297312a1df1SDavid du Colombier 		for (v = now->lft; v; v = v->rgt)
298312a1df1SDavid du Colombier 			def_use(v->lft, USE|code);
299312a1df1SDavid du Colombier 		break;
300312a1df1SDavid du Colombier 
301312a1df1SDavid du Colombier 	case PRINTM:
302312a1df1SDavid du Colombier 		def_use(now->lft, USE);
303312a1df1SDavid du Colombier 		break;
304312a1df1SDavid du Colombier 
305312a1df1SDavid du Colombier 	case CONST:
306312a1df1SDavid du Colombier 	case ELSE:	/* ? */
307312a1df1SDavid du Colombier 	case NONPROGRESS:
308312a1df1SDavid du Colombier 	case PC_VAL:
309312a1df1SDavid du Colombier 	case   'p':
310312a1df1SDavid du Colombier 	case   'q':
311312a1df1SDavid du Colombier 		break;
312312a1df1SDavid du Colombier 
313312a1df1SDavid du Colombier 	case   '.':
314312a1df1SDavid du Colombier 	case  GOTO:
315312a1df1SDavid du Colombier 	case BREAK:
316312a1df1SDavid du Colombier 	case   '@':
317312a1df1SDavid du Colombier 	case D_STEP:
318312a1df1SDavid du Colombier 	case ATOMIC:
319312a1df1SDavid du Colombier 	case NON_ATOMIC:
320312a1df1SDavid du Colombier 	case IF:
321312a1df1SDavid du Colombier 	case DO:
322312a1df1SDavid du Colombier 	case UNLESS:
323312a1df1SDavid du Colombier 	case TIMEOUT:
324312a1df1SDavid du Colombier 	case C_CODE:
325312a1df1SDavid du Colombier 	case C_EXPR:
326312a1df1SDavid du Colombier 	default:
327312a1df1SDavid du Colombier 		break;
328312a1df1SDavid du Colombier 	}
329312a1df1SDavid du Colombier }
330312a1df1SDavid du Colombier 
331312a1df1SDavid du Colombier static int
AST_add_alias(Lextok * n,int nr)332312a1df1SDavid du Colombier AST_add_alias(Lextok *n, int nr)
333312a1df1SDavid du Colombier {	ALIAS *ca;
334312a1df1SDavid du Colombier 	int res;
335312a1df1SDavid du Colombier 
336312a1df1SDavid du Colombier 	for (ca = chalcur->alias; ca; ca = ca->nxt)
337312a1df1SDavid du Colombier 		if (AST_mutual(ca->cnm, n, 1))
338312a1df1SDavid du Colombier 		{	res = (ca->origin&nr);
339312a1df1SDavid du Colombier 			ca->origin |= nr;	/* 1, 2, or 4 - run, asgn, or rcv */
340312a1df1SDavid du Colombier 			return (res == 0);	/* 0 if already there with same origin */
341312a1df1SDavid du Colombier 		}
342312a1df1SDavid du Colombier 
343312a1df1SDavid du Colombier 	ca = (ALIAS *) emalloc(sizeof(ALIAS));
344312a1df1SDavid du Colombier 	ca->cnm = n;
345312a1df1SDavid du Colombier 	ca->origin = nr;
346312a1df1SDavid du Colombier 	ca->nxt = chalcur->alias;
347312a1df1SDavid du Colombier 	chalcur->alias = ca;
348312a1df1SDavid du Colombier 	return 1;
349312a1df1SDavid du Colombier }
350312a1df1SDavid du Colombier 
351312a1df1SDavid du Colombier static void
AST_run_alias(char * pn,char * s,Lextok * t,int parno)352312a1df1SDavid du Colombier AST_run_alias(char *pn, char *s, Lextok *t, int parno)
353312a1df1SDavid du Colombier {	Lextok *v;
354312a1df1SDavid du Colombier 	int cnt;
355312a1df1SDavid du Colombier 
356312a1df1SDavid du Colombier 	if (!t) return;
357312a1df1SDavid du Colombier 
358312a1df1SDavid du Colombier 	if (t->ntyp == RUN)
359312a1df1SDavid du Colombier 	{	if (strcmp(t->sym->name, s) == 0)
360312a1df1SDavid du Colombier 		for (v = t->lft, cnt = 1; v; v = v->rgt, cnt++)
361312a1df1SDavid du Colombier 			if (cnt == parno)
362312a1df1SDavid du Colombier 			{	AST_add_alias(v->lft, 1); /* RUN */
363312a1df1SDavid du Colombier 				break;
364312a1df1SDavid du Colombier 			}
365312a1df1SDavid du Colombier 	} else
366312a1df1SDavid du Colombier 	{	AST_run_alias(pn, s, t->lft, parno);
367312a1df1SDavid du Colombier 		AST_run_alias(pn, s, t->rgt, parno);
368312a1df1SDavid du Colombier 	}
369312a1df1SDavid du Colombier }
370312a1df1SDavid du Colombier 
371312a1df1SDavid du Colombier static void
AST_findrun(char * s,int parno)372312a1df1SDavid du Colombier AST_findrun(char *s, int parno)
373312a1df1SDavid du Colombier {	FSM_state *f;
374312a1df1SDavid du Colombier 	FSM_trans *t;
375312a1df1SDavid du Colombier 	AST *a;
376312a1df1SDavid du Colombier 
377312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)		/* automata       */
378312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)		/* control states */
379312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)		/* transitions    */
380312a1df1SDavid du Colombier 	{	if (t->step)
381312a1df1SDavid du Colombier 		AST_run_alias(a->p->n->name, s, t->step->n, parno);
382312a1df1SDavid du Colombier 	}
383312a1df1SDavid du Colombier }
384312a1df1SDavid du Colombier 
385312a1df1SDavid du Colombier static void
AST_par_chans(ProcList * p)386312a1df1SDavid du Colombier AST_par_chans(ProcList *p)	/* find local chan's init'd to chan passed as param */
387312a1df1SDavid du Colombier {	Ordered	*walk;
388312a1df1SDavid du Colombier 	Symbol	*sp;
389312a1df1SDavid du Colombier 
390312a1df1SDavid du Colombier 	for (walk = all_names; walk; walk = walk->next)
391312a1df1SDavid du Colombier 	{	sp = walk->entry;
392312a1df1SDavid du Colombier 		if (sp
393312a1df1SDavid du Colombier 		&&  sp->context
394312a1df1SDavid du Colombier 		&&  strcmp(sp->context->name, p->n->name) == 0
395312a1df1SDavid du Colombier 		&&  sp->Nid >= 0	/* not itself a param */
396312a1df1SDavid du Colombier 		&&  sp->type == CHAN
397312a1df1SDavid du Colombier 		&&  sp->ini->ntyp == NAME)	/* != CONST and != CHAN */
398312a1df1SDavid du Colombier 		{	Lextok *x = nn(ZN, 0, ZN, ZN);
399312a1df1SDavid du Colombier 			x->sym = sp;
400312a1df1SDavid du Colombier 			AST_setcur(x);
401312a1df1SDavid du Colombier 			AST_add_alias(sp->ini, 2);	/* ASGN */
402312a1df1SDavid du Colombier 	}	}
403312a1df1SDavid du Colombier }
404312a1df1SDavid du Colombier 
405312a1df1SDavid du Colombier static void
AST_para(ProcList * p)406312a1df1SDavid du Colombier AST_para(ProcList *p)
407312a1df1SDavid du Colombier {	Lextok *f, *t, *c;
408312a1df1SDavid du Colombier 	int cnt = 0;
409312a1df1SDavid du Colombier 
410312a1df1SDavid du Colombier 	AST_par_chans(p);
411312a1df1SDavid du Colombier 
412312a1df1SDavid du Colombier 	for (f = p->p; f; f = f->rgt) 		/* list of types */
413312a1df1SDavid du Colombier 	for (t = f->lft; t; t = t->rgt)
414312a1df1SDavid du Colombier 	{	if (t->ntyp != ',')
415312a1df1SDavid du Colombier 			c = t;
416312a1df1SDavid du Colombier 		else
417312a1df1SDavid du Colombier 			c = t->lft;	/* expanded struct */
418312a1df1SDavid du Colombier 
419312a1df1SDavid du Colombier 		cnt++;
420312a1df1SDavid du Colombier 		if (Sym_typ(c) == CHAN)
421312a1df1SDavid du Colombier 		{	ALIAS *na = (ALIAS *) emalloc(sizeof(ALIAS));
422312a1df1SDavid du Colombier 
423312a1df1SDavid du Colombier 			na->cnm = c;
424312a1df1SDavid du Colombier 			na->nxt = chalias;
425312a1df1SDavid du Colombier 			chalcur = chalias = na;
426312a1df1SDavid du Colombier #if 0
427312a1df1SDavid du Colombier 			printf("%s -- (par) -- ", p->n->name);
428312a1df1SDavid du Colombier 			AST_var(c, c->sym, 1);
429312a1df1SDavid du Colombier 			printf(" => <<");
430312a1df1SDavid du Colombier #endif
431312a1df1SDavid du Colombier 			AST_findrun(p->n->name, cnt);
432312a1df1SDavid du Colombier #if 0
433312a1df1SDavid du Colombier 			printf(">>\n");
434312a1df1SDavid du Colombier #endif
435312a1df1SDavid du Colombier 		}
436312a1df1SDavid du Colombier 	}
437312a1df1SDavid du Colombier }
438312a1df1SDavid du Colombier 
439312a1df1SDavid du Colombier static void
AST_haschan(Lextok * c)440312a1df1SDavid du Colombier AST_haschan(Lextok *c)
441312a1df1SDavid du Colombier {
442312a1df1SDavid du Colombier 	if (!c) return;
443312a1df1SDavid du Colombier 	if (Sym_typ(c) == CHAN)
444312a1df1SDavid du Colombier 	{	AST_add_alias(c, 2);	/* ASGN */
445312a1df1SDavid du Colombier #if 0
446312a1df1SDavid du Colombier 		printf("<<");
447312a1df1SDavid du Colombier 		AST_var(c, c->sym, 1);
448312a1df1SDavid du Colombier 		printf(">>\n");
449312a1df1SDavid du Colombier #endif
450312a1df1SDavid du Colombier 	} else
451312a1df1SDavid du Colombier 	{	AST_haschan(c->rgt);
452312a1df1SDavid du Colombier 		AST_haschan(c->lft);
453312a1df1SDavid du Colombier 	}
454312a1df1SDavid du Colombier }
455312a1df1SDavid du Colombier 
456312a1df1SDavid du Colombier static int
AST_nrpar(Lextok * n)457312a1df1SDavid du Colombier AST_nrpar(Lextok *n) /* 's' or 'r' */
458312a1df1SDavid du Colombier {	Lextok *m;
459312a1df1SDavid du Colombier 	int j = 0;
460312a1df1SDavid du Colombier 
461312a1df1SDavid du Colombier 	for (m = n->rgt; m; m = m->rgt)
462312a1df1SDavid du Colombier 		j++;
463312a1df1SDavid du Colombier 	return j;
464312a1df1SDavid du Colombier }
465312a1df1SDavid du Colombier 
466312a1df1SDavid du Colombier static int
AST_ord(Lextok * n,Lextok * s)467312a1df1SDavid du Colombier AST_ord(Lextok *n, Lextok *s)
468312a1df1SDavid du Colombier {	Lextok *m;
469312a1df1SDavid du Colombier 	int j = 0;
470312a1df1SDavid du Colombier 
471312a1df1SDavid du Colombier 	for (m = n->rgt; m; m = m->rgt)
472312a1df1SDavid du Colombier 	{	j++;
473312a1df1SDavid du Colombier 		if (s->sym == m->lft->sym)
474312a1df1SDavid du Colombier 			return j;
475312a1df1SDavid du Colombier 	}
476312a1df1SDavid du Colombier 	return 0;
477312a1df1SDavid du Colombier }
478312a1df1SDavid du Colombier 
479312a1df1SDavid du Colombier #if 0
480312a1df1SDavid du Colombier static void
481312a1df1SDavid du Colombier AST_ownership(Symbol *s)
482312a1df1SDavid du Colombier {
483312a1df1SDavid du Colombier 	if (!s) return;
484312a1df1SDavid du Colombier 	printf("%s:", s->name);
485312a1df1SDavid du Colombier 	AST_ownership(s->owner);
486312a1df1SDavid du Colombier }
487312a1df1SDavid du Colombier #endif
488312a1df1SDavid du Colombier 
489312a1df1SDavid du Colombier static int
AST_mutual(Lextok * a,Lextok * b,int toplevel)490312a1df1SDavid du Colombier AST_mutual(Lextok *a, Lextok *b, int toplevel)
491312a1df1SDavid du Colombier {	Symbol *as, *bs;
492312a1df1SDavid du Colombier 
493312a1df1SDavid du Colombier 	if (!a && !b) return 1;
494312a1df1SDavid du Colombier 
495312a1df1SDavid du Colombier 	if (!a || !b) return 0;
496312a1df1SDavid du Colombier 
497312a1df1SDavid du Colombier 	as = a->sym;
498312a1df1SDavid du Colombier 	bs = b->sym;
499312a1df1SDavid du Colombier 
500312a1df1SDavid du Colombier 	if (!as || !bs) return 0;
501312a1df1SDavid du Colombier 
502312a1df1SDavid du Colombier 	if (toplevel && as->context != bs->context)
503312a1df1SDavid du Colombier 		return 0;
504312a1df1SDavid du Colombier 
505312a1df1SDavid du Colombier 	if (as->type != bs->type)
506312a1df1SDavid du Colombier 		return 0;
507312a1df1SDavid du Colombier 
508312a1df1SDavid du Colombier 	if (strcmp(as->name, bs->name) != 0)
509312a1df1SDavid du Colombier 		return 0;
510312a1df1SDavid du Colombier 
51100d97012SDavid du Colombier 	if (as->type == STRUCT && a->rgt && b->rgt)	/* we know that a and b are not null */
512312a1df1SDavid du Colombier 		return AST_mutual(a->rgt->lft, b->rgt->lft, 0);
513312a1df1SDavid du Colombier 
514312a1df1SDavid du Colombier 	return 1;
515312a1df1SDavid du Colombier }
516312a1df1SDavid du Colombier 
517312a1df1SDavid du Colombier static void
AST_setcur(Lextok * n)518312a1df1SDavid du Colombier AST_setcur(Lextok *n)	/* set chalcur */
519312a1df1SDavid du Colombier {	ALIAS *ca;
520312a1df1SDavid du Colombier 
521312a1df1SDavid du Colombier 	for (ca = chalias; ca; ca = ca->nxt)
522312a1df1SDavid du Colombier 		if (AST_mutual(ca->cnm, n, 1))	/* if same chan */
523312a1df1SDavid du Colombier 		{	chalcur = ca;
524312a1df1SDavid du Colombier 			return;
525312a1df1SDavid du Colombier 		}
526312a1df1SDavid du Colombier 
527312a1df1SDavid du Colombier 	ca = (ALIAS *) emalloc(sizeof(ALIAS));
528312a1df1SDavid du Colombier 	ca->cnm = n;
529312a1df1SDavid du Colombier 	ca->nxt = chalias;
530312a1df1SDavid du Colombier 	chalcur = chalias = ca;
531312a1df1SDavid du Colombier }
532312a1df1SDavid du Colombier 
533312a1df1SDavid du Colombier static void
AST_other(AST * a)534312a1df1SDavid du Colombier AST_other(AST *a)	/* check chan params in asgns and recvs */
535312a1df1SDavid du Colombier {	FSM_state *f;
536312a1df1SDavid du Colombier 	FSM_trans *t;
537312a1df1SDavid du Colombier 	FSM_use *u;
538312a1df1SDavid du Colombier 	ChanList *cl;
539312a1df1SDavid du Colombier 
540312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)		/* control states */
541312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)		/* transitions    */
542312a1df1SDavid du Colombier 	for (u = t->Val[0]; u; u = u->nxt)	/* def/use info   */
543312a1df1SDavid du Colombier 		if (Sym_typ(u->n) == CHAN
544312a1df1SDavid du Colombier 		&&  (u->special&DEF))		/* def of chan-name  */
545312a1df1SDavid du Colombier 		{	AST_setcur(u->n);
546312a1df1SDavid du Colombier 			switch (t->step->n->ntyp) {
547312a1df1SDavid du Colombier 			case ASGN:
548312a1df1SDavid du Colombier 				AST_haschan(t->step->n->rgt);
549312a1df1SDavid du Colombier 				break;
550312a1df1SDavid du Colombier 			case 'r':
551312a1df1SDavid du Colombier 				/* guess sends where name may originate */
552312a1df1SDavid du Colombier 				for (cl = chanlist; cl; cl = cl->nxt)	/* all sends */
55300d97012SDavid du Colombier 				{	int aa = AST_nrpar(cl->s);
55400d97012SDavid du Colombier 					int bb = AST_nrpar(t->step->n);
55500d97012SDavid du Colombier 					if (aa != bb)	/* matching nrs of params */
556312a1df1SDavid du Colombier 						continue;
557312a1df1SDavid du Colombier 
55800d97012SDavid du Colombier 					aa = AST_ord(cl->s, cl->n);
55900d97012SDavid du Colombier 					bb = AST_ord(t->step->n, u->n);
56000d97012SDavid du Colombier 					if (aa != bb)	/* same position in parlist */
561312a1df1SDavid du Colombier 						continue;
562312a1df1SDavid du Colombier 
563312a1df1SDavid du Colombier 					AST_add_alias(cl->n, 4); /* RCV assume possible match */
564312a1df1SDavid du Colombier 				}
565312a1df1SDavid du Colombier 				break;
566312a1df1SDavid du Colombier 			default:
567312a1df1SDavid du Colombier 				printf("type = %d\n", t->step->n->ntyp);
568312a1df1SDavid du Colombier 				non_fatal("unexpected chan def type", (char *) 0);
569312a1df1SDavid du Colombier 				break;
570312a1df1SDavid du Colombier 		}	}
571312a1df1SDavid du Colombier }
572312a1df1SDavid du Colombier 
573312a1df1SDavid du Colombier static void
AST_aliases(void)574312a1df1SDavid du Colombier AST_aliases(void)
575312a1df1SDavid du Colombier {	ALIAS *na, *ca;
576312a1df1SDavid du Colombier 
577312a1df1SDavid du Colombier 	for (na = chalias; na; na = na->nxt)
578312a1df1SDavid du Colombier 	{	printf("\npossible aliases of ");
579312a1df1SDavid du Colombier 		AST_var(na->cnm, na->cnm->sym, 1);
580312a1df1SDavid du Colombier 		printf("\n\t");
581312a1df1SDavid du Colombier 		for (ca = na->alias; ca; ca = ca->nxt)
582312a1df1SDavid du Colombier 		{	if (!ca->cnm->sym)
583312a1df1SDavid du Colombier 				printf("no valid name ");
584312a1df1SDavid du Colombier 			else
585312a1df1SDavid du Colombier 				AST_var(ca->cnm, ca->cnm->sym, 1);
586312a1df1SDavid du Colombier 			printf("<");
587312a1df1SDavid du Colombier 			if (ca->origin & 1) printf("RUN ");
588312a1df1SDavid du Colombier 			if (ca->origin & 2) printf("ASGN ");
589312a1df1SDavid du Colombier 			if (ca->origin & 4) printf("RCV ");
590312a1df1SDavid du Colombier 			printf("[%s]", AST_isini(ca->cnm)?"Initzd":"Name");
591312a1df1SDavid du Colombier 			printf(">");
592312a1df1SDavid du Colombier 			if (ca->nxt) printf(", ");
593312a1df1SDavid du Colombier 		}
594312a1df1SDavid du Colombier 		printf("\n");
595312a1df1SDavid du Colombier 	}
596312a1df1SDavid du Colombier 	printf("\n");
597312a1df1SDavid du Colombier }
598312a1df1SDavid du Colombier 
599312a1df1SDavid du Colombier static void
AST_indirect(FSM_use * uin,FSM_trans * t,char * cause,char * pn)600312a1df1SDavid du Colombier AST_indirect(FSM_use *uin, FSM_trans *t, char *cause, char *pn)
601312a1df1SDavid du Colombier {	FSM_use *u;
602312a1df1SDavid du Colombier 
603312a1df1SDavid du Colombier 	/* this is a newly discovered relevant statement */
604312a1df1SDavid du Colombier 	/* all vars it uses to contribute to its DEF are new criteria */
605312a1df1SDavid du Colombier 
606312a1df1SDavid du Colombier 	if (!(t->relevant&1)) AST_Changes++;
607312a1df1SDavid du Colombier 
608312a1df1SDavid du Colombier 	t->round = AST_Round;
609312a1df1SDavid du Colombier 	t->relevant = 1;
610312a1df1SDavid du Colombier 
611312a1df1SDavid du Colombier 	if ((verbose&32) && t->step)
612312a1df1SDavid du Colombier 	{	printf("\tDR %s [[ ", pn);
613312a1df1SDavid du Colombier 		comment(stdout, t->step->n, 0);
614312a1df1SDavid du Colombier 		printf("]]\n\t\tfully relevant %s", cause);
615312a1df1SDavid du Colombier 		if (uin) { printf(" due to "); AST_var(uin->n, uin->n->sym, 1); }
616312a1df1SDavid du Colombier 		printf("\n");
617312a1df1SDavid du Colombier 	}
618312a1df1SDavid du Colombier 	for (u = t->Val[0]; u; u = u->nxt)
619312a1df1SDavid du Colombier 		if (u != uin
620312a1df1SDavid du Colombier 		&& (u->special&(USE|DEREF_USE)))
621312a1df1SDavid du Colombier 		{	if (verbose&32)
622312a1df1SDavid du Colombier 			{	printf("\t\t\tuses(%d): ", u->special);
623312a1df1SDavid du Colombier 				AST_var(u->n, u->n->sym, 1);
624312a1df1SDavid du Colombier 				printf("\n");
625312a1df1SDavid du Colombier 			}
626312a1df1SDavid du Colombier 			name_AST_track(u->n, u->special);	/* add to slice criteria */
627312a1df1SDavid du Colombier 		}
628312a1df1SDavid du Colombier }
629312a1df1SDavid du Colombier 
630312a1df1SDavid du Colombier static void
def_relevant(char * pn,FSM_trans * t,Lextok * n,int ischan)631312a1df1SDavid du Colombier def_relevant(char *pn, FSM_trans *t, Lextok *n, int ischan)
632312a1df1SDavid du Colombier {	FSM_use *u;
633312a1df1SDavid du Colombier 	ALIAS *na, *ca;
634312a1df1SDavid du Colombier 	int chanref;
635312a1df1SDavid du Colombier 
636312a1df1SDavid du Colombier 	/* look for all DEF's of n
637312a1df1SDavid du Colombier 	 *	mark those stmnts relevant
638312a1df1SDavid du Colombier 	 *	mark all var USEs in those stmnts as criteria
639312a1df1SDavid du Colombier 	 */
640312a1df1SDavid du Colombier 
641312a1df1SDavid du Colombier 	if (n->ntyp != ELSE)
642312a1df1SDavid du Colombier 	for (u = t->Val[0]; u; u = u->nxt)
643312a1df1SDavid du Colombier 	{	chanref = (Sym_typ(u->n) == CHAN);
644312a1df1SDavid du Colombier 
645312a1df1SDavid du Colombier 		if (ischan != chanref			/* no possible match  */
646312a1df1SDavid du Colombier 		|| !(u->special&(DEF|DEREF_DEF)))	/* not a def */
647312a1df1SDavid du Colombier 			continue;
648312a1df1SDavid du Colombier 
649312a1df1SDavid du Colombier 		if (AST_mutual(u->n, n, 1))
650312a1df1SDavid du Colombier 		{	AST_indirect(u, t, "(exact match)", pn);
651312a1df1SDavid du Colombier 			continue;
652312a1df1SDavid du Colombier 		}
653312a1df1SDavid du Colombier 
654312a1df1SDavid du Colombier 		if (chanref)
655312a1df1SDavid du Colombier 		for (na = chalias; na; na = na->nxt)
656312a1df1SDavid du Colombier 		{	if (!AST_mutual(u->n, na->cnm, 1))
657312a1df1SDavid du Colombier 				continue;
658312a1df1SDavid du Colombier 			for (ca = na->alias; ca; ca = ca->nxt)
659312a1df1SDavid du Colombier 				if (AST_mutual(ca->cnm, n, 1)
660312a1df1SDavid du Colombier 				&&  AST_isini(ca->cnm))
661312a1df1SDavid du Colombier 				{	AST_indirect(u, t, "(alias match)", pn);
662312a1df1SDavid du Colombier 					break;
663312a1df1SDavid du Colombier 				}
664312a1df1SDavid du Colombier 			if (ca) break;
665312a1df1SDavid du Colombier 	}	}
666312a1df1SDavid du Colombier }
667312a1df1SDavid du Colombier 
668312a1df1SDavid du Colombier static void
AST_relevant(Lextok * n)669312a1df1SDavid du Colombier AST_relevant(Lextok *n)
670312a1df1SDavid du Colombier {	AST *a;
671312a1df1SDavid du Colombier 	FSM_state *f;
672312a1df1SDavid du Colombier 	FSM_trans *t;
673312a1df1SDavid du Colombier 	int ischan;
674312a1df1SDavid du Colombier 
675312a1df1SDavid du Colombier 	/* look for all DEF's of n
676312a1df1SDavid du Colombier 	 *	mark those stmnts relevant
677312a1df1SDavid du Colombier 	 *	mark all var USEs in those stmnts as criteria
678312a1df1SDavid du Colombier 	 */
679312a1df1SDavid du Colombier 
680312a1df1SDavid du Colombier 	if (!n) return;
681312a1df1SDavid du Colombier 	ischan = (Sym_typ(n) == CHAN);
682312a1df1SDavid du Colombier 
683312a1df1SDavid du Colombier 	if (verbose&32)
684312a1df1SDavid du Colombier 	{	printf("<<ast_relevant (ntyp=%d) ", n->ntyp);
685312a1df1SDavid du Colombier 		AST_var(n, n->sym, 1);
686312a1df1SDavid du Colombier 		printf(">>\n");
687312a1df1SDavid du Colombier 	}
688312a1df1SDavid du Colombier 
689312a1df1SDavid du Colombier 	for (t = expl_par; t; t = t->nxt)	/* param assignments */
690312a1df1SDavid du Colombier 	{	if (!(t->relevant&1))
691312a1df1SDavid du Colombier 		def_relevant(":params:", t, n, ischan);
692312a1df1SDavid du Colombier 	}
693312a1df1SDavid du Colombier 
694312a1df1SDavid du Colombier 	for (t = expl_var; t; t = t->nxt)
695312a1df1SDavid du Colombier 	{	if (!(t->relevant&1))		/* var inits */
696312a1df1SDavid du Colombier 		def_relevant(":vars:", t, n, ischan);
697312a1df1SDavid du Colombier 	}
698312a1df1SDavid du Colombier 
699312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)		/* all other stmnts */
70000d97012SDavid du Colombier 	{	if (a->p->b != N_CLAIM && a->p->b != E_TRACE && a->p->b != N_TRACE)
701312a1df1SDavid du Colombier 		for (f = a->fsm; f; f = f->nxt)
702312a1df1SDavid du Colombier 		for (t = f->t; t; t = t->nxt)
703312a1df1SDavid du Colombier 		{	if (!(t->relevant&1))
704312a1df1SDavid du Colombier 			def_relevant(a->p->n->name, t, n, ischan);
705312a1df1SDavid du Colombier 	}	}
706312a1df1SDavid du Colombier }
707312a1df1SDavid du Colombier 
708312a1df1SDavid du Colombier static int
AST_relpar(char * s)709312a1df1SDavid du Colombier AST_relpar(char *s)
710312a1df1SDavid du Colombier {	FSM_trans *t, *T;
711312a1df1SDavid du Colombier 	FSM_use *u;
712312a1df1SDavid du Colombier 
713312a1df1SDavid du Colombier 	for (T = expl_par; T; T = (T == expl_par)?expl_var: (FSM_trans *) 0)
714312a1df1SDavid du Colombier 	for (t = T; t; t = t->nxt)
715312a1df1SDavid du Colombier 	{	if (t->relevant&1)
716312a1df1SDavid du Colombier 		for (u = t->Val[0]; u; u = u->nxt)
717312a1df1SDavid du Colombier 		{	if (u->n->sym->type
718312a1df1SDavid du Colombier 			&&  u->n->sym->context
719312a1df1SDavid du Colombier 			&&  strcmp(u->n->sym->context->name, s) == 0)
720312a1df1SDavid du Colombier 			{
721312a1df1SDavid du Colombier 				if (verbose&32)
722312a1df1SDavid du Colombier 				{	printf("proctype %s relevant, due to symbol ", s);
723312a1df1SDavid du Colombier 					AST_var(u->n, u->n->sym, 1);
724312a1df1SDavid du Colombier 					printf("\n");
725312a1df1SDavid du Colombier 				}
726312a1df1SDavid du Colombier 				return 1;
727312a1df1SDavid du Colombier 	}	}	}
728312a1df1SDavid du Colombier 	return 0;
729312a1df1SDavid du Colombier }
730312a1df1SDavid du Colombier 
731312a1df1SDavid du Colombier static void
AST_dorelevant(void)732312a1df1SDavid du Colombier AST_dorelevant(void)
733312a1df1SDavid du Colombier {	AST *a;
734312a1df1SDavid du Colombier 	RPN *r;
735312a1df1SDavid du Colombier 
736312a1df1SDavid du Colombier 	for (r = rpn; r; r = r->nxt)
737312a1df1SDavid du Colombier 	{	for (a = ast; a; a = a->nxt)
738312a1df1SDavid du Colombier 			if (strcmp(a->p->n->name, r->rn->name) == 0)
739312a1df1SDavid du Colombier 			{	a->relevant |= 1;
740312a1df1SDavid du Colombier 				break;
741312a1df1SDavid du Colombier 			}
742312a1df1SDavid du Colombier 		if (!a)
743312a1df1SDavid du Colombier 		fatal("cannot find proctype %s", r->rn->name);
744312a1df1SDavid du Colombier 	}
745312a1df1SDavid du Colombier }
746312a1df1SDavid du Colombier 
747312a1df1SDavid du Colombier static void
AST_procisrelevant(Symbol * s)748312a1df1SDavid du Colombier AST_procisrelevant(Symbol *s)
749312a1df1SDavid du Colombier {	RPN *r;
750312a1df1SDavid du Colombier 	for (r = rpn; r; r = r->nxt)
751312a1df1SDavid du Colombier 		if (strcmp(r->rn->name, s->name) == 0)
752312a1df1SDavid du Colombier 			return;
753312a1df1SDavid du Colombier 	r = (RPN *) emalloc(sizeof(RPN));
754312a1df1SDavid du Colombier 	r->rn = s;
755312a1df1SDavid du Colombier 	r->nxt = rpn;
756312a1df1SDavid du Colombier 	rpn = r;
757312a1df1SDavid du Colombier }
758312a1df1SDavid du Colombier 
759312a1df1SDavid du Colombier static int
AST_proc_isrel(char * s)760312a1df1SDavid du Colombier AST_proc_isrel(char *s)
761312a1df1SDavid du Colombier {	AST *a;
762312a1df1SDavid du Colombier 
763312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)
764312a1df1SDavid du Colombier 		if (strcmp(a->p->n->name, s) == 0)
765312a1df1SDavid du Colombier 			return (a->relevant&1);
766312a1df1SDavid du Colombier 	non_fatal("cannot happen, missing proc in ast", (char *) 0);
767312a1df1SDavid du Colombier 	return 0;
768312a1df1SDavid du Colombier }
769312a1df1SDavid du Colombier 
770312a1df1SDavid du Colombier static int
AST_scoutrun(Lextok * t)771312a1df1SDavid du Colombier AST_scoutrun(Lextok *t)
772312a1df1SDavid du Colombier {
773312a1df1SDavid du Colombier 	if (!t) return 0;
774312a1df1SDavid du Colombier 
775312a1df1SDavid du Colombier 	if (t->ntyp == RUN)
776312a1df1SDavid du Colombier 		return AST_proc_isrel(t->sym->name);
777312a1df1SDavid du Colombier 	return (AST_scoutrun(t->lft) || AST_scoutrun(t->rgt));
778312a1df1SDavid du Colombier }
779312a1df1SDavid du Colombier 
780312a1df1SDavid du Colombier static void
AST_tagruns(void)781312a1df1SDavid du Colombier AST_tagruns(void)
782312a1df1SDavid du Colombier {	AST *a;
783312a1df1SDavid du Colombier 	FSM_state *f;
784312a1df1SDavid du Colombier 	FSM_trans *t;
785312a1df1SDavid du Colombier 
786312a1df1SDavid du Colombier 	/* if any stmnt inside a proctype is relevant
787312a1df1SDavid du Colombier 	 * or any parameter passed in a run
788312a1df1SDavid du Colombier 	 * then so are all the run statements on that proctype
789312a1df1SDavid du Colombier 	 */
790312a1df1SDavid du Colombier 
791312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)
79200d97012SDavid du Colombier 	{	if (a->p->b == N_CLAIM || a->p->b == I_PROC
79300d97012SDavid du Colombier 		||  a->p->b == E_TRACE || a->p->b == N_TRACE)
794312a1df1SDavid du Colombier 		{	a->relevant |= 1;	/* the proctype is relevant */
795312a1df1SDavid du Colombier 			continue;
796312a1df1SDavid du Colombier 		}
797312a1df1SDavid du Colombier 		if (AST_relpar(a->p->n->name))
798312a1df1SDavid du Colombier 			a->relevant |= 1;
799312a1df1SDavid du Colombier 		else
800312a1df1SDavid du Colombier 		{	for (f = a->fsm; f; f = f->nxt)
801312a1df1SDavid du Colombier 			for (t = f->t; t; t = t->nxt)
802312a1df1SDavid du Colombier 				if (t->relevant)
803312a1df1SDavid du Colombier 					goto yes;
804312a1df1SDavid du Colombier yes:			if (f)
805312a1df1SDavid du Colombier 				a->relevant |= 1;
806312a1df1SDavid du Colombier 		}
807312a1df1SDavid du Colombier 	}
808312a1df1SDavid du Colombier 
809312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)
810312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)
811312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)
812312a1df1SDavid du Colombier 		if (t->step
813312a1df1SDavid du Colombier 		&&  AST_scoutrun(t->step->n))
814312a1df1SDavid du Colombier 		{	AST_indirect((FSM_use *)0, t, ":run:", a->p->n->name);
815312a1df1SDavid du Colombier 			/* BUT, not all actual params are relevant */
816312a1df1SDavid du Colombier 		}
817312a1df1SDavid du Colombier }
818312a1df1SDavid du Colombier 
819312a1df1SDavid du Colombier static void
AST_report(AST * a,Element * e)820312a1df1SDavid du Colombier AST_report(AST *a, Element *e)	/* ALSO deduce irrelevant vars */
821312a1df1SDavid du Colombier {
822312a1df1SDavid du Colombier 	if (!(a->relevant&2))
823312a1df1SDavid du Colombier 	{	a->relevant |= 2;
824312a1df1SDavid du Colombier 		printf("spin: redundant in proctype %s (for given property):\n",
825312a1df1SDavid du Colombier 			a->p->n->name);
826312a1df1SDavid du Colombier 	}
82700d97012SDavid du Colombier 	printf("      %s:%d (state %d)",
828312a1df1SDavid du Colombier 		e->n?e->n->fn->name:"-",
82900d97012SDavid du Colombier 		e->n?e->n->ln:-1,
830312a1df1SDavid du Colombier 		e->seqno);
831312a1df1SDavid du Colombier 	printf("	[");
832312a1df1SDavid du Colombier 	comment(stdout, e->n, 0);
833312a1df1SDavid du Colombier 	printf("]\n");
834312a1df1SDavid du Colombier }
835312a1df1SDavid du Colombier 
836312a1df1SDavid du Colombier static int
AST_always(Lextok * n)837312a1df1SDavid du Colombier AST_always(Lextok *n)
838312a1df1SDavid du Colombier {
839312a1df1SDavid du Colombier 	if (!n) return 0;
840312a1df1SDavid du Colombier 
841312a1df1SDavid du Colombier 	if (n->ntyp == '@'	/* -end */
842312a1df1SDavid du Colombier 	||  n->ntyp == 'p')	/* remote reference */
843312a1df1SDavid du Colombier 		return 1;
844312a1df1SDavid du Colombier 	return AST_always(n->lft) || AST_always(n->rgt);
845312a1df1SDavid du Colombier }
846312a1df1SDavid du Colombier 
847312a1df1SDavid du Colombier static void
AST_edge_dump(AST * a,FSM_state * f)848312a1df1SDavid du Colombier AST_edge_dump(AST *a, FSM_state *f)
849312a1df1SDavid du Colombier {	FSM_trans *t;
850312a1df1SDavid du Colombier 	FSM_use *u;
851312a1df1SDavid du Colombier 
852312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)	/* edges */
853312a1df1SDavid du Colombier 	{
854312a1df1SDavid du Colombier 		if (t->step && AST_always(t->step->n))
855312a1df1SDavid du Colombier 			t->relevant |= 1;	/* always relevant */
856312a1df1SDavid du Colombier 
857312a1df1SDavid du Colombier 		if (verbose&32)
858312a1df1SDavid du Colombier 		{	switch (t->relevant) {
859312a1df1SDavid du Colombier 			case  0: printf("     "); break;
860312a1df1SDavid du Colombier 			case  1: printf("*%3d ", t->round); break;
861312a1df1SDavid du Colombier 			case  2: printf("+%3d ", t->round); break;
862312a1df1SDavid du Colombier 			case  3: printf("#%3d ", t->round); break;
863312a1df1SDavid du Colombier 			default: printf("? "); break;
864312a1df1SDavid du Colombier 			}
865312a1df1SDavid du Colombier 
866312a1df1SDavid du Colombier 			printf("%d\t->\t%d\t", f->from, t->to);
867312a1df1SDavid du Colombier 			if (t->step)
868312a1df1SDavid du Colombier 				comment(stdout, t->step->n, 0);
869312a1df1SDavid du Colombier 			else
870312a1df1SDavid du Colombier 				printf("Unless");
871312a1df1SDavid du Colombier 
872312a1df1SDavid du Colombier 			for (u = t->Val[0]; u; u = u->nxt)
873312a1df1SDavid du Colombier 			{	printf(" <");
874312a1df1SDavid du Colombier 				AST_var(u->n, u->n->sym, 1);
875312a1df1SDavid du Colombier 				printf(":%d>", u->special);
876312a1df1SDavid du Colombier 			}
877312a1df1SDavid du Colombier 			printf("\n");
878312a1df1SDavid du Colombier 		} else
879312a1df1SDavid du Colombier 		{	if (t->relevant)
880312a1df1SDavid du Colombier 				continue;
881312a1df1SDavid du Colombier 
882312a1df1SDavid du Colombier 			if (t->step)
883312a1df1SDavid du Colombier 			switch(t->step->n->ntyp) {
884312a1df1SDavid du Colombier 			case ASGN:
885312a1df1SDavid du Colombier 			case 's':
886312a1df1SDavid du Colombier 			case 'r':
887312a1df1SDavid du Colombier 			case 'c':
888312a1df1SDavid du Colombier 				if (t->step->n->lft->ntyp != CONST)
889312a1df1SDavid du Colombier 					AST_report(a, t->step);
890312a1df1SDavid du Colombier 				break;
891312a1df1SDavid du Colombier 
892312a1df1SDavid du Colombier 			case PRINT:	/* don't report */
893312a1df1SDavid du Colombier 			case PRINTM:
894312a1df1SDavid du Colombier 			case ASSERT:
895312a1df1SDavid du Colombier 			case C_CODE:
896312a1df1SDavid du Colombier 			case C_EXPR:
897312a1df1SDavid du Colombier 			default:
898312a1df1SDavid du Colombier 				break;
899312a1df1SDavid du Colombier 	}	}	}
900312a1df1SDavid du Colombier }
901312a1df1SDavid du Colombier 
902312a1df1SDavid du Colombier static void
AST_dfs(AST * a,int s,int vis)903312a1df1SDavid du Colombier AST_dfs(AST *a, int s, int vis)
904312a1df1SDavid du Colombier {	FSM_state *f;
905312a1df1SDavid du Colombier 	FSM_trans *t;
906312a1df1SDavid du Colombier 
907312a1df1SDavid du Colombier 	f = fsm_tbl[s];
908312a1df1SDavid du Colombier 	if (f->seen) return;
909312a1df1SDavid du Colombier 
910312a1df1SDavid du Colombier 	f->seen = 1;
911312a1df1SDavid du Colombier 	if (vis) AST_edge_dump(a, f);
912312a1df1SDavid du Colombier 
913312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)
914312a1df1SDavid du Colombier 		AST_dfs(a, t->to, vis);
915312a1df1SDavid du Colombier }
916312a1df1SDavid du Colombier 
917312a1df1SDavid du Colombier static void
AST_dump(AST * a)918312a1df1SDavid du Colombier AST_dump(AST *a)
919312a1df1SDavid du Colombier {	FSM_state *f;
920312a1df1SDavid du Colombier 
921312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)
922312a1df1SDavid du Colombier 	{	f->seen = 0;
923312a1df1SDavid du Colombier 		fsm_tbl[f->from] = f;
924312a1df1SDavid du Colombier 	}
925312a1df1SDavid du Colombier 
926312a1df1SDavid du Colombier 	if (verbose&32)
927312a1df1SDavid du Colombier 		printf("AST_START %s from %d\n", a->p->n->name, a->i_st);
928312a1df1SDavid du Colombier 
929312a1df1SDavid du Colombier 	AST_dfs(a, a->i_st, 1);
930312a1df1SDavid du Colombier }
931312a1df1SDavid du Colombier 
932312a1df1SDavid du Colombier static void
AST_sends(AST * a)933312a1df1SDavid du Colombier AST_sends(AST *a)
934312a1df1SDavid du Colombier {	FSM_state *f;
935312a1df1SDavid du Colombier 	FSM_trans *t;
936312a1df1SDavid du Colombier 	FSM_use *u;
937312a1df1SDavid du Colombier 	ChanList *cl;
938312a1df1SDavid du Colombier 
939312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)		/* control states */
940312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)		/* transitions    */
941312a1df1SDavid du Colombier 	{	if (t->step
942312a1df1SDavid du Colombier 		&&  t->step->n
943312a1df1SDavid du Colombier 		&&  t->step->n->ntyp == 's')
944312a1df1SDavid du Colombier 		for (u = t->Val[0]; u; u = u->nxt)
945312a1df1SDavid du Colombier 		{	if (Sym_typ(u->n) == CHAN
946312a1df1SDavid du Colombier 			&&  ((u->special&USE) && !(u->special&DEREF_USE)))
947312a1df1SDavid du Colombier 			{
948312a1df1SDavid du Colombier #if 0
949312a1df1SDavid du Colombier 				printf("%s -- (%d->%d) -- ",
950312a1df1SDavid du Colombier 					a->p->n->name, f->from, t->to);
951312a1df1SDavid du Colombier 				AST_var(u->n, u->n->sym, 1);
952312a1df1SDavid du Colombier 				printf(" -> chanlist\n");
953312a1df1SDavid du Colombier #endif
954312a1df1SDavid du Colombier 				cl = (ChanList *) emalloc(sizeof(ChanList));
955312a1df1SDavid du Colombier 				cl->s = t->step->n;
956312a1df1SDavid du Colombier 				cl->n = u->n;
957312a1df1SDavid du Colombier 				cl->nxt = chanlist;
958312a1df1SDavid du Colombier 				chanlist = cl;
959312a1df1SDavid du Colombier }	}	}	}
960312a1df1SDavid du Colombier 
961312a1df1SDavid du Colombier static ALIAS *
AST_alfind(Lextok * n)962312a1df1SDavid du Colombier AST_alfind(Lextok *n)
963312a1df1SDavid du Colombier {	ALIAS *na;
964312a1df1SDavid du Colombier 
965312a1df1SDavid du Colombier 	for (na = chalias; na; na = na->nxt)
966312a1df1SDavid du Colombier 		if (AST_mutual(na->cnm, n, 1))
967312a1df1SDavid du Colombier 			return na;
968312a1df1SDavid du Colombier 	return (ALIAS *) 0;
969312a1df1SDavid du Colombier }
970312a1df1SDavid du Colombier 
971312a1df1SDavid du Colombier static void
AST_trans(void)972312a1df1SDavid du Colombier AST_trans(void)
973312a1df1SDavid du Colombier {	ALIAS *na, *ca, *da, *ea;
974312a1df1SDavid du Colombier 	int nchanges;
975312a1df1SDavid du Colombier 
976312a1df1SDavid du Colombier 	do {
977312a1df1SDavid du Colombier 		nchanges = 0;
978312a1df1SDavid du Colombier 		for (na = chalias; na; na = na->nxt)
979312a1df1SDavid du Colombier 		{	chalcur = na;
980312a1df1SDavid du Colombier 			for (ca = na->alias; ca; ca = ca->nxt)
981312a1df1SDavid du Colombier 			{	da = AST_alfind(ca->cnm);
982312a1df1SDavid du Colombier 				if (da)
983312a1df1SDavid du Colombier 				for (ea = da->alias; ea; ea = ea->nxt)
984312a1df1SDavid du Colombier 				{	nchanges += AST_add_alias(ea->cnm,
985312a1df1SDavid du Colombier 							ea->origin|ca->origin);
986312a1df1SDavid du Colombier 		}	}	}
987312a1df1SDavid du Colombier 	} while (nchanges > 0);
988312a1df1SDavid du Colombier 
989312a1df1SDavid du Colombier 	chalcur = (ALIAS *) 0;
990312a1df1SDavid du Colombier }
991312a1df1SDavid du Colombier 
992312a1df1SDavid du Colombier static void
AST_def_use(AST * a)993312a1df1SDavid du Colombier AST_def_use(AST *a)
994312a1df1SDavid du Colombier {	FSM_state *f;
995312a1df1SDavid du Colombier 	FSM_trans *t;
996312a1df1SDavid du Colombier 
997312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)		/* control states */
998312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)		/* all edges */
999312a1df1SDavid du Colombier 	{	cur_t = t;
1000312a1df1SDavid du Colombier 		rel_use(t->Val[0]);		/* redo Val; doesn't cover structs */
1001312a1df1SDavid du Colombier 		rel_use(t->Val[1]);
1002312a1df1SDavid du Colombier 		t->Val[0] = t->Val[1] = (FSM_use *) 0;
1003312a1df1SDavid du Colombier 
1004312a1df1SDavid du Colombier 		if (!t->step) continue;
1005312a1df1SDavid du Colombier 
1006312a1df1SDavid du Colombier 		def_use(t->step->n, 0);		/* def/use info, including structs */
1007312a1df1SDavid du Colombier 	}
1008312a1df1SDavid du Colombier 	cur_t = (FSM_trans *) 0;
1009312a1df1SDavid du Colombier }
1010312a1df1SDavid du Colombier 
1011312a1df1SDavid du Colombier static void
name_AST_track(Lextok * n,int code)1012312a1df1SDavid du Colombier name_AST_track(Lextok *n, int code)
1013312a1df1SDavid du Colombier {	extern int nr_errs;
1014312a1df1SDavid du Colombier #if 0
1015312a1df1SDavid du Colombier 	printf("AST_name: ");
1016312a1df1SDavid du Colombier 	AST_var(n, n->sym, 1);
1017312a1df1SDavid du Colombier 	printf(" -- %d\n", code);
1018312a1df1SDavid du Colombier #endif
1019312a1df1SDavid du Colombier 	if (in_recv && (code&DEF) && (code&USE))
1020*de2caf28SDavid du Colombier 	{	printf("spin: %s:%d, error: DEF and USE of same var in rcv stmnt: ",
1021*de2caf28SDavid du Colombier 			n->fn->name, n->ln);
1022312a1df1SDavid du Colombier 		AST_var(n, n->sym, 1);
1023312a1df1SDavid du Colombier 		printf(" -- %d\n", code);
1024312a1df1SDavid du Colombier 		nr_errs++;
1025312a1df1SDavid du Colombier 	}
1026312a1df1SDavid du Colombier 	check_slice(n, code);
1027312a1df1SDavid du Colombier }
1028312a1df1SDavid du Colombier 
1029312a1df1SDavid du Colombier void
AST_track(Lextok * now,int code)1030312a1df1SDavid du Colombier AST_track(Lextok *now, int code)	/* called from main.c */
1031312a1df1SDavid du Colombier {	Lextok *v; extern int export_ast;
1032312a1df1SDavid du Colombier 
1033312a1df1SDavid du Colombier 	if (!export_ast) return;
1034312a1df1SDavid du Colombier 
1035312a1df1SDavid du Colombier 	if (now)
1036312a1df1SDavid du Colombier 	switch (now->ntyp) {
1037312a1df1SDavid du Colombier 	case LEN:
1038312a1df1SDavid du Colombier 	case FULL:
1039312a1df1SDavid du Colombier 	case EMPTY:
1040312a1df1SDavid du Colombier 	case NFULL:
1041312a1df1SDavid du Colombier 	case NEMPTY:
1042312a1df1SDavid du Colombier 		AST_track(now->lft, DEREF_USE|USE|code);
1043312a1df1SDavid du Colombier 		break;
1044312a1df1SDavid du Colombier 
1045312a1df1SDavid du Colombier 	case '/':
1046312a1df1SDavid du Colombier 	case '*':
1047312a1df1SDavid du Colombier 	case '-':
1048312a1df1SDavid du Colombier 	case '+':
1049312a1df1SDavid du Colombier 	case '%':
1050312a1df1SDavid du Colombier 	case '&':
1051312a1df1SDavid du Colombier 	case '^':
1052312a1df1SDavid du Colombier 	case '|':
1053312a1df1SDavid du Colombier 	case LE:
1054312a1df1SDavid du Colombier 	case GE:
1055312a1df1SDavid du Colombier 	case GT:
1056312a1df1SDavid du Colombier 	case LT:
1057312a1df1SDavid du Colombier 	case NE:
1058312a1df1SDavid du Colombier 	case EQ:
1059312a1df1SDavid du Colombier 	case OR:
1060312a1df1SDavid du Colombier 	case AND:
1061312a1df1SDavid du Colombier 	case LSHIFT:
1062312a1df1SDavid du Colombier 	case RSHIFT:
1063312a1df1SDavid du Colombier 		AST_track(now->rgt, USE|code);
1064312a1df1SDavid du Colombier 		/* fall through */
1065312a1df1SDavid du Colombier 	case '!':
1066312a1df1SDavid du Colombier 	case UMIN:
1067312a1df1SDavid du Colombier 	case '~':
1068312a1df1SDavid du Colombier 	case 'c':
1069312a1df1SDavid du Colombier 	case ENABLED:
1070*de2caf28SDavid du Colombier 	case SET_P:
1071*de2caf28SDavid du Colombier 	case GET_P:
1072312a1df1SDavid du Colombier 	case ASSERT:
1073312a1df1SDavid du Colombier 		AST_track(now->lft, USE|code);
1074312a1df1SDavid du Colombier 		break;
1075312a1df1SDavid du Colombier 
1076312a1df1SDavid du Colombier 	case EVAL:
1077*de2caf28SDavid du Colombier 		if (now->lft->ntyp == ',')
1078*de2caf28SDavid du Colombier 		{	AST_track(now->lft->lft, USE|(code&(~DEF)));
1079*de2caf28SDavid du Colombier 		} else
1080*de2caf28SDavid du Colombier 		{	AST_track(now->lft, USE|(code&(~DEF)));
1081*de2caf28SDavid du Colombier 		}
1082312a1df1SDavid du Colombier 		break;
1083312a1df1SDavid du Colombier 
1084312a1df1SDavid du Colombier 	case NAME:
1085312a1df1SDavid du Colombier 		name_AST_track(now, code);
108600d97012SDavid du Colombier 		if (now->sym->nel > 1 || now->sym->isarray)
1087*de2caf28SDavid du Colombier 			AST_track(now->lft, USE);	/* index, was USE|code */
1088312a1df1SDavid du Colombier 		break;
1089312a1df1SDavid du Colombier 
1090312a1df1SDavid du Colombier 	case 'R':
1091312a1df1SDavid du Colombier 		AST_track(now->lft, DEREF_USE|USE|code);
1092312a1df1SDavid du Colombier 		for (v = now->rgt; v; v = v->rgt)
1093312a1df1SDavid du Colombier 			AST_track(v->lft, code); /* a deeper eval can add USE */
1094312a1df1SDavid du Colombier 		break;
1095312a1df1SDavid du Colombier 
1096312a1df1SDavid du Colombier 	case '?':
1097312a1df1SDavid du Colombier 		AST_track(now->lft, USE|code);
1098312a1df1SDavid du Colombier 		if (now->rgt)
1099312a1df1SDavid du Colombier 		{	AST_track(now->rgt->lft, code);
1100312a1df1SDavid du Colombier 			AST_track(now->rgt->rgt, code);
1101312a1df1SDavid du Colombier 		}
1102312a1df1SDavid du Colombier 		break;
1103312a1df1SDavid du Colombier 
1104312a1df1SDavid du Colombier /* added for control deps: */
1105312a1df1SDavid du Colombier 	case TYPE:
1106312a1df1SDavid du Colombier 		name_AST_track(now, code);
1107312a1df1SDavid du Colombier 		break;
1108312a1df1SDavid du Colombier 	case ASGN:
1109312a1df1SDavid du Colombier 		AST_track(now->lft, DEF|code);
1110312a1df1SDavid du Colombier 		AST_track(now->rgt, USE|code);
1111312a1df1SDavid du Colombier 		break;
1112312a1df1SDavid du Colombier 	case RUN:
1113312a1df1SDavid du Colombier 		name_AST_track(now, USE);
1114312a1df1SDavid du Colombier 		for (v = now->lft; v; v = v->rgt)
1115312a1df1SDavid du Colombier 			AST_track(v->lft, USE|code);
1116312a1df1SDavid du Colombier 		break;
1117312a1df1SDavid du Colombier 	case 's':
1118312a1df1SDavid du Colombier 		AST_track(now->lft, DEREF_DEF|DEREF_USE|USE|code);
1119312a1df1SDavid du Colombier 		for (v = now->rgt; v; v = v->rgt)
1120312a1df1SDavid du Colombier 			AST_track(v->lft, USE|code);
1121312a1df1SDavid du Colombier 		break;
1122312a1df1SDavid du Colombier 	case 'r':
1123312a1df1SDavid du Colombier 		AST_track(now->lft, DEREF_DEF|DEREF_USE|USE|code);
1124312a1df1SDavid du Colombier 		for (v = now->rgt; v; v = v->rgt)
1125312a1df1SDavid du Colombier 		{	in_recv++;
1126312a1df1SDavid du Colombier 			AST_track(v->lft, DEF|code);
1127312a1df1SDavid du Colombier 			in_recv--;
1128312a1df1SDavid du Colombier 		}
1129312a1df1SDavid du Colombier 		break;
1130312a1df1SDavid du Colombier 	case PRINT:
1131312a1df1SDavid du Colombier 		for (v = now->lft; v; v = v->rgt)
1132312a1df1SDavid du Colombier 			AST_track(v->lft, USE|code);
1133312a1df1SDavid du Colombier 		break;
1134312a1df1SDavid du Colombier 	case PRINTM:
1135312a1df1SDavid du Colombier 		AST_track(now->lft, USE);
1136312a1df1SDavid du Colombier 		break;
1137312a1df1SDavid du Colombier /* end add */
1138312a1df1SDavid du Colombier 	case   'p':
1139312a1df1SDavid du Colombier #if 0
1140312a1df1SDavid du Colombier 			   'p' -sym-> _p
1141312a1df1SDavid du Colombier 			   /
1142312a1df1SDavid du Colombier 			 '?' -sym-> a (proctype)
1143312a1df1SDavid du Colombier 			 /
1144312a1df1SDavid du Colombier 			b (pid expr)
1145312a1df1SDavid du Colombier #endif
1146312a1df1SDavid du Colombier 		AST_track(now->lft->lft, USE|code);
1147312a1df1SDavid du Colombier 		AST_procisrelevant(now->lft->sym);
1148312a1df1SDavid du Colombier 		break;
1149312a1df1SDavid du Colombier 
1150312a1df1SDavid du Colombier 	case CONST:
1151312a1df1SDavid du Colombier 	case ELSE:
1152312a1df1SDavid du Colombier 	case NONPROGRESS:
1153312a1df1SDavid du Colombier 	case PC_VAL:
1154312a1df1SDavid du Colombier 	case   'q':
1155312a1df1SDavid du Colombier 		break;
1156312a1df1SDavid du Colombier 
1157312a1df1SDavid du Colombier 	case   '.':
1158312a1df1SDavid du Colombier 	case  GOTO:
1159312a1df1SDavid du Colombier 	case BREAK:
1160312a1df1SDavid du Colombier 	case   '@':
1161312a1df1SDavid du Colombier 	case D_STEP:
1162312a1df1SDavid du Colombier 	case ATOMIC:
1163312a1df1SDavid du Colombier 	case NON_ATOMIC:
1164312a1df1SDavid du Colombier 	case IF:
1165312a1df1SDavid du Colombier 	case DO:
1166312a1df1SDavid du Colombier 	case UNLESS:
1167312a1df1SDavid du Colombier 	case TIMEOUT:
1168312a1df1SDavid du Colombier 	case C_CODE:
1169312a1df1SDavid du Colombier 	case C_EXPR:
1170312a1df1SDavid du Colombier 		break;
1171312a1df1SDavid du Colombier 
1172312a1df1SDavid du Colombier 	default:
1173312a1df1SDavid du Colombier 		printf("AST_track, NOT EXPECTED ntyp: %d\n", now->ntyp);
1174312a1df1SDavid du Colombier 		break;
1175312a1df1SDavid du Colombier 	}
1176312a1df1SDavid du Colombier }
1177312a1df1SDavid du Colombier 
1178312a1df1SDavid du Colombier static int
AST_dump_rel(void)1179312a1df1SDavid du Colombier AST_dump_rel(void)
1180312a1df1SDavid du Colombier {	Slicer *rv;
1181312a1df1SDavid du Colombier 	Ordered *walk;
1182312a1df1SDavid du Colombier 	char buf[64];
1183312a1df1SDavid du Colombier 	int banner=0;
1184312a1df1SDavid du Colombier 
1185312a1df1SDavid du Colombier 	if (verbose&32)
1186312a1df1SDavid du Colombier 	{	printf("Relevant variables:\n");
1187312a1df1SDavid du Colombier 		for (rv = rel_vars; rv; rv = rv->nxt)
1188312a1df1SDavid du Colombier 		{	printf("\t");
1189312a1df1SDavid du Colombier 			AST_var(rv->n, rv->n->sym, 1);
1190312a1df1SDavid du Colombier 			printf("\n");
1191312a1df1SDavid du Colombier 		}
1192312a1df1SDavid du Colombier 		return 1;
1193312a1df1SDavid du Colombier 	}
1194312a1df1SDavid du Colombier 	for (rv = rel_vars; rv; rv = rv->nxt)
1195312a1df1SDavid du Colombier 		rv->n->sym->setat = 1;	/* mark it */
1196312a1df1SDavid du Colombier 
1197312a1df1SDavid du Colombier 	for (walk = all_names; walk; walk = walk->next)
1198312a1df1SDavid du Colombier 	{	Symbol *s;
1199312a1df1SDavid du Colombier 		s = walk->entry;
1200312a1df1SDavid du Colombier 		if (!s->setat
1201312a1df1SDavid du Colombier 		&&  (s->type != MTYPE || s->ini->ntyp != CONST)
1202312a1df1SDavid du Colombier 		&&  s->type != STRUCT	/* report only fields */
1203312a1df1SDavid du Colombier 		&&  s->type != PROCTYPE
1204312a1df1SDavid du Colombier 		&&  !s->owner
1205312a1df1SDavid du Colombier 		&&  sputtype(buf, s->type))
1206312a1df1SDavid du Colombier 		{	if (!banner)
1207312a1df1SDavid du Colombier 			{	banner = 1;
1208312a1df1SDavid du Colombier 				printf("spin: redundant vars (for given property):\n");
1209312a1df1SDavid du Colombier 			}
1210312a1df1SDavid du Colombier 			printf("\t");
1211312a1df1SDavid du Colombier 			symvar(s);
1212312a1df1SDavid du Colombier 	}	}
1213312a1df1SDavid du Colombier 	return banner;
1214312a1df1SDavid du Colombier }
1215312a1df1SDavid du Colombier 
1216312a1df1SDavid du Colombier static void
AST_suggestions(void)1217312a1df1SDavid du Colombier AST_suggestions(void)
1218312a1df1SDavid du Colombier {	Symbol *s;
1219312a1df1SDavid du Colombier 	Ordered *walk;
1220312a1df1SDavid du Colombier 	FSM_state *f;
1221312a1df1SDavid du Colombier 	FSM_trans *t;
1222312a1df1SDavid du Colombier 	AST *a;
1223312a1df1SDavid du Colombier 	int banner=0;
1224312a1df1SDavid du Colombier 	int talked=0;
1225312a1df1SDavid du Colombier 
1226312a1df1SDavid du Colombier 	for (walk = all_names; walk; walk = walk->next)
1227312a1df1SDavid du Colombier 	{	s = walk->entry;
1228312a1df1SDavid du Colombier 		if (s->colnr == 2	/* only used in conditionals */
1229312a1df1SDavid du Colombier 		&&  (s->type == BYTE
1230312a1df1SDavid du Colombier 		||   s->type == SHORT
1231312a1df1SDavid du Colombier 		||   s->type == INT
1232312a1df1SDavid du Colombier 		||   s->type == MTYPE))
1233312a1df1SDavid du Colombier 		{	if (!banner)
1234312a1df1SDavid du Colombier 			{	banner = 1;
1235312a1df1SDavid du Colombier 				printf("spin: consider using predicate");
1236312a1df1SDavid du Colombier 				printf(" abstraction to replace:\n");
1237312a1df1SDavid du Colombier 			}
1238312a1df1SDavid du Colombier 			printf("\t");
1239312a1df1SDavid du Colombier 			symvar(s);
1240312a1df1SDavid du Colombier 	}	}
1241312a1df1SDavid du Colombier 
1242312a1df1SDavid du Colombier 	/* look for source and sink processes */
1243312a1df1SDavid du Colombier 
1244312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)		/* automata       */
1245312a1df1SDavid du Colombier 	{	banner = 0;
1246312a1df1SDavid du Colombier 		for (f = a->fsm; f; f = f->nxt)	/* control states */
1247312a1df1SDavid du Colombier 		for (t = f->t; t; t = t->nxt)	/* transitions    */
1248312a1df1SDavid du Colombier 		{	if (t->step)
1249312a1df1SDavid du Colombier 			switch (t->step->n->ntyp) {
1250312a1df1SDavid du Colombier 			case 's':
1251312a1df1SDavid du Colombier 				banner |= 1;
1252312a1df1SDavid du Colombier 				break;
1253312a1df1SDavid du Colombier 			case 'r':
1254312a1df1SDavid du Colombier 				banner |= 2;
1255312a1df1SDavid du Colombier 				break;
1256312a1df1SDavid du Colombier 			case '.':
1257312a1df1SDavid du Colombier 			case D_STEP:
1258312a1df1SDavid du Colombier 			case ATOMIC:
1259312a1df1SDavid du Colombier 			case NON_ATOMIC:
1260312a1df1SDavid du Colombier 			case IF:
1261312a1df1SDavid du Colombier 			case DO:
1262312a1df1SDavid du Colombier 			case UNLESS:
1263312a1df1SDavid du Colombier 			case '@':
1264312a1df1SDavid du Colombier 			case GOTO:
1265312a1df1SDavid du Colombier 			case BREAK:
1266312a1df1SDavid du Colombier 			case PRINT:
1267312a1df1SDavid du Colombier 			case PRINTM:
1268312a1df1SDavid du Colombier 			case ASSERT:
1269312a1df1SDavid du Colombier 			case C_CODE:
1270312a1df1SDavid du Colombier 			case C_EXPR:
1271312a1df1SDavid du Colombier 				break;
1272312a1df1SDavid du Colombier 			default:
1273312a1df1SDavid du Colombier 				banner |= 4;
1274312a1df1SDavid du Colombier 				goto no_good;
1275312a1df1SDavid du Colombier 			}
1276312a1df1SDavid du Colombier 		}
1277312a1df1SDavid du Colombier no_good:	if (banner == 1 || banner == 2)
1278312a1df1SDavid du Colombier 		{	printf("spin: proctype %s defines a %s process\n",
1279312a1df1SDavid du Colombier 				a->p->n->name,
1280312a1df1SDavid du Colombier 				banner==1?"source":"sink");
1281312a1df1SDavid du Colombier 			talked |= banner;
1282312a1df1SDavid du Colombier 		} else if (banner == 3)
1283312a1df1SDavid du Colombier 		{	printf("spin: proctype %s mimics a buffer\n",
1284312a1df1SDavid du Colombier 				a->p->n->name);
1285312a1df1SDavid du Colombier 			talked |= 4;
1286312a1df1SDavid du Colombier 		}
1287312a1df1SDavid du Colombier 	}
1288312a1df1SDavid du Colombier 	if (talked&1)
1289312a1df1SDavid du Colombier 	{	printf("\tto reduce complexity, consider merging the code of\n");
1290312a1df1SDavid du Colombier 		printf("\teach source process into the code of its target\n");
1291312a1df1SDavid du Colombier 	}
1292312a1df1SDavid du Colombier 	if (talked&2)
1293312a1df1SDavid du Colombier 	{	printf("\tto reduce complexity, consider merging the code of\n");
1294312a1df1SDavid du Colombier 		printf("\teach sink process into the code of its source\n");
1295312a1df1SDavid du Colombier 	}
1296312a1df1SDavid du Colombier 	if (talked&4)
1297312a1df1SDavid du Colombier 		printf("\tto reduce complexity, avoid buffer processes\n");
1298312a1df1SDavid du Colombier }
1299312a1df1SDavid du Colombier 
1300312a1df1SDavid du Colombier static void
AST_preserve(void)1301312a1df1SDavid du Colombier AST_preserve(void)
1302312a1df1SDavid du Colombier {	Slicer *sc, *nx, *rv;
1303312a1df1SDavid du Colombier 
1304312a1df1SDavid du Colombier 	for (sc = slicer; sc; sc = nx)
1305312a1df1SDavid du Colombier 	{	if (!sc->used)
1306312a1df1SDavid du Colombier 			break;	/* done */
1307312a1df1SDavid du Colombier 
1308312a1df1SDavid du Colombier 		nx = sc->nxt;
1309312a1df1SDavid du Colombier 
1310312a1df1SDavid du Colombier 		for (rv = rel_vars; rv; rv = rv->nxt)
1311312a1df1SDavid du Colombier 			if (AST_mutual(sc->n, rv->n, 1))
1312312a1df1SDavid du Colombier 				break;
1313312a1df1SDavid du Colombier 
1314312a1df1SDavid du Colombier 		if (!rv) /* not already there */
1315312a1df1SDavid du Colombier 		{	sc->nxt = rel_vars;
1316312a1df1SDavid du Colombier 			rel_vars = sc;
1317312a1df1SDavid du Colombier 	}	}
1318312a1df1SDavid du Colombier 	slicer = sc;
1319312a1df1SDavid du Colombier }
1320312a1df1SDavid du Colombier 
1321312a1df1SDavid du Colombier static void
check_slice(Lextok * n,int code)1322312a1df1SDavid du Colombier check_slice(Lextok *n, int code)
1323312a1df1SDavid du Colombier {	Slicer *sc;
1324312a1df1SDavid du Colombier 
1325312a1df1SDavid du Colombier 	for (sc = slicer; sc; sc = sc->nxt)
1326312a1df1SDavid du Colombier 		if (AST_mutual(sc->n, n, 1)
1327312a1df1SDavid du Colombier 		&&  sc->code == code)
1328312a1df1SDavid du Colombier 			return;	/* already there */
1329312a1df1SDavid du Colombier 
1330312a1df1SDavid du Colombier 	sc = (Slicer *) emalloc(sizeof(Slicer));
1331312a1df1SDavid du Colombier 	sc->n = n;
1332312a1df1SDavid du Colombier 
1333312a1df1SDavid du Colombier 	sc->code = code;
1334312a1df1SDavid du Colombier 	sc->used = 0;
1335312a1df1SDavid du Colombier 	sc->nxt = slicer;
1336312a1df1SDavid du Colombier 	slicer = sc;
1337312a1df1SDavid du Colombier }
1338312a1df1SDavid du Colombier 
1339312a1df1SDavid du Colombier static void
AST_data_dep(void)1340312a1df1SDavid du Colombier AST_data_dep(void)
1341312a1df1SDavid du Colombier {	Slicer *sc;
1342312a1df1SDavid du Colombier 
1343312a1df1SDavid du Colombier 	/* mark all def-relevant transitions */
1344312a1df1SDavid du Colombier 	for (sc = slicer; sc; sc = sc->nxt)
1345312a1df1SDavid du Colombier 	{	sc->used = 1;
1346312a1df1SDavid du Colombier 		if (verbose&32)
1347312a1df1SDavid du Colombier 		{	printf("spin: slice criterion ");
1348312a1df1SDavid du Colombier 			AST_var(sc->n, sc->n->sym, 1);
1349312a1df1SDavid du Colombier 			printf(" type=%d\n", Sym_typ(sc->n));
1350312a1df1SDavid du Colombier 		}
1351312a1df1SDavid du Colombier 		AST_relevant(sc->n);
1352312a1df1SDavid du Colombier 	}
1353312a1df1SDavid du Colombier 	AST_tagruns();	/* mark 'run's relevant if target proctype is relevant */
1354312a1df1SDavid du Colombier }
1355312a1df1SDavid du Colombier 
1356312a1df1SDavid du Colombier static int
AST_blockable(AST * a,int s)1357312a1df1SDavid du Colombier AST_blockable(AST *a, int s)
1358312a1df1SDavid du Colombier {	FSM_state *f;
1359312a1df1SDavid du Colombier 	FSM_trans *t;
1360312a1df1SDavid du Colombier 
1361312a1df1SDavid du Colombier 	f = fsm_tbl[s];
1362312a1df1SDavid du Colombier 
1363312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)
1364312a1df1SDavid du Colombier 	{	if (t->relevant&2)
1365312a1df1SDavid du Colombier 			return 1;
1366312a1df1SDavid du Colombier 
1367312a1df1SDavid du Colombier 		if (t->step && t->step->n)
1368312a1df1SDavid du Colombier 		switch (t->step->n->ntyp) {
1369312a1df1SDavid du Colombier 		case IF:
1370312a1df1SDavid du Colombier 		case DO:
1371312a1df1SDavid du Colombier 		case ATOMIC:
1372312a1df1SDavid du Colombier 		case NON_ATOMIC:
1373312a1df1SDavid du Colombier 		case D_STEP:
1374312a1df1SDavid du Colombier 			if (AST_blockable(a, t->to))
1375312a1df1SDavid du Colombier 			{	t->round = AST_Round;
1376312a1df1SDavid du Colombier 				t->relevant |= 2;
1377312a1df1SDavid du Colombier 				return 1;
1378312a1df1SDavid du Colombier 			}
1379312a1df1SDavid du Colombier 			/* else fall through */
1380312a1df1SDavid du Colombier 		default:
1381312a1df1SDavid du Colombier 			break;
1382312a1df1SDavid du Colombier 		}
1383312a1df1SDavid du Colombier 		else if (AST_blockable(a, t->to))	/* Unless */
1384312a1df1SDavid du Colombier 		{	t->round = AST_Round;
1385312a1df1SDavid du Colombier 			t->relevant |= 2;
1386312a1df1SDavid du Colombier 			return 1;
1387312a1df1SDavid du Colombier 		}
1388312a1df1SDavid du Colombier 	}
1389312a1df1SDavid du Colombier 	return 0;
1390312a1df1SDavid du Colombier }
1391312a1df1SDavid du Colombier 
1392312a1df1SDavid du Colombier static void
AST_spread(AST * a,int s)1393312a1df1SDavid du Colombier AST_spread(AST *a, int s)
1394312a1df1SDavid du Colombier {	FSM_state *f;
1395312a1df1SDavid du Colombier 	FSM_trans *t;
1396312a1df1SDavid du Colombier 
1397312a1df1SDavid du Colombier 	f = fsm_tbl[s];
1398312a1df1SDavid du Colombier 
1399312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)
1400312a1df1SDavid du Colombier 	{	if (t->relevant&2)
1401312a1df1SDavid du Colombier 			continue;
1402312a1df1SDavid du Colombier 
1403312a1df1SDavid du Colombier 		if (t->step && t->step->n)
1404312a1df1SDavid du Colombier 			switch (t->step->n->ntyp) {
1405312a1df1SDavid du Colombier 			case IF:
1406312a1df1SDavid du Colombier 			case DO:
1407312a1df1SDavid du Colombier 			case ATOMIC:
1408312a1df1SDavid du Colombier 			case NON_ATOMIC:
1409312a1df1SDavid du Colombier 			case D_STEP:
1410312a1df1SDavid du Colombier 				AST_spread(a, t->to);
1411312a1df1SDavid du Colombier 				/* fall thru */
1412312a1df1SDavid du Colombier 			default:
1413312a1df1SDavid du Colombier 				t->round = AST_Round;
1414312a1df1SDavid du Colombier 				t->relevant |= 2;
1415312a1df1SDavid du Colombier 				break;
1416312a1df1SDavid du Colombier 			}
1417312a1df1SDavid du Colombier 		else	/* Unless */
1418312a1df1SDavid du Colombier 		{	AST_spread(a, t->to);
1419312a1df1SDavid du Colombier 			t->round = AST_Round;
1420312a1df1SDavid du Colombier 			t->relevant |= 2;
1421312a1df1SDavid du Colombier 		}
1422312a1df1SDavid du Colombier 	}
1423312a1df1SDavid du Colombier }
1424312a1df1SDavid du Colombier 
1425312a1df1SDavid du Colombier static int
AST_notrelevant(Lextok * n)1426312a1df1SDavid du Colombier AST_notrelevant(Lextok *n)
1427312a1df1SDavid du Colombier {	Slicer *s;
1428312a1df1SDavid du Colombier 
1429312a1df1SDavid du Colombier 	for (s = rel_vars; s; s = s->nxt)
1430312a1df1SDavid du Colombier 		if (AST_mutual(s->n, n, 1))
1431312a1df1SDavid du Colombier 			return 0;
1432312a1df1SDavid du Colombier 	for (s = slicer; s; s = s->nxt)
1433312a1df1SDavid du Colombier 		if (AST_mutual(s->n, n, 1))
1434312a1df1SDavid du Colombier 			return 0;
1435312a1df1SDavid du Colombier 	return 1;
1436312a1df1SDavid du Colombier }
1437312a1df1SDavid du Colombier 
1438312a1df1SDavid du Colombier static int
AST_withchan(Lextok * n)1439312a1df1SDavid du Colombier AST_withchan(Lextok *n)
1440312a1df1SDavid du Colombier {
1441312a1df1SDavid du Colombier 	if (!n) return 0;
1442312a1df1SDavid du Colombier 	if (Sym_typ(n) == CHAN)
1443312a1df1SDavid du Colombier 		return 1;
1444312a1df1SDavid du Colombier 	return AST_withchan(n->lft) || AST_withchan(n->rgt);
1445312a1df1SDavid du Colombier }
1446312a1df1SDavid du Colombier 
1447312a1df1SDavid du Colombier static int
AST_suspect(FSM_trans * t)1448312a1df1SDavid du Colombier AST_suspect(FSM_trans *t)
1449312a1df1SDavid du Colombier {	FSM_use *u;
1450312a1df1SDavid du Colombier 	/* check for possible overkill */
1451312a1df1SDavid du Colombier 	if (!t || !t->step || !AST_withchan(t->step->n))
1452312a1df1SDavid du Colombier 		return 0;
1453312a1df1SDavid du Colombier 	for (u = t->Val[0]; u; u = u->nxt)
1454312a1df1SDavid du Colombier 		if (AST_notrelevant(u->n))
1455312a1df1SDavid du Colombier 			return 1;
1456312a1df1SDavid du Colombier 	return 0;
1457312a1df1SDavid du Colombier }
1458312a1df1SDavid du Colombier 
1459312a1df1SDavid du Colombier static void
AST_shouldconsider(AST * a,int s)1460312a1df1SDavid du Colombier AST_shouldconsider(AST *a, int s)
1461312a1df1SDavid du Colombier {	FSM_state *f;
1462312a1df1SDavid du Colombier 	FSM_trans *t;
1463312a1df1SDavid du Colombier 
1464312a1df1SDavid du Colombier 	f = fsm_tbl[s];
1465312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)
1466312a1df1SDavid du Colombier 	{	if (t->step && t->step->n)
1467312a1df1SDavid du Colombier 			switch (t->step->n->ntyp) {
1468312a1df1SDavid du Colombier 			case IF:
1469312a1df1SDavid du Colombier 			case DO:
1470312a1df1SDavid du Colombier 			case ATOMIC:
1471312a1df1SDavid du Colombier 			case NON_ATOMIC:
1472312a1df1SDavid du Colombier 			case D_STEP:
1473312a1df1SDavid du Colombier 				AST_shouldconsider(a, t->to);
1474312a1df1SDavid du Colombier 				break;
1475312a1df1SDavid du Colombier 			default:
1476312a1df1SDavid du Colombier 				AST_track(t->step->n, 0);
1477312a1df1SDavid du Colombier /*
1478312a1df1SDavid du Colombier 	AST_track is called here for a blockable stmnt from which
1479312a1df1SDavid du Colombier 	a relevant stmnmt was shown to be reachable
1480312a1df1SDavid du Colombier 	for a condition this makes all USEs relevant
1481312a1df1SDavid du Colombier 	but for a channel operation it only makes the executability
1482312a1df1SDavid du Colombier 	relevant -- in those cases, parameters that aren't already
1483312a1df1SDavid du Colombier 	relevant may be replaceable with arbitrary tokens
1484312a1df1SDavid du Colombier  */
1485312a1df1SDavid du Colombier 				if (AST_suspect(t))
1486312a1df1SDavid du Colombier 				{	printf("spin: possibly redundant parameters in: ");
1487312a1df1SDavid du Colombier 					comment(stdout, t->step->n, 0);
1488312a1df1SDavid du Colombier 					printf("\n");
1489312a1df1SDavid du Colombier 				}
1490312a1df1SDavid du Colombier 				break;
1491312a1df1SDavid du Colombier 			}
1492312a1df1SDavid du Colombier 		else	/* an Unless */
1493312a1df1SDavid du Colombier 			AST_shouldconsider(a, t->to);
1494312a1df1SDavid du Colombier 	}
1495312a1df1SDavid du Colombier }
1496312a1df1SDavid du Colombier 
1497312a1df1SDavid du Colombier static int
FSM_critical(AST * a,int s)1498312a1df1SDavid du Colombier FSM_critical(AST *a, int s)
1499312a1df1SDavid du Colombier {	FSM_state *f;
1500312a1df1SDavid du Colombier 	FSM_trans *t;
1501312a1df1SDavid du Colombier 
1502312a1df1SDavid du Colombier 	/* is a 1-relevant stmnt reachable from this state? */
1503312a1df1SDavid du Colombier 
1504312a1df1SDavid du Colombier 	f = fsm_tbl[s];
1505312a1df1SDavid du Colombier 	if (f->seen)
1506312a1df1SDavid du Colombier 		goto done;
1507312a1df1SDavid du Colombier 	f->seen = 1;
1508312a1df1SDavid du Colombier 	f->cr   = 0;
1509312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)
1510312a1df1SDavid du Colombier 		if ((t->relevant&1)
1511312a1df1SDavid du Colombier 		||  FSM_critical(a, t->to))
1512312a1df1SDavid du Colombier 		{	f->cr = 1;
1513312a1df1SDavid du Colombier 
1514312a1df1SDavid du Colombier 			if (verbose&32)
1515312a1df1SDavid du Colombier 			{	printf("\t\t\t\tcritical(%d) ", t->relevant);
1516312a1df1SDavid du Colombier 				comment(stdout, t->step->n, 0);
1517312a1df1SDavid du Colombier 				printf("\n");
1518312a1df1SDavid du Colombier 			}
1519312a1df1SDavid du Colombier 			break;
1520312a1df1SDavid du Colombier 		}
1521312a1df1SDavid du Colombier #if 0
1522312a1df1SDavid du Colombier 	else {
1523312a1df1SDavid du Colombier 		if (verbose&32)
1524312a1df1SDavid du Colombier 		{ printf("\t\t\t\tnot-crit ");
1525312a1df1SDavid du Colombier 		  comment(stdout, t->step->n, 0);
1526312a1df1SDavid du Colombier 	 	  printf("\n");
1527312a1df1SDavid du Colombier 		}
1528312a1df1SDavid du Colombier 	}
1529312a1df1SDavid du Colombier #endif
1530312a1df1SDavid du Colombier done:
1531312a1df1SDavid du Colombier 	return f->cr;
1532312a1df1SDavid du Colombier }
1533312a1df1SDavid du Colombier 
1534312a1df1SDavid du Colombier static void
AST_ctrl(AST * a)1535312a1df1SDavid du Colombier AST_ctrl(AST *a)
1536312a1df1SDavid du Colombier {	FSM_state *f;
1537312a1df1SDavid du Colombier 	FSM_trans *t;
1538312a1df1SDavid du Colombier 	int hit;
1539312a1df1SDavid du Colombier 
1540312a1df1SDavid du Colombier 	/* add all blockable transitions
1541312a1df1SDavid du Colombier 	 * from which relevant transitions can be reached
1542312a1df1SDavid du Colombier 	 */
1543312a1df1SDavid du Colombier 	if (verbose&32)
1544312a1df1SDavid du Colombier 		printf("CTL -- %s\n", a->p->n->name);
1545312a1df1SDavid du Colombier 
1546312a1df1SDavid du Colombier 	/* 1 : mark all blockable edges */
1547312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)
1548312a1df1SDavid du Colombier 	{	if (!(f->scratch&2))		/* not part of irrelevant subgraph */
1549312a1df1SDavid du Colombier 		for (t = f->t; t; t = t->nxt)
1550312a1df1SDavid du Colombier 		{	if (t->step && t->step->n)
1551312a1df1SDavid du Colombier 			switch (t->step->n->ntyp) {
1552312a1df1SDavid du Colombier 			case 'r':
1553312a1df1SDavid du Colombier 			case 's':
1554312a1df1SDavid du Colombier 			case 'c':
1555312a1df1SDavid du Colombier 			case ELSE:
1556312a1df1SDavid du Colombier 				t->round = AST_Round;
1557312a1df1SDavid du Colombier 				t->relevant |= 2;	/* mark for next phases */
1558312a1df1SDavid du Colombier 				if (verbose&32)
1559312a1df1SDavid du Colombier 				{	printf("\tpremark ");
1560312a1df1SDavid du Colombier 					comment(stdout, t->step->n, 0);
1561312a1df1SDavid du Colombier 					printf("\n");
1562312a1df1SDavid du Colombier 				}
1563312a1df1SDavid du Colombier 				break;
1564312a1df1SDavid du Colombier 			default:
1565312a1df1SDavid du Colombier 				break;
1566312a1df1SDavid du Colombier 	}	}	}
1567312a1df1SDavid du Colombier 
1568312a1df1SDavid du Colombier 	/* 2: keep only 2-marked stmnts from which 1-marked stmnts can be reached */
1569312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)
1570312a1df1SDavid du Colombier 	{	fsm_tbl[f->from] = f;
1571312a1df1SDavid du Colombier 		f->seen = 0;	/* used in dfs from FSM_critical */
1572312a1df1SDavid du Colombier 	}
1573312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)
1574312a1df1SDavid du Colombier 	{	if (!FSM_critical(a, f->from))
1575312a1df1SDavid du Colombier 		for (t = f->t; t; t = t->nxt)
1576312a1df1SDavid du Colombier 			if (t->relevant&2)
1577312a1df1SDavid du Colombier 			{	t->relevant &= ~2;	/* clear mark */
1578312a1df1SDavid du Colombier 				if (verbose&32)
1579312a1df1SDavid du Colombier 				{	printf("\t\tnomark ");
158000d97012SDavid du Colombier 					if (t->step && t->step->n)
1581312a1df1SDavid du Colombier 						comment(stdout, t->step->n, 0);
1582312a1df1SDavid du Colombier 					printf("\n");
1583312a1df1SDavid du Colombier 	}		}	}
1584312a1df1SDavid du Colombier 
1585312a1df1SDavid du Colombier 	/* 3 : lift marks across IF/DO etc. */
1586312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)
1587312a1df1SDavid du Colombier 	{	hit = 0;
1588312a1df1SDavid du Colombier 		for (t = f->t; t; t = t->nxt)
1589312a1df1SDavid du Colombier 		{	if (t->step && t->step->n)
1590312a1df1SDavid du Colombier 			switch (t->step->n->ntyp) {
1591312a1df1SDavid du Colombier 			case IF:
1592312a1df1SDavid du Colombier 			case DO:
1593312a1df1SDavid du Colombier 			case ATOMIC:
1594312a1df1SDavid du Colombier 			case NON_ATOMIC:
1595312a1df1SDavid du Colombier 			case D_STEP:
1596312a1df1SDavid du Colombier 				if (AST_blockable(a, t->to))
1597312a1df1SDavid du Colombier 					hit = 1;
1598312a1df1SDavid du Colombier 				break;
1599312a1df1SDavid du Colombier 			default:
1600312a1df1SDavid du Colombier 				break;
1601312a1df1SDavid du Colombier 			}
1602312a1df1SDavid du Colombier 			else if (AST_blockable(a, t->to))	/* Unless */
1603312a1df1SDavid du Colombier 				hit = 1;
1604312a1df1SDavid du Colombier 
1605312a1df1SDavid du Colombier 			if (hit) break;
1606312a1df1SDavid du Colombier 		}
1607312a1df1SDavid du Colombier 		if (hit)	/* at least one outgoing trans can block */
1608312a1df1SDavid du Colombier 		for (t = f->t; t; t = t->nxt)
1609312a1df1SDavid du Colombier 		{	t->round = AST_Round;
1610312a1df1SDavid du Colombier 			t->relevant |= 2;	/* lift */
1611312a1df1SDavid du Colombier 			if (verbose&32)
1612312a1df1SDavid du Colombier 			{	printf("\t\t\tliftmark ");
161300d97012SDavid du Colombier 				if (t->step && t->step->n)
1614312a1df1SDavid du Colombier 					comment(stdout, t->step->n, 0);
1615312a1df1SDavid du Colombier 				printf("\n");
1616312a1df1SDavid du Colombier 			}
1617312a1df1SDavid du Colombier 			AST_spread(a, t->to);	/* and spread to all guards */
1618312a1df1SDavid du Colombier 	}	}
1619312a1df1SDavid du Colombier 
1620312a1df1SDavid du Colombier 	/* 4: nodes with 2-marked out-edges contribute new slice criteria */
1621312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)
1622312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)
1623312a1df1SDavid du Colombier 		if (t->relevant&2)
1624312a1df1SDavid du Colombier 		{	AST_shouldconsider(a, f->from);
1625312a1df1SDavid du Colombier 			break;	/* inner loop */
1626312a1df1SDavid du Colombier 		}
1627312a1df1SDavid du Colombier }
1628312a1df1SDavid du Colombier 
1629312a1df1SDavid du Colombier static void
AST_control_dep(void)1630312a1df1SDavid du Colombier AST_control_dep(void)
1631312a1df1SDavid du Colombier {	AST *a;
1632312a1df1SDavid du Colombier 
1633312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)
163400d97012SDavid du Colombier 	{	if (a->p->b != N_CLAIM && a->p->b != E_TRACE && a->p->b != N_TRACE)
163500d97012SDavid du Colombier 		{	AST_ctrl(a);
163600d97012SDavid du Colombier 	}	}
1637312a1df1SDavid du Colombier }
1638312a1df1SDavid du Colombier 
1639312a1df1SDavid du Colombier static void
AST_prelabel(void)1640312a1df1SDavid du Colombier AST_prelabel(void)
1641312a1df1SDavid du Colombier {	AST *a;
1642312a1df1SDavid du Colombier 	FSM_state *f;
1643312a1df1SDavid du Colombier 	FSM_trans *t;
1644312a1df1SDavid du Colombier 
1645312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)
164600d97012SDavid du Colombier 	{	if (a->p->b != N_CLAIM && a->p->b != E_TRACE && a->p->b != N_TRACE)
1647312a1df1SDavid du Colombier 		for (f = a->fsm; f; f = f->nxt)
1648312a1df1SDavid du Colombier 		for (t = f->t; t; t = t->nxt)
1649312a1df1SDavid du Colombier 		{	if (t->step
1650312a1df1SDavid du Colombier 			&&  t->step->n
1651312a1df1SDavid du Colombier 			&&  t->step->n->ntyp == ASSERT
1652312a1df1SDavid du Colombier 			)
1653312a1df1SDavid du Colombier 			{	t->relevant |= 1;
1654312a1df1SDavid du Colombier 	}	}	}
1655312a1df1SDavid du Colombier }
1656312a1df1SDavid du Colombier 
1657312a1df1SDavid du Colombier static void
AST_criteria(void)1658312a1df1SDavid du Colombier AST_criteria(void)
1659312a1df1SDavid du Colombier {	/*
1660312a1df1SDavid du Colombier 	 * remote labels are handled separately -- by making
1661312a1df1SDavid du Colombier 	 * sure they are not pruned away during optimization
1662312a1df1SDavid du Colombier 	 */
1663312a1df1SDavid du Colombier 	AST_Changes = 1;	/* to get started */
1664312a1df1SDavid du Colombier 	for (AST_Round = 1; slicer && AST_Changes; AST_Round++)
1665312a1df1SDavid du Colombier 	{	AST_Changes = 0;
1666312a1df1SDavid du Colombier 		AST_data_dep();
1667312a1df1SDavid du Colombier 		AST_preserve();		/* moves processed vars from slicer to rel_vars */
1668312a1df1SDavid du Colombier 		AST_dominant();		/* mark data-irrelevant subgraphs */
1669312a1df1SDavid du Colombier 		AST_control_dep();	/* can add data deps, which add control deps */
1670312a1df1SDavid du Colombier 
1671312a1df1SDavid du Colombier 		if (verbose&32)
1672312a1df1SDavid du Colombier 			printf("\n\nROUND %d -- changes %d\n",
1673312a1df1SDavid du Colombier 				AST_Round, AST_Changes);
1674312a1df1SDavid du Colombier 	}
1675312a1df1SDavid du Colombier }
1676312a1df1SDavid du Colombier 
1677312a1df1SDavid du Colombier static void
AST_alias_analysis(void)1678312a1df1SDavid du Colombier AST_alias_analysis(void)		/* aliasing of promela channels */
1679312a1df1SDavid du Colombier {	AST *a;
1680312a1df1SDavid du Colombier 
1681312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)
1682312a1df1SDavid du Colombier 		AST_sends(a);		/* collect chan-names that are send across chans */
1683312a1df1SDavid du Colombier 
1684312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)
1685312a1df1SDavid du Colombier 		AST_para(a->p);		/* aliasing of chans thru proctype parameters */
1686312a1df1SDavid du Colombier 
1687312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)
1688312a1df1SDavid du Colombier 		AST_other(a);		/* chan params in asgns and recvs */
1689312a1df1SDavid du Colombier 
1690312a1df1SDavid du Colombier 	AST_trans();			/* transitive closure of alias table */
1691312a1df1SDavid du Colombier 
1692312a1df1SDavid du Colombier 	if (verbose&32)
1693312a1df1SDavid du Colombier 		AST_aliases();		/* show channel aliasing info */
1694312a1df1SDavid du Colombier }
1695312a1df1SDavid du Colombier 
1696312a1df1SDavid du Colombier void
AST_slice(void)1697312a1df1SDavid du Colombier AST_slice(void)
1698312a1df1SDavid du Colombier {	AST *a;
1699312a1df1SDavid du Colombier 	int spurious = 0;
1700312a1df1SDavid du Colombier 
1701312a1df1SDavid du Colombier 	if (!slicer)
170200d97012SDavid du Colombier 	{	printf("spin: warning: no slice criteria found (no assertions and no claim)\n");
1703312a1df1SDavid du Colombier 		spurious = 1;
1704312a1df1SDavid du Colombier 	}
1705312a1df1SDavid du Colombier 	AST_dorelevant();		/* mark procs refered to in remote refs */
1706312a1df1SDavid du Colombier 
1707312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)
1708312a1df1SDavid du Colombier 		AST_def_use(a);		/* compute standard def/use information */
1709312a1df1SDavid du Colombier 
1710312a1df1SDavid du Colombier 	AST_hidden();			/* parameter passing and local var inits */
1711312a1df1SDavid du Colombier 
1712312a1df1SDavid du Colombier 	AST_alias_analysis();		/* channel alias analysis */
1713312a1df1SDavid du Colombier 
1714312a1df1SDavid du Colombier 	AST_prelabel();			/* mark all 'assert(...)' stmnts as relevant */
1715312a1df1SDavid du Colombier 	AST_criteria();			/* process the slice criteria from
1716312a1df1SDavid du Colombier 					 * asserts and from the never claim
1717312a1df1SDavid du Colombier 					 */
1718312a1df1SDavid du Colombier 	if (!spurious || (verbose&32))
1719312a1df1SDavid du Colombier 	{	spurious = 1;
1720312a1df1SDavid du Colombier 		for (a = ast; a; a = a->nxt)
1721312a1df1SDavid du Colombier 		{	AST_dump(a);		/* marked up result */
1722312a1df1SDavid du Colombier 			if (a->relevant&2)	/* it printed something */
1723312a1df1SDavid du Colombier 				spurious = 0;
1724312a1df1SDavid du Colombier 		}
1725312a1df1SDavid du Colombier 		if (!AST_dump_rel()		/* relevant variables */
1726312a1df1SDavid du Colombier 		&&  spurious)
1727312a1df1SDavid du Colombier 			printf("spin: no redundancies found (for given property)\n");
1728312a1df1SDavid du Colombier 	}
1729312a1df1SDavid du Colombier 	AST_suggestions();
1730312a1df1SDavid du Colombier 
1731312a1df1SDavid du Colombier 	if (verbose&32)
1732312a1df1SDavid du Colombier 		show_expl();
1733312a1df1SDavid du Colombier }
1734312a1df1SDavid du Colombier 
1735312a1df1SDavid du Colombier void
AST_store(ProcList * p,int start_state)1736312a1df1SDavid du Colombier AST_store(ProcList *p, int start_state)
1737312a1df1SDavid du Colombier {	AST *n_ast;
1738312a1df1SDavid du Colombier 
173900d97012SDavid du Colombier 	if (p->b != N_CLAIM && p->b != E_TRACE && p->b != N_TRACE)
1740312a1df1SDavid du Colombier 	{	n_ast = (AST *) emalloc(sizeof(AST));
1741312a1df1SDavid du Colombier 		n_ast->p = p;
1742312a1df1SDavid du Colombier 		n_ast->i_st = start_state;
1743312a1df1SDavid du Colombier 		n_ast->relevant = 0;
1744*de2caf28SDavid du Colombier 		n_ast->fsm = fsmx;
1745312a1df1SDavid du Colombier 		n_ast->nxt = ast;
1746312a1df1SDavid du Colombier 		ast = n_ast;
1747312a1df1SDavid du Colombier 	}
1748*de2caf28SDavid du Colombier 	fsmx = (FSM_state *) 0;	/* hide it from FSM_DEL */
1749312a1df1SDavid du Colombier }
1750312a1df1SDavid du Colombier 
1751312a1df1SDavid du Colombier static void
AST_add_explicit(Lextok * d,Lextok * u)1752312a1df1SDavid du Colombier AST_add_explicit(Lextok *d, Lextok *u)
1753312a1df1SDavid du Colombier {	FSM_trans *e = (FSM_trans *) emalloc(sizeof(FSM_trans));
1754312a1df1SDavid du Colombier 
1755312a1df1SDavid du Colombier 	e->to = 0;			/* or start_state ? */
1756312a1df1SDavid du Colombier 	e->relevant = 0;		/* to be determined */
1757312a1df1SDavid du Colombier 	e->step = (Element *) 0;	/* left blank */
1758312a1df1SDavid du Colombier 	e->Val[0] = e->Val[1] = (FSM_use *) 0;
1759312a1df1SDavid du Colombier 
1760312a1df1SDavid du Colombier 	cur_t = e;
1761312a1df1SDavid du Colombier 
1762312a1df1SDavid du Colombier 	def_use(u, USE);
1763312a1df1SDavid du Colombier 	def_use(d, DEF);
1764312a1df1SDavid du Colombier 
1765312a1df1SDavid du Colombier 	cur_t = (FSM_trans *) 0;
1766312a1df1SDavid du Colombier 
1767312a1df1SDavid du Colombier 	e->nxt = explicit;
1768312a1df1SDavid du Colombier 	explicit = e;
1769312a1df1SDavid du Colombier }
1770312a1df1SDavid du Colombier 
1771312a1df1SDavid du Colombier static void
AST_fp1(char * s,Lextok * t,Lextok * f,int parno)1772312a1df1SDavid du Colombier AST_fp1(char *s, Lextok *t, Lextok *f, int parno)
1773312a1df1SDavid du Colombier {	Lextok *v;
1774312a1df1SDavid du Colombier 	int cnt;
1775312a1df1SDavid du Colombier 
1776312a1df1SDavid du Colombier 	if (!t) return;
1777312a1df1SDavid du Colombier 
1778312a1df1SDavid du Colombier 	if (t->ntyp == RUN)
1779312a1df1SDavid du Colombier 	{	if (strcmp(t->sym->name, s) == 0)
1780312a1df1SDavid du Colombier 		for (v = t->lft, cnt = 1; v; v = v->rgt, cnt++)
1781312a1df1SDavid du Colombier 			if (cnt == parno)
1782312a1df1SDavid du Colombier 			{	AST_add_explicit(f, v->lft);
1783312a1df1SDavid du Colombier 				break;
1784312a1df1SDavid du Colombier 			}
1785312a1df1SDavid du Colombier 	} else
1786312a1df1SDavid du Colombier 	{	AST_fp1(s, t->lft, f, parno);
1787312a1df1SDavid du Colombier 		AST_fp1(s, t->rgt, f, parno);
1788312a1df1SDavid du Colombier 	}
1789312a1df1SDavid du Colombier }
1790312a1df1SDavid du Colombier 
1791312a1df1SDavid du Colombier static void
AST_mk1(char * s,Lextok * c,int parno)1792312a1df1SDavid du Colombier AST_mk1(char *s, Lextok *c, int parno)
1793312a1df1SDavid du Colombier {	AST *a;
1794312a1df1SDavid du Colombier 	FSM_state *f;
1795312a1df1SDavid du Colombier 	FSM_trans *t;
1796312a1df1SDavid du Colombier 
1797312a1df1SDavid du Colombier 	/* concoct an extra FSM_trans *t with the asgn of
1798312a1df1SDavid du Colombier 	 * formal par c to matching actual pars made explicit
1799312a1df1SDavid du Colombier 	 */
1800312a1df1SDavid du Colombier 
1801312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)		/* automata       */
1802312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)		/* control states */
1803312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)		/* transitions    */
1804312a1df1SDavid du Colombier 	{	if (t->step)
1805312a1df1SDavid du Colombier 		AST_fp1(s, t->step->n, c, parno);
1806312a1df1SDavid du Colombier 	}
1807312a1df1SDavid du Colombier }
1808312a1df1SDavid du Colombier 
1809312a1df1SDavid du Colombier static void
AST_par_init(void)1810312a1df1SDavid du Colombier AST_par_init(void)	/* parameter passing -- hidden assignments */
1811312a1df1SDavid du Colombier {	AST *a;
1812312a1df1SDavid du Colombier 	Lextok *f, *t, *c;
1813312a1df1SDavid du Colombier 	int cnt;
1814312a1df1SDavid du Colombier 
1815312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)
181600d97012SDavid du Colombier 	{	if (a->p->b == N_CLAIM || a->p->b == I_PROC
181700d97012SDavid du Colombier 		||  a->p->b == E_TRACE || a->p->b == N_TRACE)
181800d97012SDavid du Colombier 		{	continue;			/* has no params */
181900d97012SDavid du Colombier 		}
1820312a1df1SDavid du Colombier 		cnt = 0;
1821312a1df1SDavid du Colombier 		for (f = a->p->p; f; f = f->rgt)	/* types */
1822312a1df1SDavid du Colombier 		for (t = f->lft; t; t = t->rgt)		/* formals */
1823312a1df1SDavid du Colombier 		{	cnt++;				/* formal par count */
1824312a1df1SDavid du Colombier 			c = (t->ntyp != ',')? t : t->lft;	/* the formal parameter */
1825312a1df1SDavid du Colombier 			AST_mk1(a->p->n->name, c, cnt);		/* all matching run statements */
1826312a1df1SDavid du Colombier 	}	}
1827312a1df1SDavid du Colombier }
1828312a1df1SDavid du Colombier 
1829312a1df1SDavid du Colombier static void
AST_var_init(void)1830312a1df1SDavid du Colombier AST_var_init(void)		/* initialized vars (not chans) - hidden assignments */
1831312a1df1SDavid du Colombier {	Ordered	*walk;
1832312a1df1SDavid du Colombier 	Lextok *x;
1833312a1df1SDavid du Colombier 	Symbol	*sp;
1834312a1df1SDavid du Colombier 	AST *a;
1835312a1df1SDavid du Colombier 
1836312a1df1SDavid du Colombier 	for (walk = all_names; walk; walk = walk->next)
1837312a1df1SDavid du Colombier 	{	sp = walk->entry;
1838312a1df1SDavid du Colombier 		if (sp
1839312a1df1SDavid du Colombier 		&&  !sp->context		/* globals */
1840312a1df1SDavid du Colombier 		&&  sp->type != PROCTYPE
1841312a1df1SDavid du Colombier 		&&  sp->ini
1842312a1df1SDavid du Colombier 		&& (sp->type != MTYPE || sp->ini->ntyp != CONST) /* not mtype defs */
1843312a1df1SDavid du Colombier 		&&  sp->ini->ntyp != CHAN)
1844312a1df1SDavid du Colombier 		{	x = nn(ZN, TYPE, ZN, ZN);
1845312a1df1SDavid du Colombier 			x->sym = sp;
1846312a1df1SDavid du Colombier 			AST_add_explicit(x, sp->ini);
1847312a1df1SDavid du Colombier 	}	}
1848312a1df1SDavid du Colombier 
1849312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)
185000d97012SDavid du Colombier 	{	if (a->p->b != N_CLAIM
185100d97012SDavid du Colombier 		&&  a->p->b != E_TRACE && a->p->b != N_TRACE)	/* has no locals */
1852312a1df1SDavid du Colombier 		for (walk = all_names; walk; walk = walk->next)
1853312a1df1SDavid du Colombier 		{	sp = walk->entry;
1854312a1df1SDavid du Colombier 			if (sp
1855312a1df1SDavid du Colombier 			&&  sp->context
1856312a1df1SDavid du Colombier 			&&  strcmp(sp->context->name, a->p->n->name) == 0
1857312a1df1SDavid du Colombier 			&&  sp->Nid >= 0	/* not a param */
1858312a1df1SDavid du Colombier 			&&  sp->type != LABEL
1859312a1df1SDavid du Colombier 			&&  sp->ini
1860312a1df1SDavid du Colombier 			&&  sp->ini->ntyp != CHAN)
1861312a1df1SDavid du Colombier 			{	x = nn(ZN, TYPE, ZN, ZN);
1862312a1df1SDavid du Colombier 				x->sym = sp;
1863312a1df1SDavid du Colombier 				AST_add_explicit(x, sp->ini);
1864312a1df1SDavid du Colombier 	}	}	}
1865312a1df1SDavid du Colombier }
1866312a1df1SDavid du Colombier 
1867312a1df1SDavid du Colombier static void
show_expl(void)1868312a1df1SDavid du Colombier show_expl(void)
1869312a1df1SDavid du Colombier {	FSM_trans *t, *T;
1870312a1df1SDavid du Colombier 	FSM_use *u;
1871312a1df1SDavid du Colombier 
1872312a1df1SDavid du Colombier 	printf("\nExplicit List:\n");
1873312a1df1SDavid du Colombier 	for (T = expl_par; T; T = (T == expl_par)?expl_var: (FSM_trans *) 0)
1874312a1df1SDavid du Colombier 	{	for (t = T; t; t = t->nxt)
1875312a1df1SDavid du Colombier 		{	if (!t->Val[0]) continue;
1876312a1df1SDavid du Colombier 			printf("%s", t->relevant?"*":" ");
1877312a1df1SDavid du Colombier 			printf("%3d", t->round);
1878312a1df1SDavid du Colombier 			for (u = t->Val[0]; u; u = u->nxt)
1879312a1df1SDavid du Colombier 			{	printf("\t<");
1880312a1df1SDavid du Colombier 				AST_var(u->n, u->n->sym, 1);
1881312a1df1SDavid du Colombier 				printf(":%d>, ", u->special);
1882312a1df1SDavid du Colombier 			}
1883312a1df1SDavid du Colombier 			printf("\n");
1884312a1df1SDavid du Colombier 		}
1885312a1df1SDavid du Colombier 		printf("==\n");
1886312a1df1SDavid du Colombier 	}
1887312a1df1SDavid du Colombier 	printf("End\n");
1888312a1df1SDavid du Colombier }
1889312a1df1SDavid du Colombier 
1890312a1df1SDavid du Colombier static void
AST_hidden(void)1891312a1df1SDavid du Colombier AST_hidden(void)			/* reveal all hidden assignments */
1892312a1df1SDavid du Colombier {
1893312a1df1SDavid du Colombier 	AST_par_init();
1894312a1df1SDavid du Colombier 	expl_par = explicit;
1895312a1df1SDavid du Colombier 	explicit = (FSM_trans *) 0;
1896312a1df1SDavid du Colombier 
1897312a1df1SDavid du Colombier 	AST_var_init();
1898312a1df1SDavid du Colombier 	expl_var = explicit;
1899312a1df1SDavid du Colombier 	explicit = (FSM_trans *) 0;
1900312a1df1SDavid du Colombier }
1901312a1df1SDavid du Colombier 
1902312a1df1SDavid du Colombier #define BPW	(8*sizeof(ulong))			/* bits per word */
1903312a1df1SDavid du Colombier 
1904312a1df1SDavid du Colombier static int
bad_scratch(FSM_state * f,int upto)1905312a1df1SDavid du Colombier bad_scratch(FSM_state *f, int upto)
1906312a1df1SDavid du Colombier {	FSM_trans *t;
1907312a1df1SDavid du Colombier #if 0
1908312a1df1SDavid du Colombier 	1. all internal branch-points have else-s
1909312a1df1SDavid du Colombier 	2. all non-branchpoints have non-blocking out-edge
1910312a1df1SDavid du Colombier 	3. all internal edges are non-relevant
1911312a1df1SDavid du Colombier 	subgraphs like this need NOT contribute control-dependencies
1912312a1df1SDavid du Colombier #endif
1913312a1df1SDavid du Colombier 
1914312a1df1SDavid du Colombier 	if (!f->seen
1915312a1df1SDavid du Colombier 	||  (f->scratch&4))
1916312a1df1SDavid du Colombier 		return 0;
1917312a1df1SDavid du Colombier 
1918312a1df1SDavid du Colombier 	if (f->scratch&8)
1919312a1df1SDavid du Colombier 		return 1;
1920312a1df1SDavid du Colombier 
1921312a1df1SDavid du Colombier 	f->scratch |= 4;
1922312a1df1SDavid du Colombier 
1923312a1df1SDavid du Colombier 	if (verbose&32) printf("X[%d:%d:%d] ", f->from, upto, f->scratch);
1924312a1df1SDavid du Colombier 
1925312a1df1SDavid du Colombier 	if (f->scratch&1)
1926312a1df1SDavid du Colombier 	{	if (verbose&32)
1927312a1df1SDavid du Colombier 			printf("\tbad scratch: %d\n", f->from);
1928312a1df1SDavid du Colombier bad:		f->scratch &= ~4;
1929312a1df1SDavid du Colombier 	/*	f->scratch |=  8;	 wrong */
1930312a1df1SDavid du Colombier 		return 1;
1931312a1df1SDavid du Colombier 	}
1932312a1df1SDavid du Colombier 
1933312a1df1SDavid du Colombier 	if (f->from != upto)
1934312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)
1935312a1df1SDavid du Colombier 		if (bad_scratch(fsm_tbl[t->to], upto))
1936312a1df1SDavid du Colombier 			goto bad;
1937312a1df1SDavid du Colombier 
1938312a1df1SDavid du Colombier 	return 0;
1939312a1df1SDavid du Colombier }
1940312a1df1SDavid du Colombier 
1941312a1df1SDavid du Colombier static void
mark_subgraph(FSM_state * f,int upto)1942312a1df1SDavid du Colombier mark_subgraph(FSM_state *f, int upto)
1943312a1df1SDavid du Colombier {	FSM_trans *t;
1944312a1df1SDavid du Colombier 
1945312a1df1SDavid du Colombier 	if (f->from == upto
1946312a1df1SDavid du Colombier 	||  !f->seen
1947312a1df1SDavid du Colombier 	||  (f->scratch&2))
1948312a1df1SDavid du Colombier 		return;
1949312a1df1SDavid du Colombier 
1950312a1df1SDavid du Colombier 	f->scratch |= 2;
1951312a1df1SDavid du Colombier 
1952312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)
1953312a1df1SDavid du Colombier 		mark_subgraph(fsm_tbl[t->to], upto);
1954312a1df1SDavid du Colombier }
1955312a1df1SDavid du Colombier 
1956312a1df1SDavid du Colombier static void
AST_pair(AST * a,FSM_state * h,int y)1957312a1df1SDavid du Colombier AST_pair(AST *a, FSM_state *h, int y)
1958312a1df1SDavid du Colombier {	Pair *p;
1959312a1df1SDavid du Colombier 
1960312a1df1SDavid du Colombier 	for (p = a->pairs; p; p = p->nxt)
1961312a1df1SDavid du Colombier 		if (p->h == h
1962312a1df1SDavid du Colombier 		&&  p->b == y)
1963312a1df1SDavid du Colombier 			return;
1964312a1df1SDavid du Colombier 
1965312a1df1SDavid du Colombier 	p = (Pair *) emalloc(sizeof(Pair));
1966312a1df1SDavid du Colombier 	p->h = h;
1967312a1df1SDavid du Colombier 	p->b = y;
1968312a1df1SDavid du Colombier 	p->nxt = a->pairs;
1969312a1df1SDavid du Colombier 	a->pairs = p;
1970312a1df1SDavid du Colombier }
1971312a1df1SDavid du Colombier 
1972312a1df1SDavid du Colombier static void
AST_checkpairs(AST * a)1973312a1df1SDavid du Colombier AST_checkpairs(AST *a)
1974312a1df1SDavid du Colombier {	Pair *p;
1975312a1df1SDavid du Colombier 
1976312a1df1SDavid du Colombier 	for (p = a->pairs; p; p = p->nxt)
1977312a1df1SDavid du Colombier 	{	if (verbose&32)
1978312a1df1SDavid du Colombier 			printf("	inspect pair %d %d\n", p->b, p->h->from);
1979312a1df1SDavid du Colombier 		if (!bad_scratch(p->h, p->b))	/* subgraph is clean */
1980312a1df1SDavid du Colombier 		{	if (verbose&32)
1981312a1df1SDavid du Colombier 				printf("subgraph: %d .. %d\n", p->b, p->h->from);
1982312a1df1SDavid du Colombier 			mark_subgraph(p->h, p->b);
1983312a1df1SDavid du Colombier 		}
1984312a1df1SDavid du Colombier 	}
1985312a1df1SDavid du Colombier }
1986312a1df1SDavid du Colombier 
1987312a1df1SDavid du Colombier static void
subgraph(AST * a,FSM_state * f,int out)1988312a1df1SDavid du Colombier subgraph(AST *a, FSM_state *f, int out)
1989312a1df1SDavid du Colombier {	FSM_state *h;
1990312a1df1SDavid du Colombier 	int i, j;
1991312a1df1SDavid du Colombier 	ulong *g;
1992312a1df1SDavid du Colombier #if 0
1993312a1df1SDavid du Colombier 	reverse dominance suggests that this is a possible
1994312a1df1SDavid du Colombier 	entry and exit node for a proper subgraph
1995312a1df1SDavid du Colombier #endif
1996312a1df1SDavid du Colombier 	h = fsm_tbl[out];
1997312a1df1SDavid du Colombier 
1998312a1df1SDavid du Colombier 	i = f->from / BPW;
1999*de2caf28SDavid du Colombier 	j = f->from % BPW; /* assert(j <= 32); else lshift undefined? */
2000312a1df1SDavid du Colombier 	g = h->mod;
2001312a1df1SDavid du Colombier 
2002312a1df1SDavid du Colombier 	if (verbose&32)
2003312a1df1SDavid du Colombier 		printf("possible pair %d %d -- %d\n",
2004312a1df1SDavid du Colombier 			f->from, h->from, (g[i]&(1<<j))?1:0);
2005312a1df1SDavid du Colombier 
2006312a1df1SDavid du Colombier 	if (g[i]&(1<<j))		/* also a forward dominance pair */
2007312a1df1SDavid du Colombier 		AST_pair(a, h, f->from);	/* record this pair */
2008312a1df1SDavid du Colombier }
2009312a1df1SDavid du Colombier 
2010312a1df1SDavid du Colombier static void
act_dom(AST * a)2011312a1df1SDavid du Colombier act_dom(AST *a)
2012312a1df1SDavid du Colombier {	FSM_state *f;
2013312a1df1SDavid du Colombier 	FSM_trans *t;
2014312a1df1SDavid du Colombier 	int i, j, cnt;
2015312a1df1SDavid du Colombier 
2016312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)
2017312a1df1SDavid du Colombier 	{	if (!f->seen) continue;
2018312a1df1SDavid du Colombier #if 0
2019312a1df1SDavid du Colombier 		f->from is the exit-node of a proper subgraph, with
2020312a1df1SDavid du Colombier 		the dominator its entry-node, if:
2021312a1df1SDavid du Colombier 		a. this node has more than 1 reachable predecessor
2022312a1df1SDavid du Colombier 		b. the dominator has more than 1 reachable successor
2023312a1df1SDavid du Colombier 		   (need reachability - in case of reverse dominance)
2024312a1df1SDavid du Colombier 		d. the dominator is reachable, and not equal to this node
2025312a1df1SDavid du Colombier #endif
2026312a1df1SDavid du Colombier 		for (t = f->p, i = 0; t; t = t->nxt)
2027*de2caf28SDavid du Colombier 		{	i += fsm_tbl[t->to]->seen;
2028*de2caf28SDavid du Colombier 		}
2029*de2caf28SDavid du Colombier 		if (i <= 1)
2030*de2caf28SDavid du Colombier 		{	continue;					/* a. */
2031*de2caf28SDavid du Colombier 		}
2032312a1df1SDavid du Colombier 		for (cnt = 1; cnt < a->nstates; cnt++)	/* 0 is endstate */
2033312a1df1SDavid du Colombier 		{	if (cnt == f->from
2034312a1df1SDavid du Colombier 			||  !fsm_tbl[cnt]->seen)
2035*de2caf28SDavid du Colombier 			{	continue;				/* c. */
2036*de2caf28SDavid du Colombier 			}
2037312a1df1SDavid du Colombier 			i = cnt / BPW;
2038*de2caf28SDavid du Colombier 			j = cnt % BPW;	/* assert(j <= 32); */
2039312a1df1SDavid du Colombier 			if (!(f->dom[i]&(1<<j)))
2040*de2caf28SDavid du Colombier 			{	continue;
2041*de2caf28SDavid du Colombier 			}
2042312a1df1SDavid du Colombier 			for (t = fsm_tbl[cnt]->t, i = 0; t; t = t->nxt)
2043*de2caf28SDavid du Colombier 			{	i += fsm_tbl[t->to]->seen;
2044*de2caf28SDavid du Colombier 			}
2045312a1df1SDavid du Colombier 			if (i <= 1)
2046*de2caf28SDavid du Colombier 			{	continue;				/* b. */
2047*de2caf28SDavid du Colombier 			}
2048312a1df1SDavid du Colombier 			if (f->mod)			/* final check in 2nd phase */
2049*de2caf28SDavid du Colombier 			{	subgraph(a, f, cnt);	/* possible entry-exit pair */
2050*de2caf28SDavid du Colombier 	}	}	}
2051312a1df1SDavid du Colombier }
2052312a1df1SDavid du Colombier 
2053312a1df1SDavid du Colombier static void
reachability(AST * a)2054312a1df1SDavid du Colombier reachability(AST *a)
2055312a1df1SDavid du Colombier {	FSM_state *f;
2056312a1df1SDavid du Colombier 
2057312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)
2058312a1df1SDavid du Colombier 		f->seen = 0;		/* clear */
2059312a1df1SDavid du Colombier 	AST_dfs(a, a->i_st, 0);		/* mark 'seen' */
2060312a1df1SDavid du Colombier }
2061312a1df1SDavid du Colombier 
2062312a1df1SDavid du Colombier static int
see_else(FSM_state * f)2063312a1df1SDavid du Colombier see_else(FSM_state *f)
2064312a1df1SDavid du Colombier {	FSM_trans *t;
2065312a1df1SDavid du Colombier 
2066312a1df1SDavid du Colombier 	for (t = f->t; t; t = t->nxt)
2067312a1df1SDavid du Colombier 	{	if (t->step
2068312a1df1SDavid du Colombier 		&&  t->step->n)
2069312a1df1SDavid du Colombier 		switch (t->step->n->ntyp) {
2070312a1df1SDavid du Colombier 		case ELSE:
2071312a1df1SDavid du Colombier 			return 1;
2072312a1df1SDavid du Colombier 		case IF:
2073312a1df1SDavid du Colombier 		case DO:
2074312a1df1SDavid du Colombier 		case ATOMIC:
2075312a1df1SDavid du Colombier 		case NON_ATOMIC:
2076312a1df1SDavid du Colombier 		case D_STEP:
2077312a1df1SDavid du Colombier 			if (see_else(fsm_tbl[t->to]))
2078312a1df1SDavid du Colombier 				return 1;
2079312a1df1SDavid du Colombier 		default:
2080312a1df1SDavid du Colombier 			break;
2081312a1df1SDavid du Colombier 		}
2082312a1df1SDavid du Colombier 	}
2083312a1df1SDavid du Colombier 	return 0;
2084312a1df1SDavid du Colombier }
2085312a1df1SDavid du Colombier 
2086312a1df1SDavid du Colombier static int
is_guard(FSM_state * f)2087312a1df1SDavid du Colombier is_guard(FSM_state *f)
2088312a1df1SDavid du Colombier {	FSM_state *g;
2089312a1df1SDavid du Colombier 	FSM_trans *t;
2090312a1df1SDavid du Colombier 
2091312a1df1SDavid du Colombier 	for (t = f->p; t; t = t->nxt)
2092312a1df1SDavid du Colombier 	{	g = fsm_tbl[t->to];
2093312a1df1SDavid du Colombier 		if (!g->seen)
2094312a1df1SDavid du Colombier 			continue;
2095312a1df1SDavid du Colombier 
2096312a1df1SDavid du Colombier 		if (t->step
2097312a1df1SDavid du Colombier 		&&  t->step->n)
2098312a1df1SDavid du Colombier 		switch(t->step->n->ntyp) {
2099312a1df1SDavid du Colombier 		case IF:
2100312a1df1SDavid du Colombier 		case DO:
2101312a1df1SDavid du Colombier 			return 1;
2102312a1df1SDavid du Colombier 		case ATOMIC:
2103312a1df1SDavid du Colombier 		case NON_ATOMIC:
2104312a1df1SDavid du Colombier 		case D_STEP:
2105312a1df1SDavid du Colombier 			if (is_guard(g))
2106312a1df1SDavid du Colombier 				return 1;
2107312a1df1SDavid du Colombier 		default:
2108312a1df1SDavid du Colombier 			break;
2109312a1df1SDavid du Colombier 		}
2110312a1df1SDavid du Colombier 	}
2111312a1df1SDavid du Colombier 	return 0;
2112312a1df1SDavid du Colombier }
2113312a1df1SDavid du Colombier 
2114312a1df1SDavid du Colombier static void
curtail(AST * a)2115312a1df1SDavid du Colombier curtail(AST *a)
2116312a1df1SDavid du Colombier {	FSM_state *f, *g;
2117312a1df1SDavid du Colombier 	FSM_trans *t;
2118312a1df1SDavid du Colombier 	int i, haselse, isrel, blocking;
2119312a1df1SDavid du Colombier #if 0
2120312a1df1SDavid du Colombier 	mark nodes that do not satisfy these requirements:
2121312a1df1SDavid du Colombier 	1. all internal branch-points have else-s
2122312a1df1SDavid du Colombier 	2. all non-branchpoints have non-blocking out-edge
2123312a1df1SDavid du Colombier 	3. all internal edges are non-data-relevant
2124312a1df1SDavid du Colombier #endif
2125312a1df1SDavid du Colombier 	if (verbose&32)
2126312a1df1SDavid du Colombier 		printf("Curtail %s:\n", a->p->n->name);
2127312a1df1SDavid du Colombier 
2128312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)
2129312a1df1SDavid du Colombier 	{	if (!f->seen
2130312a1df1SDavid du Colombier 		||  (f->scratch&(1|2)))
2131312a1df1SDavid du Colombier 			continue;
2132312a1df1SDavid du Colombier 
2133312a1df1SDavid du Colombier 		isrel = haselse = i = blocking = 0;
2134312a1df1SDavid du Colombier 
2135312a1df1SDavid du Colombier 		for (t = f->t; t; t = t->nxt)
2136312a1df1SDavid du Colombier 		{	g = fsm_tbl[t->to];
2137312a1df1SDavid du Colombier 
2138312a1df1SDavid du Colombier 			isrel |= (t->relevant&1);	/* data relevant */
2139312a1df1SDavid du Colombier 			i += g->seen;
2140312a1df1SDavid du Colombier 
2141312a1df1SDavid du Colombier 			if (t->step
2142312a1df1SDavid du Colombier 			&&  t->step->n)
2143312a1df1SDavid du Colombier 			{	switch (t->step->n->ntyp) {
2144312a1df1SDavid du Colombier 				case IF:
2145312a1df1SDavid du Colombier 				case DO:
2146312a1df1SDavid du Colombier 					haselse |= see_else(g);
2147312a1df1SDavid du Colombier 					break;
2148312a1df1SDavid du Colombier 				case 'c':
2149312a1df1SDavid du Colombier 				case 's':
2150312a1df1SDavid du Colombier 				case 'r':
2151312a1df1SDavid du Colombier 					blocking = 1;
2152312a1df1SDavid du Colombier 					break;
2153312a1df1SDavid du Colombier 		}	}	}
2154312a1df1SDavid du Colombier #if 0
2155312a1df1SDavid du Colombier 		if (verbose&32)
2156312a1df1SDavid du Colombier 			printf("prescratch %d -- %d %d %d %d -- %d\n",
2157312a1df1SDavid du Colombier 				f->from, i, isrel, blocking, haselse, is_guard(f));
2158312a1df1SDavid du Colombier #endif
2159312a1df1SDavid du Colombier 		if (isrel			/* 3. */
2160312a1df1SDavid du Colombier 		||  (i == 1 && blocking)	/* 2. */
2161312a1df1SDavid du Colombier 		||  (i >  1 && !haselse))	/* 1. */
2162312a1df1SDavid du Colombier 		{	if (!is_guard(f))
2163312a1df1SDavid du Colombier 			{	f->scratch |= 1;
2164312a1df1SDavid du Colombier 				if (verbose&32)
2165312a1df1SDavid du Colombier 				printf("scratch %d -- %d %d %d %d\n",
2166312a1df1SDavid du Colombier 					f->from, i, isrel, blocking, haselse);
2167312a1df1SDavid du Colombier 			}
2168312a1df1SDavid du Colombier 		}
2169312a1df1SDavid du Colombier 	}
2170312a1df1SDavid du Colombier }
2171312a1df1SDavid du Colombier 
2172312a1df1SDavid du Colombier static void
init_dom(AST * a)2173312a1df1SDavid du Colombier init_dom(AST *a)
2174312a1df1SDavid du Colombier {	FSM_state *f;
2175312a1df1SDavid du Colombier 	int i, j, cnt;
2176312a1df1SDavid du Colombier #if 0
2177312a1df1SDavid du Colombier 	(1)  D(s0) = {s0}
2178312a1df1SDavid du Colombier 	(2)  for s in S - {s0} do D(s) = S
2179312a1df1SDavid du Colombier #endif
2180312a1df1SDavid du Colombier 
2181312a1df1SDavid du Colombier 	for (f = a->fsm; f; f = f->nxt)
2182312a1df1SDavid du Colombier 	{	if (!f->seen) continue;
2183312a1df1SDavid du Colombier 
2184*de2caf28SDavid du Colombier 		f->dom = (ulong *) emalloc(a->nwords * sizeof(ulong));
2185312a1df1SDavid du Colombier 
2186312a1df1SDavid du Colombier 		if (f->from == a->i_st)
2187312a1df1SDavid du Colombier 		{	i = a->i_st / BPW;
2188*de2caf28SDavid du Colombier 			j = a->i_st % BPW; /* assert(j <= 32); */
2189312a1df1SDavid du Colombier 			f->dom[i] = (1<<j);			/* (1) */
2190312a1df1SDavid du Colombier 		} else						/* (2) */
2191312a1df1SDavid du Colombier 		{	for (i = 0; i < a->nwords; i++)
2192*de2caf28SDavid du Colombier 			{	f->dom[i] = (ulong) ~0;		/* all 1's */
2193*de2caf28SDavid du Colombier 			}
2194312a1df1SDavid du Colombier 			if (a->nstates % BPW)
2195f3793cddSDavid du Colombier 			for (i = (a->nstates % BPW); i < (int) BPW; i++)
2196*de2caf28SDavid du Colombier 			{	f->dom[a->nwords-1] &= ~(1<< ((ulong) i)); /* clear tail */
2197*de2caf28SDavid du Colombier 			}
2198312a1df1SDavid du Colombier 			for (cnt = 0; cnt < a->nstates; cnt++)
2199*de2caf28SDavid du Colombier 			{	if (!fsm_tbl[cnt]->seen)
2200312a1df1SDavid du Colombier 				{	i = cnt / BPW;
2201*de2caf28SDavid du Colombier 					j = cnt % BPW; /* assert(j <= 32); */
2202*de2caf28SDavid du Colombier 					f->dom[i] &= ~(1<< ((ulong) j));
2203*de2caf28SDavid du Colombier 	}	}	}	}
2204312a1df1SDavid du Colombier }
2205312a1df1SDavid du Colombier 
2206312a1df1SDavid du Colombier static int
dom_perculate(AST * a,FSM_state * f)2207312a1df1SDavid du Colombier dom_perculate(AST *a, FSM_state *f)
2208312a1df1SDavid du Colombier {	static ulong *ndom = (ulong *) 0;
2209312a1df1SDavid du Colombier 	static int on = 0;
2210312a1df1SDavid du Colombier 	int i, j, cnt = 0;
2211312a1df1SDavid du Colombier 	FSM_state *g;
2212312a1df1SDavid du Colombier 	FSM_trans *t;
2213312a1df1SDavid du Colombier 
2214312a1df1SDavid du Colombier 	if (on < a->nwords)
2215312a1df1SDavid du Colombier 	{	on = a->nwords;
2216312a1df1SDavid du Colombier 		ndom = (ulong *)
2217312a1df1SDavid du Colombier 			emalloc(on * sizeof(ulong));
2218312a1df1SDavid du Colombier 	}
2219312a1df1SDavid du Colombier 
2220312a1df1SDavid du Colombier 	for (i = 0; i < a->nwords; i++)
2221312a1df1SDavid du Colombier 		ndom[i] = (ulong) ~0;
2222312a1df1SDavid du Colombier 
2223312a1df1SDavid du Colombier 	for (t = f->p; t; t = t->nxt)	/* all reachable predecessors */
2224312a1df1SDavid du Colombier 	{	g = fsm_tbl[t->to];
2225312a1df1SDavid du Colombier 		if (g->seen)
2226312a1df1SDavid du Colombier 		for (i = 0; i < a->nwords; i++)
2227312a1df1SDavid du Colombier 			ndom[i] &= g->dom[i];	/* (5b) */
2228312a1df1SDavid du Colombier 	}
2229312a1df1SDavid du Colombier 
2230312a1df1SDavid du Colombier 	i = f->from / BPW;
2231*de2caf28SDavid du Colombier 	j = f->from % BPW;	/* assert(j <= 32); */
2232312a1df1SDavid du Colombier 	ndom[i] |= (1<<j);			/* (5a) */
2233312a1df1SDavid du Colombier 
2234312a1df1SDavid du Colombier 	for (i = 0; i < a->nwords; i++)
2235312a1df1SDavid du Colombier 		if (f->dom[i] != ndom[i])
2236312a1df1SDavid du Colombier 		{	cnt++;
2237312a1df1SDavid du Colombier 			f->dom[i] = ndom[i];
2238312a1df1SDavid du Colombier 		}
2239312a1df1SDavid du Colombier 
2240312a1df1SDavid du Colombier 	return cnt;
2241312a1df1SDavid du Colombier }
2242312a1df1SDavid du Colombier 
2243312a1df1SDavid du Colombier static void
dom_forward(AST * a)2244312a1df1SDavid du Colombier dom_forward(AST *a)
2245312a1df1SDavid du Colombier {	FSM_state *f;
2246312a1df1SDavid du Colombier 	int cnt;
2247312a1df1SDavid du Colombier 
2248312a1df1SDavid du Colombier 	init_dom(a);						/* (1,2) */
2249312a1df1SDavid du Colombier 	do {
2250312a1df1SDavid du Colombier 		cnt = 0;
2251312a1df1SDavid du Colombier 		for (f = a->fsm; f; f = f->nxt)
2252312a1df1SDavid du Colombier 		{	if (f->seen
2253312a1df1SDavid du Colombier 			&&  f->from != a->i_st)			/* (4) */
2254312a1df1SDavid du Colombier 				cnt += dom_perculate(a, f);	/* (5) */
2255312a1df1SDavid du Colombier 		}
2256312a1df1SDavid du Colombier 	} while (cnt);						/* (3) */
2257312a1df1SDavid du Colombier 	dom_perculate(a, fsm_tbl[a->i_st]);
2258312a1df1SDavid du Colombier }
2259312a1df1SDavid du Colombier 
2260312a1df1SDavid du Colombier static void
AST_dominant(void)2261312a1df1SDavid du Colombier AST_dominant(void)
2262312a1df1SDavid du Colombier {	FSM_state *f;
2263312a1df1SDavid du Colombier 	FSM_trans *t;
2264312a1df1SDavid du Colombier 	AST *a;
2265312a1df1SDavid du Colombier 	int oi;
226600d97012SDavid du Colombier 	static FSM_state no_state;
2267312a1df1SDavid du Colombier #if 0
2268312a1df1SDavid du Colombier 	find dominators
2269312a1df1SDavid du Colombier 	Aho, Sethi, & Ullman, Compilers - principles, techniques, and tools
2270312a1df1SDavid du Colombier 	Addison-Wesley, 1986, p.671.
2271312a1df1SDavid du Colombier 
2272312a1df1SDavid du Colombier 	(1)  D(s0) = {s0}
2273312a1df1SDavid du Colombier 	(2)  for s in S - {s0} do D(s) = S
2274312a1df1SDavid du Colombier 
2275312a1df1SDavid du Colombier 	(3)  while any D(s) changes do
2276312a1df1SDavid du Colombier 	(4)    for s in S - {s0} do
2277312a1df1SDavid du Colombier 	(5)	D(s) = {s} union  with intersection of all D(p)
2278312a1df1SDavid du Colombier 		where p are the immediate predecessors of s
2279312a1df1SDavid du Colombier 
2280312a1df1SDavid du Colombier 	the purpose is to find proper subgraphs
2281312a1df1SDavid du Colombier 	(one entry node, one exit node)
2282312a1df1SDavid du Colombier #endif
2283312a1df1SDavid du Colombier 	if (AST_Round == 1)	/* computed once, reused in every round */
2284312a1df1SDavid du Colombier 	for (a = ast; a; a = a->nxt)
2285312a1df1SDavid du Colombier 	{	a->nstates = 0;
2286312a1df1SDavid du Colombier 		for (f = a->fsm; f; f = f->nxt)
2287312a1df1SDavid du Colombier 		{	a->nstates++;				/* count */
2288312a1df1SDavid du Colombier 			fsm_tbl[f->from] = f;			/* fast lookup */
2289312a1df1SDavid du Colombier 			f->scratch = 0;				/* clear scratch marks */
2290312a1df1SDavid du Colombier 		}
2291312a1df1SDavid du Colombier 		for (oi = 0; oi < a->nstates; oi++)
2292312a1df1SDavid du Colombier 			if (!fsm_tbl[oi])
2293312a1df1SDavid du Colombier 				fsm_tbl[oi] = &no_state;
2294312a1df1SDavid du Colombier 
2295312a1df1SDavid du Colombier 		a->nwords = (a->nstates + BPW - 1) / BPW;	/* round up */
2296312a1df1SDavid du Colombier 
2297312a1df1SDavid du Colombier 		if (verbose&32)
2298312a1df1SDavid du Colombier 		{	printf("%s (%d): ", a->p->n->name, a->i_st);
2299312a1df1SDavid du Colombier 			printf("states=%d (max %d), words = %d, bpw %d, overflow %d\n",
2300312a1df1SDavid du Colombier 				a->nstates, o_max, a->nwords,
2301312a1df1SDavid du Colombier 				(int) BPW, (int) (a->nstates % BPW));
2302312a1df1SDavid du Colombier 		}
2303312a1df1SDavid du Colombier 
2304312a1df1SDavid du Colombier 		reachability(a);
2305312a1df1SDavid du Colombier 		dom_forward(a);		/* forward dominance relation */
2306312a1df1SDavid du Colombier 
2307312a1df1SDavid du Colombier 		curtail(a);		/* mark ineligible edges */
2308312a1df1SDavid du Colombier 		for (f = a->fsm; f; f = f->nxt)
2309312a1df1SDavid du Colombier 		{	t = f->p;
2310312a1df1SDavid du Colombier 			f->p = f->t;
2311312a1df1SDavid du Colombier 			f->t = t;	/* invert edges */
2312312a1df1SDavid du Colombier 
2313312a1df1SDavid du Colombier 			f->mod = f->dom;
2314312a1df1SDavid du Colombier 			f->dom = (ulong *) 0;
2315312a1df1SDavid du Colombier 		}
2316312a1df1SDavid du Colombier 		oi = a->i_st;
2317312a1df1SDavid du Colombier 		if (fsm_tbl[0]->seen)	/* end-state reachable - else leave it */
2318312a1df1SDavid du Colombier 			a->i_st = 0;	/* becomes initial state */
2319312a1df1SDavid du Colombier 
2320312a1df1SDavid du Colombier 		dom_forward(a);		/* reverse dominance -- don't redo reachability! */
2321312a1df1SDavid du Colombier 		act_dom(a);		/* mark proper subgraphs, if any */
2322312a1df1SDavid du Colombier 		AST_checkpairs(a);	/* selectively place 2 scratch-marks */
2323312a1df1SDavid du Colombier 
2324312a1df1SDavid du Colombier 		for (f = a->fsm; f; f = f->nxt)
2325312a1df1SDavid du Colombier 		{	t = f->p;
2326312a1df1SDavid du Colombier 			f->p = f->t;
2327312a1df1SDavid du Colombier 			f->t = t;	/* restore */
2328312a1df1SDavid du Colombier 		}
2329312a1df1SDavid du Colombier 		a->i_st = oi;	/* restore */
2330312a1df1SDavid du Colombier 	} else
2331312a1df1SDavid du Colombier 		for (a = ast; a; a = a->nxt)
2332312a1df1SDavid du Colombier 		{	for (f = a->fsm; f; f = f->nxt)
2333312a1df1SDavid du Colombier 			{	fsm_tbl[f->from] = f;
2334312a1df1SDavid du Colombier 				f->scratch &= 1; /* preserve 1-marks */
2335312a1df1SDavid du Colombier 			}
2336312a1df1SDavid du Colombier 			for (oi = 0; oi < a->nstates; oi++)
2337312a1df1SDavid du Colombier 				if (!fsm_tbl[oi])
2338312a1df1SDavid du Colombier 					fsm_tbl[oi] = &no_state;
2339312a1df1SDavid du Colombier 
2340312a1df1SDavid du Colombier 			curtail(a);		/* mark ineligible edges */
2341312a1df1SDavid du Colombier 
2342312a1df1SDavid du Colombier 			for (f = a->fsm; f; f = f->nxt)
2343312a1df1SDavid du Colombier 			{	t = f->p;
2344312a1df1SDavid du Colombier 				f->p = f->t;
2345312a1df1SDavid du Colombier 				f->t = t;	/* invert edges */
2346312a1df1SDavid du Colombier 			}
2347312a1df1SDavid du Colombier 
2348312a1df1SDavid du Colombier 			AST_checkpairs(a);	/* recompute 2-marks */
2349312a1df1SDavid du Colombier 
2350312a1df1SDavid du Colombier 			for (f = a->fsm; f; f = f->nxt)
2351312a1df1SDavid du Colombier 			{	t = f->p;
2352312a1df1SDavid du Colombier 				f->p = f->t;
2353312a1df1SDavid du Colombier 				f->t = t;	/* restore */
2354312a1df1SDavid du Colombier 		}	}
2355312a1df1SDavid du Colombier }
2356