xref: /plan9-contrib/sys/src/cmd/spin/pangen5.c (revision de2caf28f9ba1a56e70be94a699435d36eb50311)
1 /***** spin: pangen5.c *****/
2 
3 /*
4  * This file is part of the public release of Spin. It is subject to the
5  * terms in the LICENSE file that is included in this source directory.
6  * Tool documentation is available at http://spinroot.com
7  */
8 
9 #include "spin.h"
10 #include "y.tab.h"
11 
12 typedef struct BuildStack {
13 	FSM_trans *t;
14 	struct BuildStack *nxt;
15 } BuildStack;
16 
17 extern ProcList	*ready;
18 extern int verbose, eventmapnr, claimnr, rvopt, export_ast, u_sync;
19 extern Element *Al_El;
20 
21 static FSM_state *fsm_free;
22 static FSM_trans *trans_free;
23 static BuildStack *bs, *bf;
24 static int max_st_id;
25 static int cur_st_id;
26 int o_max;
27 FSM_state *fsmx;
28 FSM_state **fsm_tbl;
29 FSM_use   *use_free;
30 
31 static void ana_seq(Sequence *);
32 static void ana_stmnt(FSM_trans *, Lextok *, int);
33 
34 extern void AST_slice(void);
35 extern void AST_store(ProcList *, int);
36 extern int  has_global(Lextok *);
37 extern void exit(int);
38 
39 static void
fsm_table(void)40 fsm_table(void)
41 {	FSM_state *f;
42 	max_st_id += 2;
43 	/* fprintf(stderr, "omax %d, max=%d\n", o_max, max_st_id); */
44 	if (o_max < max_st_id)
45 	{	o_max = max_st_id;
46 		fsm_tbl = (FSM_state **) emalloc(max_st_id * sizeof(FSM_state *));
47 	} else
48 		memset((char *)fsm_tbl, 0, max_st_id * sizeof(FSM_state *));
49 	cur_st_id = max_st_id;
50 	max_st_id = 0;
51 
52 	for (f = fsmx; f; f = f->nxt)
53 		fsm_tbl[f->from] = f;
54 }
55 
56 static int
FSM_DFS(int from,FSM_use * u)57 FSM_DFS(int from, FSM_use *u)
58 {	FSM_state *f;
59 	FSM_trans *t;
60 	FSM_use *v;
61 	int n;
62 
63 	if (from == 0)
64 		return 1;
65 
66 	f = fsm_tbl[from];
67 
68 	if (!f)
69 	{	printf("cannot find state %d\n", from);
70 		fatal("fsm_dfs: cannot happen\n", (char *) 0);
71 	}
72 
73 	if (f->seen)
74 		return 1;
75 	f->seen = 1;
76 
77 	for (t = f->t; t; t = t->nxt)
78 	{
79 		for (n = 0; n < 2; n++)
80 		for (v = t->Val[n]; v; v = v->nxt)
81 			if (u->var == v->var)
82 				return n;	/* a read or write */
83 
84 		if (!FSM_DFS(t->to, u))
85 			return 0;
86 	}
87 	return 1;
88 }
89 
90 static void
new_dfs(void)91 new_dfs(void)
92 {	int i;
93 
94 	for (i = 0; i < cur_st_id; i++)
95 		if (fsm_tbl[i])
96 			fsm_tbl[i]->seen = 0;
97 }
98 
99 static int
good_dead(Element * e,FSM_use * u)100 good_dead(Element *e, FSM_use *u)
101 {
102 	switch (u->special) {
103 	case 2:	/* ok if it's a receive */
104 		if (e->n->ntyp == ASGN
105 		&&  e->n->rgt->ntyp == CONST
106 		&&  e->n->rgt->val == 0)
107 			return 0;
108 		break;
109 	case 1:	/* must be able to use oval */
110 		if (e->n->ntyp != 'c'
111 		&&  e->n->ntyp != 'r')
112 			return 0;	/* can't really happen */
113 		break;
114 	}
115 	return 1;
116 }
117 
118 #if 0
119 static int howdeep = 0;
120 #endif
121 
122 static int
eligible(FSM_trans * v)123 eligible(FSM_trans *v)
124 {	Element	*el = ZE;
125 	Lextok	*lt = ZN;
126 
127 	if (v) el = v->step;
128 	if (el) lt = v->step->n;
129 
130 	if (!lt				/* dead end */
131 	||  v->nxt			/* has alternatives */
132 	||  el->esc			/* has an escape */
133 	||  (el->status&CHECK2)		/* remotely referenced */
134 	||  lt->ntyp == ATOMIC
135 	||  lt->ntyp == NON_ATOMIC	/* used for inlines -- should be able to handle this */
136 	||  lt->ntyp == IF
137 	||  lt->ntyp == C_CODE
138 	||  lt->ntyp == C_EXPR
139 	||  has_lab(el, 0)		/* any label at all */
140 	||  lt->ntyp == SET_P		/* to prevent multiple set_p merges */
141 
142 	||  lt->ntyp == DO
143 	||  lt->ntyp == UNLESS
144 	||  lt->ntyp == D_STEP
145 	||  lt->ntyp == ELSE
146 	||  lt->ntyp == '@'
147 	||  lt->ntyp == 'c'
148 	||  lt->ntyp == 'r'
149 	||  lt->ntyp == 's')
150 		return 0;
151 
152 	if (!(el->status&(2|4)))	/* not atomic */
153 	{	int unsafe = (el->status&I_GLOB)?1:has_global(el->n);
154 		if (unsafe)
155 			return 0;
156 	}
157 
158 	return 1;
159 }
160 
161 static int
canfill_in(FSM_trans * v)162 canfill_in(FSM_trans *v)
163 {	Element	*el = v->step;
164 	Lextok	*lt = v->step->n;
165 
166 	if (!lt				/* dead end */
167 	||  v->nxt			/* has alternatives */
168 	||  el->esc			/* has an escape */
169 	||  (el->status&CHECK2))	/* remotely referenced */
170 		return 0;
171 
172 	if (!(el->status&(2|4))		/* not atomic */
173 	&&  ((el->status&I_GLOB)
174 	||   has_global(el->n)))	/* and not safe */
175 		return 0;
176 
177 	return 1;
178 }
179 
180 static int
pushbuild(FSM_trans * v)181 pushbuild(FSM_trans *v)
182 {	BuildStack *b;
183 
184 	for (b = bs; b; b = b->nxt)
185 		if (b->t == v)
186 			return 0;
187 	if (bf)
188 	{	b = bf;
189 		bf = bf->nxt;
190 	} else
191 		b = (BuildStack *) emalloc(sizeof(BuildStack));
192 	b->t = v;
193 	b->nxt = bs;
194 	bs = b;
195 	return 1;
196 }
197 
198 static void
popbuild(void)199 popbuild(void)
200 {	BuildStack *f;
201 	if (!bs)
202 		fatal("cannot happen, popbuild", (char *) 0);
203 	f = bs;
204 	bs = bs->nxt;
205 	f->nxt = bf;
206 	bf = f;				/* freelist */
207 }
208 
209 static int
build_step(FSM_trans * v)210 build_step(FSM_trans *v)
211 {	FSM_state *f;
212 	Element	*el;
213 #if 0
214 	Lextok	*lt = ZN;
215 #endif
216 	int	st;
217 	int	r;
218 
219 	if (!v) return -1;
220 
221 	el = v->step;
222 	st = v->to;
223 
224 	if (!el) return -1;
225 
226 	if (v->step->merge)
227 		return v->step->merge;	/* already done */
228 
229 	if (!eligible(v))		/* non-blocking */
230 		return -1;
231 
232 	if (!pushbuild(v))		/* cycle detected */
233 		return -1;		/* break cycle */
234 
235 	f = fsm_tbl[st];
236 #if 0
237 	lt = v->step->n;
238 	if (verbose&32)
239 	{	if (++howdeep == 1)
240 			printf("spin: %s:%d, merge:\n", lt->fn->name, lt->ln);
241 		printf("\t[%d] <seqno %d>\t", howdeep, el->seqno);
242 		comment(stdout, lt, 0);
243 		printf(";\n");
244 	}
245 #endif
246 	r = build_step(f->t);
247 	v->step->merge = (r == -1) ? st : r;
248 #if 0
249 	if (verbose&32)
250 	{	printf("	merge value: %d (st=%d,r=%d, line %d)\n",
251 			v->step->merge, st, r, el->n->ln);
252 		howdeep--;
253 	}
254 #endif
255 	popbuild();
256 
257 	return v->step->merge;
258 }
259 
260 static void
FSM_MERGER(void)261 FSM_MERGER(/* char *pname */ void)	/* find candidates for safely merging steps */
262 {	FSM_state *f, *g;
263 	FSM_trans *t;
264 	Lextok	*lt;
265 
266 	for (f = fsmx; f; f = f->nxt)		/* all states */
267 	for (t = f->t; t; t = t->nxt)		/* all edges */
268 	{	if (!t->step) continue;		/* happens with 'unless' */
269 
270 		t->step->merge_in = f->in;	/* ?? */
271 
272 		if (t->step->merge)
273 			continue;
274 		lt = t->step->n;
275 
276 		if (lt->ntyp == 'c'
277 		||  lt->ntyp == 'r'
278 		||  lt->ntyp == 's')	/* blocking stmnts */
279 			continue;	/* handled in 2nd scan */
280 
281 		if (!eligible(t))
282 			continue;
283 
284 		g = fsm_tbl[t->to];
285 		if (!g || !eligible(g->t))
286 		{
287 #define SINGLES
288 #ifdef SINGLES
289 			t->step->merge_single = t->to;
290 #if 0
291 			if ((verbose&32))
292 			{	printf("spin: %s:%d, merge_single:\n\t<seqno %d>\t",
293 					t->step->n->fn->name,
294 					t->step->n->ln,
295 					t->step->seqno);
296 				comment(stdout, t->step->n, 0);
297 				printf(";\n");
298 			}
299 #endif
300 #endif
301 			/* t is an isolated eligible step:
302 			 *
303 			 * a merge_start can connect to a proper
304 			 * merge chain or to a merge_single
305 			 * a merge chain can be preceded by
306 			 * a merge_start, but not by a merge_single
307 			 */
308 
309 			continue;
310 		}
311 
312 		(void) build_step(t);
313 	}
314 
315 	/* 2nd scan -- find possible merge_starts */
316 
317 	for (f = fsmx; f; f = f->nxt)		/* all states */
318 	for (t = f->t; t; t = t->nxt)		/* all edges */
319 	{	if (!t->step || t->step->merge)
320 			continue;
321 
322 		lt = t->step->n;
323 #if 0
324 	4.1.3:
325 	an rv send operation ('s') inside an atomic, *loses* atomicity
326 	when executed, and should therefore never be merged with a subsequent
327 	statement within the atomic sequence
328 	the same is not true for non-rv send operations;
329 	6.2.2:
330 	RUN statements can start a new process at a higher priority level
331 	which interferes with statement merging, so it too is not a suitable
332 	merge target
333 #endif
334 
335 		if ((lt->ntyp == 'c' && !any_oper(lt->lft, RUN)) /* 2nd clause 6.2.2 */
336 		||  lt->ntyp == 'r'
337 		||  (lt->ntyp == 's' && u_sync == 0))	/* added !u_sync in 4.1.3 */
338 		{	if (!canfill_in(t))		/* atomic, non-global, etc. */
339 				continue;
340 
341 			g = fsm_tbl[t->to];
342 			if (!g || !g->t || !g->t->step)
343 				continue;
344 			if (g->t->step->merge)
345 				t->step->merge_start = g->t->step->merge;
346 #ifdef SINGLES
347 			else if (g->t->step->merge_single)
348 				t->step->merge_start = g->t->step->merge_single;
349 #endif
350 #if 0
351 			if ((verbose&32)
352 			&& t->step->merge_start)
353 			{	printf("spin: %s:%d, merge_START:\n\t<seqno %d>\t",
354 						lt->fn->name, lt->ln,
355 						t->step->seqno);
356 				comment(stdout, lt, 0);
357 				printf(";\n");
358 			}
359 #endif
360 		}
361 	}
362 }
363 
364 static void
FSM_ANA(void)365 FSM_ANA(void)
366 {	FSM_state *f;
367 	FSM_trans *t;
368 	FSM_use *u, *v, *w;
369 	int n;
370 
371 	for (f = fsmx; f; f = f->nxt)		/* all states */
372 	for (t = f->t; t; t = t->nxt)		/* all edges */
373 	for (n = 0; n < 2; n++)			/* reads and writes */
374 	for (u = t->Val[n]; u; u = u->nxt)
375 	{	if (!u->var->context	/* global */
376 		||   u->var->type == CHAN
377 		||   u->var->type == STRUCT)
378 			continue;
379 		new_dfs();
380 		if (FSM_DFS(t->to, u))	/* cannot hit read before hitting write */
381 			u->special = n+1;	/* means, reset to 0 after use */
382 	}
383 
384 	if (!export_ast)
385 	for (f = fsmx; f; f = f->nxt)
386 	for (t = f->t; t; t = t->nxt)
387 	for (n = 0; n < 2; n++)
388 	for (u = t->Val[n], w = (FSM_use *) 0; u; )
389 	{	if (u->special)
390 		{	v = u->nxt;
391 			if (!w)			/* remove from list */
392 				t->Val[n] = v;
393 			else
394 				w->nxt = v;
395 #if q
396 			if (verbose&32)
397 			{	printf("%s : %3d:  %d -> %d \t",
398 					t->step->n->fn->name,
399 					t->step->n->ln,
400 					f->from,
401 					t->to);
402 				comment(stdout, t->step->n, 0);
403 				printf("\t%c%d: %s\n", n==0?'R':'L',
404 					u->special, u->var->name);
405 			}
406 #endif
407 			if (good_dead(t->step, u))
408 			{	u->nxt = t->step->dead;	/* insert into dead */
409 				t->step->dead = u;
410 			}
411 			u = v;
412 		} else
413 		{	w = u;
414 			u = u->nxt;
415 	}	}
416 }
417 
418 void
rel_use(FSM_use * u)419 rel_use(FSM_use *u)
420 {
421 	if (!u) return;
422 	rel_use(u->nxt);
423 	u->var = (Symbol *) 0;
424 	u->special = 0;
425 	u->nxt = use_free;
426 	use_free = u;
427 }
428 
429 static void
rel_trans(FSM_trans * t)430 rel_trans(FSM_trans *t)
431 {
432 	if (!t) return;
433 	rel_trans(t->nxt);
434 	rel_use(t->Val[0]);
435 	rel_use(t->Val[1]);
436 	t->Val[0] = t->Val[1] = (FSM_use *) 0;
437 	t->nxt = trans_free;
438 	trans_free = t;
439 }
440 
441 static void
rel_state(FSM_state * f)442 rel_state(FSM_state *f)
443 {
444 	if (!f) return;
445 	rel_state(f->nxt);
446 	rel_trans(f->t);
447 	f->t = (FSM_trans *) 0;
448 	f->nxt = fsm_free;
449 	fsm_free = f;
450 }
451 
452 static void
FSM_DEL(void)453 FSM_DEL(void)
454 {
455 	rel_state(fsmx);
456 	fsmx = (FSM_state *) 0;
457 }
458 
459 static FSM_state *
mkstate(int s)460 mkstate(int s)
461 {	FSM_state *f;
462 
463 	/* fsm_tbl isn't allocated yet */
464 	for (f = fsmx; f; f = f->nxt)
465 		if (f->from == s)
466 			break;
467 	if (!f)
468 	{	if (fsm_free)
469 		{	f = fsm_free;
470 			memset(f, 0, sizeof(FSM_state));
471 			fsm_free = fsm_free->nxt;
472 		} else
473 			f = (FSM_state *) emalloc(sizeof(FSM_state));
474 		f->from = s;
475 		f->t = (FSM_trans *) 0;
476 		f->nxt = fsmx;
477 		fsmx = f;
478 		if (s > max_st_id)
479 			max_st_id = s;
480 	}
481 	return f;
482 }
483 
484 static FSM_trans *
get_trans(int to)485 get_trans(int to)
486 {	FSM_trans *t;
487 
488 	if (trans_free)
489 	{	t = trans_free;
490 		memset(t, 0, sizeof(FSM_trans));
491 		trans_free = trans_free->nxt;
492 	} else
493 		t = (FSM_trans *) emalloc(sizeof(FSM_trans));
494 
495 	t->to = to;
496 	return t;
497 }
498 
499 static void
FSM_EDGE(int from,int to,Element * e)500 FSM_EDGE(int from, int to, Element *e)
501 {	FSM_state *f;
502 	FSM_trans *t;
503 
504 	f = mkstate(from);	/* find it or else make it */
505 	t = get_trans(to);
506 
507 	t->step = e;
508 	t->nxt = f->t;
509 	f->t = t;
510 
511 	f = mkstate(to);
512 	f->in++;
513 
514 	if (export_ast)
515 	{	t = get_trans(from);
516 		t->step = e;
517 		t->nxt = f->p;	/* from is a predecessor of to */
518 		f->p = t;
519 	}
520 
521 	if (t->step)
522 	{	ana_stmnt(t, t->step->n, 0);
523 	}
524 }
525 
526 #define LVAL	1
527 #define RVAL	0
528 
529 static void
ana_var(FSM_trans * t,Lextok * now,int usage)530 ana_var(FSM_trans *t, Lextok *now, int usage)
531 {	FSM_use *u, *v;
532 
533 	if (!t || !now || !now->sym)
534 		return;
535 
536 	if (now->sym->name[0] == '_'
537 	&&  (strcmp(now->sym->name, "_") == 0
538 	||   strcmp(now->sym->name, "_pid") == 0
539 	||   strcmp(now->sym->name, "_priority") == 0
540 	||   strcmp(now->sym->name, "_last") == 0))
541 		return;
542 
543 	v = t->Val[usage];
544 	for (u = v; u; u = u->nxt)
545 		if (u->var == now->sym)
546 			return;	/* it's already there */
547 
548 	if (!now->lft)
549 	{	/* not for array vars -- it's hard to tell statically
550 		   if the index would, at runtime, evaluate to the
551 		   same values at lval and rval references
552 		*/
553 		if (use_free)
554 		{	u = use_free;
555 			use_free = use_free->nxt;
556 		} else
557 			u = (FSM_use *) emalloc(sizeof(FSM_use));
558 
559 		u->var = now->sym;
560 		u->nxt = t->Val[usage];
561 		t->Val[usage] = u;
562 	} else
563 		 ana_stmnt(t, now->lft, RVAL);	/* index */
564 
565 	if (now->sym->type == STRUCT
566 	&&  now->rgt
567 	&&  now->rgt->lft)
568 		ana_var(t, now->rgt->lft, usage);
569 }
570 
571 static void
ana_stmnt(FSM_trans * t,Lextok * now,int usage)572 ana_stmnt(FSM_trans *t, Lextok *now, int usage)
573 {	Lextok *v;
574 
575 	if (!t || !now) return;
576 
577 	switch (now->ntyp) {
578 	case '.':
579 	case BREAK:
580 	case GOTO:
581 	case CONST:
582 	case TIMEOUT:
583 	case NONPROGRESS:
584 	case  ELSE:
585 	case '@':
586 	case 'q':
587 	case IF:
588 	case DO:
589 	case ATOMIC:
590 	case NON_ATOMIC:
591 	case D_STEP:
592 	case C_CODE:
593 	case C_EXPR:
594 		break;
595 
596 	case ',': /* reached with SET_P and array initializers */
597 		if (now->lft && now->lft->rgt)
598 		{	ana_stmnt(t, now->lft->rgt, RVAL);
599 		}
600 		break;
601 
602 	case '!':
603 	case UMIN:
604 	case '~':
605 	case ENABLED:
606 	case GET_P:
607 	case PC_VAL:
608 	case LEN:
609 	case FULL:
610 	case EMPTY:
611 	case NFULL:
612 	case NEMPTY:
613 	case ASSERT:
614 	case 'c':
615 		ana_stmnt(t, now->lft, RVAL);
616 		break;
617 
618 	case SET_P:
619 		ana_stmnt(t, now->lft, RVAL); /* ',' */
620 		ana_stmnt(t, now->lft->rgt, RVAL);
621 		break;
622 
623 	case '/':
624 	case '*':
625 	case '-':
626 	case '+':
627 	case '%':
628 	case '&':
629 	case '^':
630 	case '|':
631 	case LT:
632 	case GT:
633 	case LE:
634 	case GE:
635 	case NE:
636 	case EQ:
637 	case OR:
638 	case AND:
639 	case LSHIFT:
640 	case RSHIFT:
641 		ana_stmnt(t, now->lft, RVAL);
642 		ana_stmnt(t, now->rgt, RVAL);
643 		break;
644 
645 	case ASGN:
646 		if (check_track(now) == STRUCT) { break; }
647 
648 		ana_stmnt(t, now->lft, LVAL);
649 		if (now->rgt->ntyp)
650 			ana_stmnt(t, now->rgt, RVAL);
651 		break;
652 
653 	case PRINT:
654 	case RUN:
655 		for (v = now->lft; v; v = v->rgt)
656 			ana_stmnt(t, v->lft, RVAL);
657 		break;
658 
659 	case PRINTM:
660 		if (now->lft && !now->lft->ismtyp)
661 			ana_stmnt(t, now->lft, RVAL);
662 		break;
663 
664 	case 's':
665 		ana_stmnt(t, now->lft, RVAL);
666 		for (v = now->rgt; v; v = v->rgt)
667 			ana_stmnt(t, v->lft, RVAL);
668 		break;
669 
670 	case 'R':
671 	case 'r':
672 		ana_stmnt(t, now->lft, RVAL);
673 		for (v = now->rgt; v; v = v->rgt)
674 		{	if (v->lft->ntyp == EVAL)
675 			{	if (v->lft->lft->ntyp == ',')
676 				{	ana_stmnt(t, v->lft->lft->lft, RVAL);
677 				} else
678 				{	ana_stmnt(t, v->lft->lft, RVAL);
679 				}
680 			} else
681 			{	if (v->lft->ntyp != CONST
682 				&&  now->ntyp != 'R')		/* was v->lft->ntyp */
683 				{	ana_stmnt(t, v->lft, LVAL);
684 		}	}	}
685 		break;
686 
687 	case '?':
688 		ana_stmnt(t, now->lft, RVAL);
689 		if (now->rgt)
690 		{	ana_stmnt(t, now->rgt->lft, RVAL);
691 			ana_stmnt(t, now->rgt->rgt, RVAL);
692 		}
693 		break;
694 
695 	case NAME:
696 		ana_var(t, now, usage);
697 		break;
698 
699 	case   'p':	/* remote ref */
700 		ana_stmnt(t, now->lft->lft, RVAL);	/* process id */
701 		ana_var(t, now, RVAL);
702 		ana_var(t, now->rgt, RVAL);
703 		break;
704 
705 	default:
706 		if (0) printf("spin: %s:%d, bad node type %d usage %d (ana_stmnt)\n",
707 			now->fn->name, now->ln, now->ntyp, usage);
708 		fatal("aborting (ana_stmnt)", (char *) 0);
709 	}
710 }
711 
712 void
ana_src(int dataflow,int merger)713 ana_src(int dataflow, int merger)	/* called from main.c and guided.c */
714 {	ProcList *p;
715 	Element *e;
716 #if 0
717 	int counter = 1;
718 #endif
719 	for (p = ready; p; p = p->nxt)
720 	{
721 		ana_seq(p->s);
722 		fsm_table();
723 
724 		e = p->s->frst;
725 #if 0
726 		if (dataflow || merger)
727 		{	printf("spin: %d, optimizing '%s'",
728 				counter++, p->n->name);
729 			fflush(stdout);
730 		}
731 #endif
732 		if (dataflow)
733 		{	FSM_ANA();
734 		}
735 		if (merger)
736 		{	FSM_MERGER(/* p->n->name */);
737 			huntele(e, e->status, -1)->merge_in = 1; /* start-state */
738 #if 0
739 			printf("\n");
740 #endif
741 		}
742 		if (export_ast)
743 			AST_store(p, huntele(e, e->status, -1)->seqno);
744 
745 		FSM_DEL();
746 	}
747 	for (e = Al_El; e; e = e->Nxt)
748 	{
749 		if (!(e->status&DONE) && (verbose&32))
750 		{	printf("unreachable code: ");
751 			printf("%s:%3d  ", e->n->fn->name, e->n->ln);
752 			comment(stdout, e->n, 0);
753 			printf("\n");
754 		}
755 		e->status &= ~DONE;
756 	}
757 	if (export_ast)
758 	{	AST_slice();
759 		alldone(0);	/* changed in 5.3.0: was exit(0) */
760 	}
761 }
762 
763 void
spit_recvs(FILE * f1,FILE * f2)764 spit_recvs(FILE *f1, FILE *f2)	/* called from pangen2.c */
765 {	Element *e;
766 	Sequence *s;
767 	extern int Unique;
768 
769 	fprintf(f1, "unsigned char Is_Recv[%d];\n", Unique);
770 
771 	fprintf(f2, "void\nset_recvs(void)\n{\n");
772 	for (e = Al_El; e; e = e->Nxt)
773 	{	if (!e->n) continue;
774 
775 		switch (e->n->ntyp) {
776 		case 'r':
777 markit:			fprintf(f2, "\tIs_Recv[%d] = 1;\n", e->Seqno);
778 			break;
779 		case D_STEP:
780 			s = e->n->sl->this;
781 			switch (s->frst->n->ntyp) {
782 			case DO:
783 				fatal("unexpected: do at start of d_step", (char *) 0);
784 			case IF: /* conservative: fall through */
785 			case 'r': goto markit;
786 			}
787 			break;
788 		}
789 	}
790 	fprintf(f2, "}\n");
791 
792 	if (rvopt)
793 	{
794 	fprintf(f2, "int\nno_recvs(int me)\n{\n");
795 	fprintf(f2, "	int h; uchar ot; short tt;\n");
796 	fprintf(f2, "	Trans *t;\n");
797 	fprintf(f2, "	for (h = BASE; h < (int) now._nr_pr; h++)\n");
798 	fprintf(f2, "	{	if (h == me) continue;\n");
799 	fprintf(f2, "		tt = (short) ((P0 *)pptr(h))->_p;\n");
800 	fprintf(f2, "		ot = (uchar) ((P0 *)pptr(h))->_t;\n");
801 	fprintf(f2, "		for (t = trans[ot][tt]; t; t = t->nxt)\n");
802 	fprintf(f2, "			if (Is_Recv[t->t_id]) return 0;\n");
803 	fprintf(f2, "	}\n");
804 	fprintf(f2, "	return 1;\n");
805 	fprintf(f2, "}\n");
806 	}
807 }
808 
809 static void
ana_seq(Sequence * s)810 ana_seq(Sequence *s)
811 {	SeqList *h;
812 	Sequence *t;
813 	Element *e, *g;
814 	int From, To;
815 
816 	for (e = s->frst; e; e = e->nxt)
817 	{	if (e->status & DONE)
818 			goto checklast;
819 
820 		e->status |= DONE;
821 
822 		From = e->seqno;
823 
824 		if (e->n->ntyp == UNLESS)
825 			ana_seq(e->sub->this);
826 		else if (e->sub)
827 		{	for (h = e->sub; h; h = h->nxt)
828 			{	g = huntstart(h->this->frst);
829 				To = g->seqno;
830 
831 				if (g->n->ntyp != 'c'
832 				||  g->n->lft->ntyp != CONST
833 				||  g->n->lft->val != 0
834 				||  g->esc)
835 					FSM_EDGE(From, To, e);
836 				/* else it's a dead link */
837 			}
838 			for (h = e->sub; h; h = h->nxt)
839 				ana_seq(h->this);
840 		} else if (e->n->ntyp == ATOMIC
841 			||  e->n->ntyp == D_STEP
842 			||  e->n->ntyp == NON_ATOMIC)
843 		{
844 			t = e->n->sl->this;
845 			g = huntstart(t->frst);
846 			t->last->nxt = e->nxt;
847 			To = g->seqno;
848 			FSM_EDGE(From, To, e);
849 
850 			ana_seq(t);
851 		} else
852 		{	if (e->n->ntyp == GOTO)
853 			{	g = get_lab(e->n, 1);
854 				g = huntele(g, e->status, -1);
855 				if (!g)
856 				{	fatal("unexpected error 2", (char *) 0);
857 				}
858 				To = g->seqno;
859 			} else if (e->nxt)
860 			{	g = huntele(e->nxt, e->status, -1);
861 				if (!g)
862 				{	fatal("unexpected error 3", (char *) 0);
863 				}
864 				To = g->seqno;
865 			} else
866 				To = 0;
867 
868 			FSM_EDGE(From, To, e);
869 
870 			if (e->esc
871 			&&  e->n->ntyp != GOTO
872 			&&  e->n->ntyp != '.')
873 			for (h = e->esc; h; h = h->nxt)
874 			{	g = huntstart(h->this->frst);
875 				To = g->seqno;
876 				FSM_EDGE(From, To, ZE);
877 				ana_seq(h->this);
878 			}
879 		}
880 
881 checklast:	if (e == s->last)
882 			break;
883 	}
884 }
885