xref: /plan9/sys/src/cmd/spin/flow.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
1 /***** spin: flow.c *****/
2 
3 /* Copyright (c) 1989-2003 by Lucent Technologies, Bell Laboratories.     */
4 /* All Rights Reserved.  This software is for educational purposes only.  */
5 /* No guarantee whatsoever is expressed or implied by the distribution of */
6 /* this code.  Permission is given to distribute this code provided that  */
7 /* this introductory message is not removed and no monies are exchanged.  */
8 /* Software written by Gerard J. Holzmann.  For tool documentation see:   */
9 /*             http://spinroot.com/                                       */
10 /* Send all bug-reports and/or questions to: bugs@spinroot.com            */
11 
12 #include "spin.h"
13 #include "y.tab.h"
14 
15 extern Symbol	*Fname;
16 extern int	nr_errs, lineno, verbose;
17 extern short	has_unless, has_badelse;
18 
19 Element *Al_El = ZE;
20 Label	*labtab = (Label *) 0;
21 int	Unique=0, Elcnt=0, DstepStart = -1;
22 
23 static Lbreak	*breakstack = (Lbreak *) 0;
24 static Lextok	*innermost;
25 static SeqList	*cur_s = (SeqList *) 0;
26 static int	break_id=0;
27 
28 static Element	*if_seq(Lextok *);
29 static Element	*new_el(Lextok *);
30 static Element	*unless_seq(Lextok *);
31 static void	add_el(Element *, Sequence *);
32 static void	attach_escape(Sequence *, Sequence *);
33 static void	mov_lab(Symbol *, Element *, Element *);
34 static void	walk_atomic(Element *, Element *, int);
35 
36 void
37 open_seq(int top)
38 {	SeqList *t;
39 	Sequence *s = (Sequence *) emalloc(sizeof(Sequence));
40 
41 	t = seqlist(s, cur_s);
42 	cur_s = t;
43 	if (top) Elcnt = 1;
44 }
45 
46 void
47 rem_Seq(void)
48 {
49 	DstepStart = Unique;
50 }
51 
52 void
53 unrem_Seq(void)
54 {
55 	DstepStart = -1;
56 }
57 
58 static int
59 Rjumpslocal(Element *q, Element *stop)
60 {	Element *lb, *f;
61 	SeqList *h;
62 
63 	/* allow no jumps out of a d_step sequence */
64 	for (f = q; f && f != stop; f = f->nxt)
65 	{	if (f && f->n && f->n->ntyp == GOTO)
66 		{	lb = get_lab(f->n, 0);
67 			if (!lb || lb->Seqno < DstepStart)
68 			{	lineno = f->n->ln;
69 				Fname = f->n->fn;
70 				return 0;
71 		}	}
72 		for (h = f->sub; h; h = h->nxt)
73 		{	if (!Rjumpslocal(h->this->frst, h->this->last))
74 				return 0;
75 
76 	}	}
77 	return 1;
78 }
79 
80 void
81 cross_dsteps(Lextok *a, Lextok *b)
82 {
83 	if (a && b
84 	&&  a->indstep != b->indstep)
85 	{	lineno = a->ln;
86 		Fname  = a->fn;
87 		fatal("jump into d_step sequence", (char *) 0);
88 	}
89 }
90 
91 int
92 is_skip(Lextok *n)
93 {
94 	return (n->ntyp == PRINT
95 	||	n->ntyp == PRINTM
96 	||	(n->ntyp == 'c'
97 		&& n->lft
98 		&& n->lft->ntyp == CONST
99 		&& n->lft->val  == 1));
100 }
101 
102 void
103 check_sequence(Sequence *s)
104 {	Element *e, *le = ZE;
105 	Lextok *n;
106 	int cnt = 0;
107 
108 	for (e = s->frst; e; le = e, e = e->nxt)
109 	{	n = e->n;
110 		if (is_skip(n) && !has_lab(e, 0))
111 		{	cnt++;
112 			if (cnt > 1
113 			&&  n->ntyp != PRINT
114 			&&  n->ntyp != PRINTM)
115 			{	if (verbose&32)
116 					printf("spin: line %d %s, redundant skip\n",
117 						n->ln, n->fn->name);
118 				if (e != s->frst
119 				&&  e != s->last
120 				&&  e != s->extent)
121 				{	e->status |= DONE;	/* not unreachable */
122 					le->nxt = e->nxt;	/* remove it */
123 					e = le;
124 				}
125 			}
126 		} else
127 			cnt = 0;
128 	}
129 }
130 
131 void
132 prune_opts(Lextok *n)
133 {	SeqList *l;
134 	extern Symbol *context;
135 	extern char *claimproc;
136 
137 	if (!n
138 	|| (context && claimproc && strcmp(context->name, claimproc) == 0))
139 		return;
140 
141 	for (l = n->sl; l; l = l->nxt)	/* find sequences of unlabeled skips */
142 		check_sequence(l->this);
143 }
144 
145 Sequence *
146 close_seq(int nottop)
147 {	Sequence *s = cur_s->this;
148 	Symbol *z;
149 
150 	if (nottop > 0 && (z = has_lab(s->frst, 0)))
151 	{	printf("error: (%s:%d) label %s placed incorrectly\n",
152 			(s->frst->n)?s->frst->n->fn->name:"-",
153 			(s->frst->n)?s->frst->n->ln:0,
154 			z->name);
155 		switch (nottop) {
156 		case 1:
157 			printf("=====> stmnt unless Label: stmnt\n");
158 			printf("sorry, cannot jump to the guard of an\n");
159 			printf("escape (it is not a unique state)\n");
160 			break;
161 		case 2:
162 			printf("=====> instead of  ");
163 			printf("\"Label: stmnt unless stmnt\"\n");
164 			printf("=====> always use  ");
165 			printf("\"Label: { stmnt unless stmnt }\"\n");
166 			break;
167 		case 3:
168 			printf("=====> instead of  ");
169 			printf("\"atomic { Label: statement ... }\"\n");
170 			printf("=====> always use  ");
171 			printf("\"Label: atomic { statement ... }\"\n");
172 			break;
173 		case 4:
174 			printf("=====> instead of  ");
175 			printf("\"d_step { Label: statement ... }\"\n");
176 			printf("=====> always use  ");
177 			printf("\"Label: d_step { statement ... }\"\n");
178 			break;
179 		case 5:
180 			printf("=====> instead of  ");
181 			printf("\"{ Label: statement ... }\"\n");
182 			printf("=====> always use  ");
183 			printf("\"Label: { statement ... }\"\n");
184 			break;
185 		case 6:
186 			printf("=====>instead of\n");
187 			printf("	do (or if)\n");
188 			printf("	:: ...\n");
189 			printf("	:: Label: statement\n");
190 			printf("	od (of fi)\n");
191 			printf("=====>always use\n");
192 			printf("Label:	do (or if)\n");
193 			printf("	:: ...\n");
194 			printf("	:: statement\n");
195 			printf("	od (or fi)\n");
196 			break;
197 		case 7:
198 			printf("cannot happen - labels\n");
199 			break;
200 		}
201 		alldone(1);
202 	}
203 
204 	if (nottop == 4
205 	&& !Rjumpslocal(s->frst, s->last))
206 		fatal("non_local jump in d_step sequence", (char *) 0);
207 
208 	cur_s = cur_s->nxt;
209 	s->maxel = Elcnt;
210 	s->extent = s->last;
211 	if (!s->last)
212 		fatal("sequence must have at least one statement", (char *) 0);
213 	return s;
214 }
215 
216 Lextok *
217 do_unless(Lextok *No, Lextok *Es)
218 {	SeqList *Sl;
219 	Lextok *Re = nn(ZN, UNLESS, ZN, ZN);
220 	Re->ln = No->ln;
221 	Re->fn = No->fn;
222 
223 	has_unless++;
224 	if (Es->ntyp == NON_ATOMIC)
225 		Sl = Es->sl;
226 	else
227 	{	open_seq(0); add_seq(Es);
228 		Sl = seqlist(close_seq(1), 0);
229 	}
230 
231 	if (No->ntyp == NON_ATOMIC)
232 	{	No->sl->nxt = Sl;
233 		Sl = No->sl;
234 	} else	if (No->ntyp == ':'
235 		&& (No->lft->ntyp == NON_ATOMIC
236 		||  No->lft->ntyp == ATOMIC
237 		||  No->lft->ntyp == D_STEP))
238 	{
239 		int tok = No->lft->ntyp;
240 
241 		No->lft->sl->nxt = Sl;
242 		Re->sl = No->lft->sl;
243 
244 		open_seq(0); add_seq(Re);
245 		Re = nn(ZN, tok, ZN, ZN);
246 		Re->sl = seqlist(close_seq(7), 0);
247 		Re->ln = No->ln;
248 		Re->fn = No->fn;
249 
250 		Re = nn(No, ':', Re, ZN);	/* lift label */
251 		Re->ln = No->ln;
252 		Re->fn = No->fn;
253 		return Re;
254 	} else
255 	{	open_seq(0); add_seq(No);
256 		Sl = seqlist(close_seq(2), Sl);
257 	}
258 
259 	Re->sl = Sl;
260 	return Re;
261 }
262 
263 SeqList *
264 seqlist(Sequence *s, SeqList *r)
265 {	SeqList *t = (SeqList *) emalloc(sizeof(SeqList));
266 
267 	t->this = s;
268 	t->nxt = r;
269 	return t;
270 }
271 
272 static Element *
273 new_el(Lextok *n)
274 {	Element *m;
275 
276 	if (n)
277 	{	if (n->ntyp == IF || n->ntyp == DO)
278 			return if_seq(n);
279 		if (n->ntyp == UNLESS)
280 			return unless_seq(n);
281 	}
282 	m = (Element *) emalloc(sizeof(Element));
283 	m->n = n;
284 	m->seqno = Elcnt++;
285 	m->Seqno = Unique++;
286 	m->Nxt = Al_El; Al_El = m;
287 	return m;
288 }
289 
290 static int
291 has_chanref(Lextok *n)
292 {
293 	if (!n) return 0;
294 
295 	switch (n->ntyp) {
296 	case 's':	case 'r':
297 #if 0
298 	case 'R':	case LEN:
299 #endif
300 	case FULL:	case NFULL:
301 	case EMPTY:	case NEMPTY:
302 		return 1;
303 	default:
304 		break;
305 	}
306 	if (has_chanref(n->lft))
307 		return 1;
308 
309 	return has_chanref(n->rgt);
310 }
311 
312 void
313 loose_ends(void)	/* properly tie-up ends of sub-sequences */
314 {	Element *e, *f;
315 
316 	for (e = Al_El; e; e = e->Nxt)
317 	{	if (!e->n
318 		||  !e->nxt)
319 			continue;
320 		switch (e->n->ntyp) {
321 		case ATOMIC:
322 		case NON_ATOMIC:
323 		case D_STEP:
324 			f = e->nxt;
325 			while (f && f->n->ntyp == '.')
326 				f = f->nxt;
327 			if (0) printf("link %d, {%d .. %d} -> %d (ntyp=%d) was %d\n",
328 				e->seqno,
329 				e->n->sl->this->frst->seqno,
330 				e->n->sl->this->last->seqno,
331 				f?f->seqno:-1, f?f->n->ntyp:-1,
332 				e->n->sl->this->last->nxt?e->n->sl->this->last->nxt->seqno:-1);
333 			if (!e->n->sl->this->last->nxt)
334 				e->n->sl->this->last->nxt = f;
335 			else
336 			{	if (e->n->sl->this->last->nxt->n->ntyp != GOTO)
337 				{	if (!f || e->n->sl->this->last->nxt->seqno != f->seqno)
338 					non_fatal("unexpected: loose ends", (char *)0);
339 				} else
340 					e->n->sl->this->last = e->n->sl->this->last->nxt;
341 				/*
342 				 * fix_dest can push a goto into the nxt position
343 				 * in that case the goto wins and f is not needed
344 				 * but the last fields needs adjusting
345 				 */
346 			}
347 			break;
348 	}	}
349 }
350 
351 static Element *
352 if_seq(Lextok *n)
353 {	int	tok = n->ntyp;
354 	SeqList	*s  = n->sl;
355 	Element	*e  = new_el(ZN);
356 	Element	*t  = new_el(nn(ZN,'.',ZN,ZN)); /* target */
357 	SeqList	*z, *prev_z = (SeqList *) 0;
358 	SeqList *move_else  = (SeqList *) 0;	/* to end of optionlist */
359 	int	ref_chans = 0;
360 
361 	for (z = s; z; z = z->nxt)
362 	{	if (!z->this->frst)
363 			continue;
364 		if (z->this->frst->n->ntyp == ELSE)
365 		{	if (move_else)
366 				fatal("duplicate `else'", (char *) 0);
367 			if (z->nxt)	/* is not already at the end */
368 			{	move_else = z;
369 				if (prev_z)
370 					prev_z->nxt = z->nxt;
371 				else
372 					s = n->sl = z->nxt;
373 				continue;
374 			}
375 		} else
376 			ref_chans |= has_chanref(z->this->frst->n);
377 		prev_z = z;
378 	}
379 	if (move_else)
380 	{	move_else->nxt = (SeqList *) 0;
381 		/* if there is no prev, then else was at the end */
382 		if (!prev_z) fatal("cannot happen - if_seq", (char *) 0);
383 		prev_z->nxt = move_else;
384 		prev_z = move_else;
385 	}
386 	if (prev_z
387 	&&  ref_chans
388 	&&  prev_z->this->frst->n->ntyp == ELSE)
389 	{	prev_z->this->frst->n->val = 1;
390 		has_badelse++;
391 		non_fatal("dubious use of 'else' combined with i/o,",
392 			(char *)0);
393 		nr_errs--;
394 	}
395 
396 	e->n = nn(n, tok, ZN, ZN);
397 	e->n->sl = s;			/* preserve as info only */
398 	e->sub = s;
399 	for (z = s; z; prev_z = z, z = z->nxt)
400 		add_el(t, z->this);	/* append target */
401 	if (tok == DO)
402 	{	add_el(t, cur_s->this); /* target upfront */
403 		t = new_el(nn(n, BREAK, ZN, ZN)); /* break target */
404 		set_lab(break_dest(), t);	/* new exit  */
405 		breakstack = breakstack->nxt;	/* pop stack */
406 	}
407 	add_el(e, cur_s->this);
408 	add_el(t, cur_s->this);
409 	return e;			/* destination node for label */
410 }
411 
412 static void
413 escape_el(Element *f, Sequence *e)
414 {	SeqList *z;
415 
416 	for (z = f->esc; z; z = z->nxt)
417 		if (z->this == e)
418 			return;	/* already there */
419 
420 	/* cover the lower-level escapes of this state */
421 	for (z = f->esc; z; z = z->nxt)
422 		attach_escape(z->this, e);
423 
424 	/* now attach escape to the state itself */
425 
426 	f->esc = seqlist(e, f->esc);	/* in lifo order... */
427 #ifdef DEBUG
428 	printf("attach %d (", e->frst->Seqno);
429 	comment(stdout, e->frst->n, 0);
430 	printf(")	to %d (", f->Seqno);
431 	comment(stdout, f->n, 0);
432 	printf(")\n");
433 #endif
434 	switch (f->n->ntyp) {
435 	case UNLESS:
436 		attach_escape(f->sub->this, e);
437 		break;
438 	case IF:
439 	case DO:
440 		for (z = f->sub; z; z = z->nxt)
441 			attach_escape(z->this, e);
442 		break;
443 	case D_STEP:
444 		/* attach only to the guard stmnt */
445 		escape_el(f->n->sl->this->frst, e);
446 		break;
447 	case ATOMIC:
448 	case NON_ATOMIC:
449 		/* attach to all stmnts */
450 		attach_escape(f->n->sl->this, e);
451 		break;
452 	}
453 }
454 
455 static void
456 attach_escape(Sequence *n, Sequence *e)
457 {	Element *f;
458 
459 	for (f = n->frst; f; f = f->nxt)
460 	{	escape_el(f, e);
461 		if (f == n->extent)
462 			break;
463 	}
464 }
465 
466 static Element *
467 unless_seq(Lextok *n)
468 {	SeqList	*s  = n->sl;
469 	Element	*e  = new_el(ZN);
470 	Element	*t  = new_el(nn(ZN,'.',ZN,ZN)); /* target */
471 	SeqList	*z;
472 
473 	e->n = nn(n, UNLESS, ZN, ZN);
474 	e->n->sl = s;			/* info only */
475 	e->sub = s;
476 
477 	/* need 2 sequences: normal execution and escape */
478 	if (!s || !s->nxt || s->nxt->nxt)
479 		fatal("unexpected unless structure", (char *)0);
480 
481 	/* append the target state to both */
482 	for (z = s; z; z = z->nxt)
483 		add_el(t, z->this);
484 
485 	/* attach escapes to all states in normal sequence */
486 	attach_escape(s->this, s->nxt->this);
487 
488 	add_el(e, cur_s->this);
489 	add_el(t, cur_s->this);
490 #ifdef DEBUG
491 	printf("unless element (%d,%d):\n", e->Seqno, t->Seqno);
492 	for (z = s; z; z = z->nxt)
493 	{	Element *x; printf("\t%d,%d,%d :: ",
494 		z->this->frst->Seqno,
495 		z->this->extent->Seqno,
496 		z->this->last->Seqno);
497 		for (x = z->this->frst; x; x = x->nxt)
498 			printf("(%d)", x->Seqno);
499 		printf("\n");
500 	}
501 #endif
502 	return e;
503 }
504 
505 Element *
506 mk_skip(void)
507 {	Lextok  *t = nn(ZN, CONST, ZN, ZN);
508 	t->val = 1;
509 	return new_el(nn(ZN, 'c', t, ZN));
510 }
511 
512 static void
513 add_el(Element *e, Sequence *s)
514 {
515 	if (e->n->ntyp == GOTO)
516 	{	Symbol *z = has_lab(e, (1|2|4));
517 		if (z)
518 		{	Element *y; /* insert a skip */
519 			y = mk_skip();
520 			mov_lab(z, e, y); /* inherit label */
521 			add_el(y, s);
522 	}	}
523 #ifdef DEBUG
524 	printf("add_el %d after %d -- ",
525 	e->Seqno, (s->last)?s->last->Seqno:-1);
526 	comment(stdout, e->n, 0);
527 	printf("\n");
528 #endif
529 	if (!s->frst)
530 		s->frst = e;
531 	else
532 		s->last->nxt = e;
533 	s->last = e;
534 }
535 
536 static Element *
537 colons(Lextok *n)
538 {
539 	if (!n)
540 		return ZE;
541 	if (n->ntyp == ':')
542 	{	Element *e = colons(n->lft);
543 		set_lab(n->sym, e);
544 		return e;
545 	}
546 	innermost = n;
547 	return new_el(n);
548 }
549 
550 void
551 add_seq(Lextok *n)
552 {	Element *e;
553 
554 	if (!n) return;
555 	innermost = n;
556 	e = colons(n);
557 	if (innermost->ntyp != IF
558 	&&  innermost->ntyp != DO
559 	&&  innermost->ntyp != UNLESS)
560 		add_el(e, cur_s->this);
561 }
562 
563 void
564 set_lab(Symbol *s, Element *e)
565 {	Label *l; extern Symbol *context;
566 
567 	if (!s) return;
568 	for (l = labtab; l; l = l->nxt)
569 		if (l->s == s && l->c == context)
570 		{	non_fatal("label %s redeclared", s->name);
571 			break;
572 		}
573 	l = (Label *) emalloc(sizeof(Label));
574 	l->s = s;
575 	l->c = context;
576 	l->e = e;
577 	l->nxt = labtab;
578 	labtab = l;
579 }
580 
581 Element *
582 get_lab(Lextok *n, int md)
583 {	Label *l;
584 	Symbol *s = n->sym;
585 
586 	for (l = labtab; l; l = l->nxt)
587 		if (s == l->s)
588 			return (l->e);
589 
590 	lineno = n->ln;
591 	Fname = n->fn;
592 	if (md) fatal("undefined label %s", s->name);
593 	return ZE;
594 }
595 
596 Symbol *
597 has_lab(Element *e, int special)
598 {	Label *l;
599 
600 	for (l = labtab; l; l = l->nxt)
601 	{	if (e != l->e)
602 			continue;
603 		if (special == 0
604 		||  ((special&1) && !strncmp(l->s->name, "accept", 6))
605 		||  ((special&2) && !strncmp(l->s->name, "end", 3))
606 		||  ((special&4) && !strncmp(l->s->name, "progress", 8)))
607 			return (l->s);
608 	}
609 	return ZS;
610 }
611 
612 static void
613 mov_lab(Symbol *z, Element *e, Element *y)
614 {	Label *l;
615 
616 	for (l = labtab; l; l = l->nxt)
617 		if (e == l->e)
618 		{	l->e = y;
619 			return;
620 		}
621 	if (e->n)
622 	{	lineno = e->n->ln;
623 		Fname  = e->n->fn;
624 	}
625 	fatal("cannot happen - mov_lab %s", z->name);
626 }
627 
628 void
629 fix_dest(Symbol *c, Symbol *a)		/* c:label name, a:proctype name */
630 {	Label *l; extern Symbol *context;
631 
632 #if 0
633 	printf("ref to label '%s' in proctype '%s', search:\n",
634 		c->name, a->name);
635 	for (l = labtab; l; l = l->nxt)
636 		printf("	%s in	%s\n", l->s->name, l->c->name);
637 #endif
638 
639 	for (l = labtab; l; l = l->nxt)
640 	{	if (strcmp(c->name, l->s->name) == 0
641 		&&  strcmp(a->name, l->c->name) == 0)	/* ? */
642 			break;
643 	}
644 	if (!l)
645 	{	printf("spin: label '%s' (proctype %s)\n", c->name, a->name);
646 		non_fatal("unknown label '%s'", c->name);
647 		if (context == a)
648 		printf("spin: cannot remote ref a label inside the same proctype\n");
649 		return;
650 	}
651 	if (!l->e || !l->e->n)
652 		fatal("fix_dest error (%s)", c->name);
653 	if (l->e->n->ntyp == GOTO)
654 	{	Element	*y = (Element *) emalloc(sizeof(Element));
655 		int	keep_ln = l->e->n->ln;
656 		Symbol	*keep_fn = l->e->n->fn;
657 
658 		/* insert skip - or target is optimized away */
659 		y->n = l->e->n;		  /* copy of the goto   */
660 		y->seqno = find_maxel(a); /* unique seqno within proc */
661 		y->nxt = l->e->nxt;
662 		y->Seqno = Unique++; y->Nxt = Al_El; Al_El = y;
663 
664 		/* turn the original element+seqno into a skip */
665 		l->e->n = nn(ZN, 'c', nn(ZN, CONST, ZN, ZN), ZN);
666 		l->e->n->ln = l->e->n->lft->ln = keep_ln;
667 		l->e->n->fn = l->e->n->lft->fn = keep_fn;
668 		l->e->n->lft->val = 1;
669 		l->e->nxt = y;		/* append the goto  */
670 	}
671 	l->e->status |= CHECK2;	/* treat as if global */
672 	if (l->e->status & (ATOM | L_ATOM | D_ATOM))
673 	{	non_fatal("cannot reference label inside atomic or d_step (%s)",
674 			c->name);
675 	}
676 }
677 
678 int
679 find_lab(Symbol *s, Symbol *c, int markit)
680 {	Label *l;
681 
682 	for (l = labtab; l; l = l->nxt)
683 	{	if (strcmp(s->name, l->s->name) == 0
684 		&&  strcmp(c->name, l->c->name) == 0)
685 		{	l->visible |= markit;
686 			return (l->e->seqno);
687 	}	}
688 	return 0;
689 }
690 
691 void
692 pushbreak(void)
693 {	Lbreak *r = (Lbreak *) emalloc(sizeof(Lbreak));
694 	Symbol *l;
695 	char buf[64];
696 
697 	sprintf(buf, ":b%d", break_id++);
698 	l = lookup(buf);
699 	r->l = l;
700 	r->nxt = breakstack;
701 	breakstack = r;
702 }
703 
704 Symbol *
705 break_dest(void)
706 {
707 	if (!breakstack)
708 		fatal("misplaced break statement", (char *)0);
709 	return breakstack->l;
710 }
711 
712 void
713 make_atomic(Sequence *s, int added)
714 {	Element *f;
715 
716 	walk_atomic(s->frst, s->last, added);
717 
718 	f = s->last;
719 	switch (f->n->ntyp) {	/* is last step basic stmnt or sequence ? */
720 	case NON_ATOMIC:
721 	case ATOMIC:
722 		/* redo and search for the last step of that sequence */
723 		make_atomic(f->n->sl->this, added);
724 		break;
725 
726 	case UNLESS:
727 		/* escapes are folded into main sequence */
728 		make_atomic(f->sub->this, added);
729 		break;
730 
731 	default:
732 		f->status &= ~ATOM;
733 		f->status |= L_ATOM;
734 		break;
735 	}
736 }
737 
738 static void
739 walk_atomic(Element *a, Element *b, int added)
740 {	Element *f; Symbol *ofn; int oln;
741 	SeqList *h;
742 
743 	ofn = Fname;
744 	oln = lineno;
745 	for (f = a; ; f = f->nxt)
746 	{	f->status |= (ATOM|added);
747 		switch (f->n->ntyp) {
748 		case ATOMIC:
749 			if (verbose&32)
750 			  printf("spin: warning, line %3d %s, atomic inside %s (ignored)\n",
751 			  f->n->ln, f->n->fn->name, (added)?"d_step":"atomic");
752 			goto mknonat;
753 		case D_STEP:
754 			if (!(verbose&32))
755 			{	if (added) goto mknonat;
756 				break;
757 			}
758 			printf("spin: warning, line %3d %s, d_step inside ",
759 			 f->n->ln, f->n->fn->name);
760 			if (added)
761 			{	printf("d_step (ignored)\n");
762 				goto mknonat;
763 			}
764 			printf("atomic\n");
765 			break;
766 		case NON_ATOMIC:
767 mknonat:		f->n->ntyp = NON_ATOMIC; /* can jump here */
768 			h = f->n->sl;
769 			walk_atomic(h->this->frst, h->this->last, added);
770 			break;
771 		case UNLESS:
772 			if (added)
773 			{ printf("spin: error, line %3d %s, unless in d_step (ignored)\n",
774 			 	 f->n->ln, f->n->fn->name);
775 			}
776 		}
777 		for (h = f->sub; h; h = h->nxt)
778 			walk_atomic(h->this->frst, h->this->last, added);
779 		if (f == b)
780 			break;
781 	}
782 	Fname = ofn;
783 	lineno = oln;
784 }
785 
786 void
787 dumplabels(void)
788 {	Label *l;
789 
790 	for (l = labtab; l; l = l->nxt)
791 		if (l->c != 0 && l->s->name[0] != ':')
792 		printf("label	%s	%d	<%s>\n",
793 		l->s->name, l->e->seqno, l->c->name);
794 }
795