1 /***** spin: flow.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 extern Symbol *Fname;
13 extern int nr_errs, lineno, verbose, in_for, old_scope_rules, s_trail;
14 extern short has_unless, has_badelse, has_xu;
15 extern char CurScope[MAXSCOPESZ];
16
17 Element *Al_El = ZE;
18 Label *labtab = (Label *) 0;
19 int Unique = 0, Elcnt = 0, DstepStart = -1;
20 int initialization_ok = 1;
21 short has_accept;
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
open_seq(int top)37 open_seq(int top)
38 { SeqList *t;
39 Sequence *s = (Sequence *) emalloc(sizeof(Sequence));
40 s->minel = -1;
41
42 t = seqlist(s, cur_s);
43 cur_s = t;
44 if (top)
45 { Elcnt = 1;
46 initialization_ok = 1;
47 } else
48 { initialization_ok = 0;
49 }
50 }
51
52 void
rem_Seq(void)53 rem_Seq(void)
54 {
55 DstepStart = Unique;
56 }
57
58 void
unrem_Seq(void)59 unrem_Seq(void)
60 {
61 DstepStart = -1;
62 }
63
64 static int
Rjumpslocal(Element * q,Element * stop)65 Rjumpslocal(Element *q, Element *stop)
66 { Element *lb, *f;
67 SeqList *h;
68
69 /* allow no jumps out of a d_step sequence */
70 for (f = q; f && f != stop; f = f->nxt)
71 { if (f && f->n && f->n->ntyp == GOTO)
72 { lb = get_lab(f->n, 0);
73 if (!lb || lb->Seqno < DstepStart)
74 { lineno = f->n->ln;
75 Fname = f->n->fn;
76 return 0;
77 } }
78 for (h = f->sub; h; h = h->nxt)
79 { if (!Rjumpslocal(h->this->frst, h->this->last))
80 return 0;
81
82 } }
83 return 1;
84 }
85
86 void
cross_dsteps(Lextok * a,Lextok * b)87 cross_dsteps(Lextok *a, Lextok *b)
88 {
89 if (a && b
90 && a->indstep != b->indstep)
91 { lineno = a->ln;
92 Fname = a->fn;
93 if (!s_trail)
94 fatal("jump into d_step sequence", (char *) 0);
95 }
96 }
97
98 int
is_skip(Lextok * n)99 is_skip(Lextok *n)
100 {
101 return (n->ntyp == PRINT
102 || n->ntyp == PRINTM
103 || (n->ntyp == 'c'
104 && n->lft
105 && n->lft->ntyp == CONST
106 && n->lft->val == 1));
107 }
108
109 void
check_sequence(Sequence * s)110 check_sequence(Sequence *s)
111 { Element *e, *le = ZE;
112 Lextok *n;
113 int cnt = 0;
114
115 for (e = s->frst; e; le = e, e = e->nxt)
116 { n = e->n;
117 if (is_skip(n) && !has_lab(e, 0))
118 { cnt++;
119 if (cnt > 1
120 && n->ntyp != PRINT
121 && n->ntyp != PRINTM)
122 { if (verbose&32)
123 printf("spin: %s:%d, redundant skip\n",
124 n->fn->name, n->ln);
125 if (e != s->frst
126 && e != s->last
127 && e != s->extent)
128 { e->status |= DONE; /* not unreachable */
129 le->nxt = e->nxt; /* remove it */
130 e = le;
131 }
132 }
133 } else
134 cnt = 0;
135 }
136 }
137
138 void
prune_opts(Lextok * n)139 prune_opts(Lextok *n)
140 { SeqList *l;
141 extern Symbol *context;
142 extern char *claimproc;
143
144 if (!n
145 || (context && claimproc && strcmp(context->name, claimproc) == 0))
146 return;
147
148 for (l = n->sl; l; l = l->nxt) /* find sequences of unlabeled skips */
149 check_sequence(l->this);
150 }
151
152 Sequence *
close_seq(int nottop)153 close_seq(int nottop)
154 { Sequence *s = cur_s->this;
155 Symbol *z;
156
157 if (nottop == 0) /* end of proctype body */
158 { initialization_ok = 1;
159 }
160
161 if (nottop > 0 && s->frst && (z = has_lab(s->frst, 0)))
162 { printf("error: (%s:%d) label %s placed incorrectly\n",
163 (s->frst->n)?s->frst->n->fn->name:"-",
164 (s->frst->n)?s->frst->n->ln:0,
165 z->name);
166 switch (nottop) {
167 case 1:
168 printf("=====> stmnt unless Label: stmnt\n");
169 printf("sorry, cannot jump to the guard of an\n");
170 printf("escape (it is not a unique state)\n");
171 break;
172 case 2:
173 printf("=====> instead of ");
174 printf("\"Label: stmnt unless stmnt\"\n");
175 printf("=====> always use ");
176 printf("\"Label: { stmnt unless stmnt }\"\n");
177 break;
178 case 3:
179 printf("=====> instead of ");
180 printf("\"atomic { Label: statement ... }\"\n");
181 printf("=====> always use ");
182 printf("\"Label: atomic { statement ... }\"\n");
183 break;
184 case 4:
185 printf("=====> instead of ");
186 printf("\"d_step { Label: statement ... }\"\n");
187 printf("=====> always use ");
188 printf("\"Label: d_step { statement ... }\"\n");
189 break;
190 case 5:
191 printf("=====> instead of ");
192 printf("\"{ Label: statement ... }\"\n");
193 printf("=====> always use ");
194 printf("\"Label: { statement ... }\"\n");
195 break;
196 case 6:
197 printf("=====> instead of\n");
198 printf(" do (or if)\n");
199 printf(" :: ...\n");
200 printf(" :: Label: statement\n");
201 printf(" od (of fi)\n");
202 printf("=====> use\n");
203 printf("Label: do (or if)\n");
204 printf(" :: ...\n");
205 printf(" :: statement\n");
206 printf(" od (or fi)\n");
207 break;
208 case 7:
209 printf("cannot happen - labels\n");
210 break;
211 }
212 if (nottop != 6)
213 { alldone(1);
214 } }
215
216 if (nottop == 4
217 && !Rjumpslocal(s->frst, s->last))
218 fatal("non_local jump in d_step sequence", (char *) 0);
219
220 cur_s = cur_s->nxt;
221 s->maxel = Elcnt;
222 s->extent = s->last;
223 if (!s->last)
224 fatal("sequence must have at least one statement", (char *) 0);
225 return s;
226 }
227
228 Lextok *
do_unless(Lextok * No,Lextok * Es)229 do_unless(Lextok *No, Lextok *Es)
230 { SeqList *Sl;
231 Lextok *Re = nn(ZN, UNLESS, ZN, ZN);
232
233 Re->ln = No->ln;
234 Re->fn = No->fn;
235 has_unless++;
236
237 if (Es->ntyp == NON_ATOMIC)
238 { Sl = Es->sl;
239 } else
240 { open_seq(0); add_seq(Es);
241 Sl = seqlist(close_seq(1), 0);
242 }
243
244 if (No->ntyp == NON_ATOMIC)
245 { No->sl->nxt = Sl;
246 Sl = No->sl;
247 } else if (No->ntyp == ':'
248 && (No->lft->ntyp == NON_ATOMIC
249 || No->lft->ntyp == ATOMIC
250 || No->lft->ntyp == D_STEP))
251 {
252 int tok = No->lft->ntyp;
253
254 No->lft->sl->nxt = Sl;
255 Re->sl = No->lft->sl;
256
257 open_seq(0); add_seq(Re);
258 Re = nn(ZN, tok, ZN, ZN);
259 Re->sl = seqlist(close_seq(7), 0);
260 Re->ln = No->ln;
261 Re->fn = No->fn;
262
263 Re = nn(No, ':', Re, ZN); /* lift label */
264 Re->ln = No->ln;
265 Re->fn = No->fn;
266 return Re;
267 } else
268 { open_seq(0); add_seq(No);
269 Sl = seqlist(close_seq(2), Sl);
270 }
271
272 Re->sl = Sl;
273 return Re;
274 }
275
276 SeqList *
seqlist(Sequence * s,SeqList * r)277 seqlist(Sequence *s, SeqList *r)
278 { SeqList *t = (SeqList *) emalloc(sizeof(SeqList));
279
280 t->this = s;
281 t->nxt = r;
282 return t;
283 }
284
285 static Element *
new_el(Lextok * n)286 new_el(Lextok *n)
287 { Element *m;
288
289 if (n)
290 { if (n->ntyp == IF || n->ntyp == DO)
291 return if_seq(n);
292 if (n->ntyp == UNLESS)
293 return unless_seq(n);
294 }
295 m = (Element *) emalloc(sizeof(Element));
296 m->n = n;
297 m->seqno = Elcnt++;
298 m->Seqno = Unique++;
299 m->Nxt = Al_El; Al_El = m;
300 return m;
301 }
302
303 static int
has_chanref(Lextok * n)304 has_chanref(Lextok *n)
305 {
306 if (!n) return 0;
307
308 switch (n->ntyp) {
309 case 's': case 'r':
310 #if 0
311 case 'R': case LEN:
312 #endif
313 case FULL: case NFULL:
314 case EMPTY: case NEMPTY:
315 return 1;
316 default:
317 break;
318 }
319 if (has_chanref(n->lft))
320 return 1;
321
322 return has_chanref(n->rgt);
323 }
324
325 void
loose_ends(void)326 loose_ends(void) /* properly tie-up ends of sub-sequences */
327 { Element *e, *f;
328
329 for (e = Al_El; e; e = e->Nxt)
330 { if (!e->n
331 || !e->nxt)
332 continue;
333 switch (e->n->ntyp) {
334 case ATOMIC:
335 case NON_ATOMIC:
336 case D_STEP:
337 f = e->nxt;
338 while (f && f->n->ntyp == '.')
339 f = f->nxt;
340 if (0) printf("link %d, {%d .. %d} -> %d (ntyp=%d) was %d\n",
341 e->seqno,
342 e->n->sl->this->frst->seqno,
343 e->n->sl->this->last->seqno,
344 f?f->seqno:-1, f?f->n->ntyp:-1,
345 e->n->sl->this->last->nxt?e->n->sl->this->last->nxt->seqno:-1);
346 if (!e->n->sl->this->last->nxt)
347 e->n->sl->this->last->nxt = f;
348 else
349 { if (e->n->sl->this->last->nxt->n->ntyp != GOTO)
350 { if (!f || e->n->sl->this->last->nxt->seqno != f->seqno)
351 non_fatal("unexpected: loose ends", (char *)0);
352 } else
353 e->n->sl->this->last = e->n->sl->this->last->nxt;
354 /*
355 * fix_dest can push a goto into the nxt position
356 * in that case the goto wins and f is not needed
357 * but the last fields needs adjusting
358 */
359 }
360 break;
361 } }
362 }
363
364 void
popbreak(void)365 popbreak(void)
366 {
367 if (!breakstack)
368 fatal("cannot happen, breakstack", (char *) 0);
369
370 breakstack = breakstack->nxt; /* pop stack */
371 }
372
373 static Lbreak *ob = (Lbreak *) 0;
374
375 void
safe_break(void)376 safe_break(void)
377 {
378 ob = breakstack;
379 popbreak();
380 }
381
382 void
restore_break(void)383 restore_break(void)
384 {
385 breakstack = ob;
386 ob = (Lbreak *) 0;
387 }
388
389 static Element *
if_seq(Lextok * n)390 if_seq(Lextok *n)
391 { int tok = n->ntyp;
392 SeqList *s = n->sl;
393 Element *e = new_el(ZN);
394 Element *t = new_el(nn(ZN,'.',ZN,ZN)); /* target */
395 SeqList *z, *prev_z = (SeqList *) 0;
396 SeqList *move_else = (SeqList *) 0; /* to end of optionlist */
397 int ref_chans = 0;
398
399 for (z = s; z; z = z->nxt)
400 { if (!z->this->frst)
401 continue;
402 if (z->this->frst->n->ntyp == ELSE)
403 { if (move_else)
404 fatal("duplicate `else'", (char *) 0);
405 if (z->nxt) /* is not already at the end */
406 { move_else = z;
407 if (prev_z)
408 prev_z->nxt = z->nxt;
409 else
410 s = n->sl = z->nxt;
411 continue;
412 }
413 } else
414 ref_chans |= has_chanref(z->this->frst->n);
415 prev_z = z;
416 }
417 if (move_else)
418 { move_else->nxt = (SeqList *) 0;
419 /* if there is no prev, then else was at the end */
420 if (!prev_z) fatal("cannot happen - if_seq", (char *) 0);
421 prev_z->nxt = move_else;
422 prev_z = move_else;
423 }
424 if (prev_z
425 && ref_chans
426 && prev_z->this->frst->n->ntyp == ELSE)
427 { prev_z->this->frst->n->val = 1;
428 has_badelse++;
429 if (has_xu)
430 { fatal("invalid use of 'else' combined with i/o and xr/xs assertions,",
431 (char *)0);
432 } else
433 { non_fatal("dubious use of 'else' combined with i/o,",
434 (char *)0);
435 }
436 nr_errs--;
437 }
438
439 e->n = nn(n, tok, ZN, ZN);
440 e->n->sl = s; /* preserve as info only */
441 e->sub = s;
442 for (z = s; z; z = z->nxt)
443 add_el(t, z->this); /* append target */
444 if (tok == DO)
445 { add_el(t, cur_s->this); /* target upfront */
446 t = new_el(nn(n, BREAK, ZN, ZN)); /* break target */
447 set_lab(break_dest(), t); /* new exit */
448 popbreak();
449 }
450 add_el(e, cur_s->this);
451 add_el(t, cur_s->this);
452 return e; /* destination node for label */
453 }
454
455 static void
escape_el(Element * f,Sequence * e)456 escape_el(Element *f, Sequence *e)
457 { SeqList *z;
458
459 for (z = f->esc; z; z = z->nxt)
460 if (z->this == e)
461 return; /* already there */
462
463 /* cover the lower-level escapes of this state */
464 for (z = f->esc; z; z = z->nxt)
465 attach_escape(z->this, e);
466
467 /* now attach escape to the state itself */
468
469 f->esc = seqlist(e, f->esc); /* in lifo order... */
470 #ifdef DEBUG
471 printf("attach %d (", e->frst->Seqno);
472 comment(stdout, e->frst->n, 0);
473 printf(") to %d (", f->Seqno);
474 comment(stdout, f->n, 0);
475 printf(")\n");
476 #endif
477 switch (f->n->ntyp) {
478 case UNLESS:
479 attach_escape(f->sub->this, e);
480 break;
481 case IF:
482 case DO:
483 for (z = f->sub; z; z = z->nxt)
484 attach_escape(z->this, e);
485 break;
486 case D_STEP:
487 /* attach only to the guard stmnt */
488 escape_el(f->n->sl->this->frst, e);
489 break;
490 case ATOMIC:
491 case NON_ATOMIC:
492 /* attach to all stmnts */
493 attach_escape(f->n->sl->this, e);
494 break;
495 }
496 }
497
498 static void
attach_escape(Sequence * n,Sequence * e)499 attach_escape(Sequence *n, Sequence *e)
500 { Element *f;
501
502 for (f = n->frst; f; f = f->nxt)
503 { escape_el(f, e);
504 if (f == n->extent)
505 break;
506 }
507 }
508
509 static Element *
unless_seq(Lextok * n)510 unless_seq(Lextok *n)
511 { SeqList *s = n->sl;
512 Element *e = new_el(ZN);
513 Element *t = new_el(nn(ZN,'.',ZN,ZN)); /* target */
514 SeqList *z;
515
516 e->n = nn(n, UNLESS, ZN, ZN);
517 e->n->sl = s; /* info only */
518 e->sub = s;
519
520 /* need 2 sequences: normal execution and escape */
521 if (!s || !s->nxt || s->nxt->nxt)
522 fatal("unexpected unless structure", (char *)0);
523
524 /* append the target state to both */
525 for (z = s; z; z = z->nxt)
526 add_el(t, z->this);
527
528 /* attach escapes to all states in normal sequence */
529 attach_escape(s->this, s->nxt->this);
530
531 add_el(e, cur_s->this);
532 add_el(t, cur_s->this);
533 #ifdef DEBUG
534 printf("unless element (%d,%d):\n", e->Seqno, t->Seqno);
535 for (z = s; z; z = z->nxt)
536 { Element *x; printf("\t%d,%d,%d :: ",
537 z->this->frst->Seqno,
538 z->this->extent->Seqno,
539 z->this->last->Seqno);
540 for (x = z->this->frst; x; x = x->nxt)
541 printf("(%d)", x->Seqno);
542 printf("\n");
543 }
544 #endif
545 return e;
546 }
547
548 Element *
mk_skip(void)549 mk_skip(void)
550 { Lextok *t = nn(ZN, CONST, ZN, ZN);
551 t->val = 1;
552 return new_el(nn(ZN, 'c', t, ZN));
553 }
554
555 static void
add_el(Element * e,Sequence * s)556 add_el(Element *e, Sequence *s)
557 {
558 if (e->n->ntyp == GOTO)
559 { Symbol *z = has_lab(e, (1|2|4));
560 if (z)
561 { Element *y; /* insert a skip */
562 y = mk_skip();
563 mov_lab(z, e, y); /* inherit label */
564 add_el(y, s);
565 } }
566 #ifdef DEBUG
567 printf("add_el %d after %d -- ",
568 e->Seqno, (s->last)?s->last->Seqno:-1);
569 comment(stdout, e->n, 0);
570 printf("\n");
571 #endif
572 if (!s->frst)
573 s->frst = e;
574 else
575 s->last->nxt = e;
576 s->last = e;
577 }
578
579 static Element *
colons(Lextok * n)580 colons(Lextok *n)
581 {
582 if (!n)
583 return ZE;
584 if (n->ntyp == ':')
585 { Element *e = colons(n->lft);
586 set_lab(n->sym, e);
587 return e;
588 }
589 innermost = n;
590 return new_el(n);
591 }
592
593 void
add_seq(Lextok * n)594 add_seq(Lextok *n)
595 { Element *e;
596
597 if (!n) return;
598 innermost = n;
599 e = colons(n);
600 if (innermost->ntyp != IF
601 && innermost->ntyp != DO
602 && innermost->ntyp != UNLESS)
603 add_el(e, cur_s->this);
604 }
605
606 void
set_lab(Symbol * s,Element * e)607 set_lab(Symbol *s, Element *e)
608 { Label *l; extern Symbol *context;
609 int cur_uiid = is_inline();
610
611 if (!s) return;
612
613 for (l = labtab; l; l = l->nxt)
614 { if (strcmp(l->s->name, s->name) == 0
615 && l->c == context
616 && (old_scope_rules || strcmp((const char *) s->bscp, (const char *) l->s->bscp) == 0)
617 && l->uiid == cur_uiid)
618 { non_fatal("label %s redeclared", s->name);
619 break;
620 } }
621
622 if (strncmp(s->name, "accept", 6) == 0
623 && strncmp(s->name, "accept_all", 10) != 0)
624 { has_accept = 1;
625 }
626
627 l = (Label *) emalloc(sizeof(Label));
628 l->s = s;
629 l->c = context;
630 l->e = e;
631 l->uiid = cur_uiid;
632 l->nxt = labtab;
633 labtab = l;
634 }
635
636 static Label *
get_labspec(Lextok * n)637 get_labspec(Lextok *n)
638 { Symbol *s = n->sym;
639 Label *l, *anymatch = (Label *) 0;
640 int ln;
641 /*
642 * try to find a label with the same inline id (uiid)
643 * but if it doesn't exist, return any other match
644 * within the same scope
645 */
646 for (l = labtab; l; l = l->nxt)
647 { if (strcmp(l->s->name, s->name) == 0 /* labelname matches */
648 && s->context == l->s->context) /* same scope */
649 {
650 #if 0
651 if (anymatch && n->uiid == anymatch->uiid)
652 { if (0) non_fatal("label %s re-declared", s->name);
653 }
654 if (0)
655 { printf("Label %s uiid now::then %d :: %d bcsp %s :: %s\n",
656 s->name, n->uiid, l->uiid, s->bscp, l->s->bscp);
657 printf("get_labspec match on %s %s (bscp goto %s - label %s)\n",
658 s->name, s->context->name, s->bscp, l->s->bscp);
659 }
660 #endif
661 /* same block scope */
662 if (strcmp((const char *) s->bscp, (const char *) l->s->bscp) == 0)
663 { return l; /* definite match */
664 }
665 /* higher block scope */
666 ln = strlen((const char *) l->s->bscp);
667 if (strncmp((const char *) s->bscp, (const char *) l->s->bscp, ln) == 0)
668 { anymatch = l; /* possible match */
669 } else if (!anymatch)
670 { anymatch = l; /* somewhere else in same context */
671 } } }
672
673 return anymatch; /* return best match */
674 }
675
676 Element *
get_lab(Lextok * n,int md)677 get_lab(Lextok *n, int md)
678 { Label *l = get_labspec(n);
679
680 if (l != (Label *) 0)
681 { return (l->e);
682 }
683
684 if (md)
685 { lineno = n->ln;
686 Fname = n->fn;
687 fatal("undefined label %s", n->sym->name);
688 }
689 return ZE;
690 }
691
692 Symbol *
has_lab(Element * e,int special)693 has_lab(Element *e, int special)
694 { Label *l;
695
696 for (l = labtab; l; l = l->nxt)
697 { if (e != l->e)
698 continue;
699 if (special == 0
700 || ((special&1) && !strncmp(l->s->name, "accept", 6))
701 || ((special&2) && !strncmp(l->s->name, "end", 3))
702 || ((special&4) && !strncmp(l->s->name, "progress", 8)))
703 return (l->s);
704 }
705 return ZS;
706 }
707
708 static void
mov_lab(Symbol * z,Element * e,Element * y)709 mov_lab(Symbol *z, Element *e, Element *y)
710 { Label *l;
711
712 for (l = labtab; l; l = l->nxt)
713 if (e == l->e)
714 { l->e = y;
715 return;
716 }
717 if (e->n)
718 { lineno = e->n->ln;
719 Fname = e->n->fn;
720 }
721 fatal("cannot happen - mov_lab %s", z->name);
722 }
723
724 void
fix_dest(Symbol * c,Symbol * a)725 fix_dest(Symbol *c, Symbol *a) /* c:label name, a:proctype name */
726 { Label *l; extern Symbol *context;
727
728 #if 0
729 printf("ref to label '%s' in proctype '%s', search:\n",
730 c->name, a->name);
731 for (l = labtab; l; l = l->nxt)
732 printf(" %s in %s\n", l->s->name, l->c->name);
733 #endif
734
735 for (l = labtab; l; l = l->nxt)
736 { if (strcmp(c->name, l->s->name) == 0
737 && strcmp(a->name, l->c->name) == 0) /* ? */
738 break;
739 }
740 if (!l)
741 { printf("spin: label '%s' (proctype %s)\n", c->name, a->name);
742 non_fatal("unknown label '%s'", c->name);
743 if (context == a)
744 printf("spin: cannot remote ref a label inside the same proctype\n");
745 return;
746 }
747 if (!l->e || !l->e->n)
748 fatal("fix_dest error (%s)", c->name);
749 if (l->e->n->ntyp == GOTO)
750 { Element *y = (Element *) emalloc(sizeof(Element));
751 int keep_ln = l->e->n->ln;
752 Symbol *keep_fn = l->e->n->fn;
753
754 /* insert skip - or target is optimized away */
755 y->n = l->e->n; /* copy of the goto */
756 y->seqno = find_maxel(a); /* unique seqno within proc */
757 y->nxt = l->e->nxt;
758 y->Seqno = Unique++; y->Nxt = Al_El; Al_El = y;
759
760 /* turn the original element+seqno into a skip */
761 l->e->n = nn(ZN, 'c', nn(ZN, CONST, ZN, ZN), ZN);
762 l->e->n->ln = l->e->n->lft->ln = keep_ln;
763 l->e->n->fn = l->e->n->lft->fn = keep_fn;
764 l->e->n->lft->val = 1;
765 l->e->nxt = y; /* append the goto */
766 }
767 l->e->status |= CHECK2; /* treat as if global */
768 if (l->e->status & (ATOM | L_ATOM | D_ATOM))
769 { printf("spin: %s:%d, warning, reference to label ",
770 Fname->name, lineno);
771 printf("from inside atomic or d_step (%s)\n", c->name);
772 }
773 }
774
775 int
find_lab(Symbol * s,Symbol * c,int markit)776 find_lab(Symbol *s, Symbol *c, int markit)
777 { Label *l, *pm = (Label *) 0, *apm = (Label *) 0;
778 int ln;
779
780 /* generally called for remote references in never claims */
781 for (l = labtab; l; l = l->nxt)
782 {
783 if (strcmp(s->name, l->s->name) == 0
784 && strcmp(c->name, l->c->name) == 0)
785 { ln = strlen((const char *) l->s->bscp);
786 if (0)
787 { printf("want '%s' in context '%s', scope ref '%s' - label '%s'\n",
788 s->name, c->name, s->bscp, l->s->bscp);
789 }
790 /* same or higher block scope */
791 if (strcmp((const char *) s->bscp, (const char *) l->s->bscp) == 0)
792 { pm = l; /* definite match */
793 break;
794 }
795 if (strncmp((const char *) s->bscp, (const char *) l->s->bscp, ln) == 0)
796 { pm = l; /* possible match */
797 } else
798 { apm = l; /* remote */
799 } } }
800
801 if (pm)
802 { pm->visible |= markit;
803 return pm->e->seqno;
804 }
805 if (apm)
806 { apm->visible |= markit;
807 return apm->e->seqno;
808 } /* else printf("Not Found\n"); */
809 return 0;
810 }
811
812 void
pushbreak(void)813 pushbreak(void)
814 { Lbreak *r = (Lbreak *) emalloc(sizeof(Lbreak));
815 Symbol *l;
816 char buf[64];
817
818 sprintf(buf, ":b%d", break_id++);
819 l = lookup(buf);
820 r->l = l;
821 r->nxt = breakstack;
822 breakstack = r;
823 }
824
825 Symbol *
break_dest(void)826 break_dest(void)
827 {
828 if (!breakstack)
829 fatal("misplaced break statement", (char *)0);
830 return breakstack->l;
831 }
832
833 void
make_atomic(Sequence * s,int added)834 make_atomic(Sequence *s, int added)
835 { Element *f;
836
837 walk_atomic(s->frst, s->last, added);
838
839 f = s->last;
840 switch (f->n->ntyp) { /* is last step basic stmnt or sequence ? */
841 case NON_ATOMIC:
842 case ATOMIC:
843 /* redo and search for the last step of that sequence */
844 make_atomic(f->n->sl->this, added);
845 break;
846
847 case UNLESS:
848 /* escapes are folded into main sequence */
849 make_atomic(f->sub->this, added);
850 break;
851
852 default:
853 f->status &= ~ATOM;
854 f->status |= L_ATOM;
855 break;
856 }
857 }
858
859 #if 0
860 static int depth = 0;
861 void dump_sym(Symbol *, char *);
862
863 void
864 dump_lex(Lextok *t, char *s)
865 { int i;
866
867 depth++;
868 printf(s);
869 for (i = 0; i < depth; i++)
870 printf("\t");
871 explain(t->ntyp);
872 if (t->ntyp == NAME) printf(" %s ", t->sym->name);
873 if (t->ntyp == CONST) printf(" %d ", t->val);
874 if (t->ntyp == STRUCT)
875 { dump_sym(t->sym, "\n:Z:");
876 }
877 if (t->lft)
878 { dump_lex(t->lft, "\nL");
879 }
880 if (t->rgt)
881 { dump_lex(t->rgt, "\nR");
882 }
883 depth--;
884 }
885 void
886 dump_sym(Symbol *z, char *s)
887 { int i;
888 char txt[64];
889 depth++;
890 printf(s);
891 for (i = 0; i < depth; i++)
892 printf("\t");
893
894 if (z->type == CHAN)
895 { if (z->ini && z->ini->rgt && z->ini->rgt->sym)
896 { /* dump_sym(z->ini->rgt->sym, "\n:I:"); -- could also be longer list */
897 if (z->ini->rgt->rgt
898 || !z->ini->rgt->sym)
899 fatal("chan %s in for should have only one field (a typedef)", z->name);
900 printf(" -- %s %p -- ", z->ini->rgt->sym->name, z->ini->rgt->sym);
901 }
902 } else if (z->type == STRUCT)
903 { if (z->Snm)
904 printf(" == %s %p == ", z->Snm->name, z->Snm);
905 else
906 { if (z->Slst)
907 dump_lex(z->Slst, "\n:X:");
908 if (z->ini)
909 dump_lex(z->ini, "\n:I:");
910 }
911 }
912 depth--;
913
914 }
915 #endif
916
917 int
match_struct(Symbol * s,Symbol * t)918 match_struct(Symbol *s, Symbol *t)
919 {
920 if (!t
921 || !t->ini
922 || !t->ini->rgt
923 || !t->ini->rgt->sym
924 || t->ini->rgt->rgt)
925 { fatal("chan %s in for should have only one field (a typedef)", t?t->name:"--");
926 }
927 /* we already know that s is a STRUCT */
928 if (0)
929 { printf("index type %s %p ==\n", s->Snm->name, (void *) s->Snm);
930 printf("chan type %s %p --\n\n", t->ini->rgt->sym->name, (void *) t->ini->rgt->sym);
931 }
932
933 return (s->Snm == t->ini->rgt->sym);
934 }
935
936 void
valid_name(Lextok * a3,Lextok * a5,Lextok * a8,char * tp)937 valid_name(Lextok *a3, Lextok *a5, Lextok *a8, char *tp)
938 {
939 if (a3->ntyp != NAME)
940 { fatal("%s ( .name : from .. to ) { ... }", tp);
941 }
942 if (a3->sym->type == CHAN
943 || a3->sym->type == STRUCT
944 || a3->sym->isarray != 0)
945 { fatal("bad index in for-construct %s", a3->sym->name);
946 }
947 if (a5->ntyp == CONST && a8->ntyp == CONST && a5->val > a8->val)
948 { non_fatal("start value for %s exceeds end-value", a3->sym->name);
949 }
950 }
951
952 void
for_setup(Lextok * a3,Lextok * a5,Lextok * a8)953 for_setup(Lextok *a3, Lextok *a5, Lextok *a8)
954 { /* for ( a3 : a5 .. a8 ) */
955
956 valid_name(a3, a5, a8, "for");
957 /* a5->ntyp = a8->ntyp = CONST; */
958 add_seq(nn(a3, ASGN, a3, a5)); /* start value */
959 open_seq(0);
960 add_seq(nn(ZN, 'c', nn(a3, LE, a3, a8), ZN)); /* condition */
961 }
962
963 Lextok *
for_index(Lextok * a3,Lextok * a5)964 for_index(Lextok *a3, Lextok *a5)
965 { Lextok *z0, *z1, *z2, *z3;
966 Symbol *tmp_cnt;
967 char tmp_nm[MAXSCOPESZ+16];
968 /* for ( a3 in a5 ) { ... } */
969
970 if (a3->ntyp != NAME)
971 { fatal("for ( .name in name ) { ... }", (char *) 0);
972 }
973
974 if (a5->ntyp != NAME)
975 { fatal("for ( %s in .name ) { ... }", a3->sym->name);
976 }
977
978 if (a3->sym->type == STRUCT)
979 { if (a5->sym->type != CHAN)
980 { fatal("for ( %s in .channel_name ) { ... }",
981 a3->sym->name);
982 }
983 z0 = a5->sym->ini;
984 if (!z0
985 || z0->val <= 0
986 || z0->rgt->ntyp != STRUCT
987 || z0->rgt->rgt != NULL)
988 { fatal("bad channel type %s in for", a5->sym->name);
989 }
990
991 if (!match_struct(a3->sym, a5->sym))
992 { fatal("type of %s does not match chan", a3->sym->name);
993 }
994
995 z1 = nn(ZN, CONST, ZN, ZN); z1->val = 0;
996 z2 = nn(a5, LEN, a5, ZN);
997
998 sprintf(tmp_nm, "_f0r_t3mp%s", CurScope); /* make sure it's unique */
999 tmp_cnt = lookup(tmp_nm);
1000 if (z0->val > 255) /* check nr of slots, i.e. max length */
1001 { tmp_cnt->type = SHORT; /* should be rare */
1002 } else
1003 { tmp_cnt->type = BYTE;
1004 }
1005 z3 = nn(ZN, NAME, ZN, ZN);
1006 z3->sym = tmp_cnt;
1007
1008 add_seq(nn(z3, ASGN, z3, z1)); /* start value 0 */
1009
1010 open_seq(0);
1011
1012 add_seq(nn(ZN, 'c', nn(z3, LT, z3, z2), ZN)); /* condition */
1013
1014 /* retrieve message from the right slot -- for now: rotate contents */
1015 in_for = 0;
1016 add_seq(nn(a5, 'r', a5, expand(a3, 1))); /* receive */
1017 add_seq(nn(a5, 's', a5, expand(a3, 1))); /* put back in to rotate */
1018 in_for = 1;
1019 return z3;
1020 } else
1021 { if (a5->sym->isarray == 0
1022 || a5->sym->nel <= 0)
1023 { fatal("bad arrayname %s", a5->sym->name);
1024 }
1025 z1 = nn(ZN, CONST, ZN, ZN); z1->val = 0;
1026 z2 = nn(ZN, CONST, ZN, ZN); z2->val = a5->sym->nel - 1;
1027 for_setup(a3, z1, z2);
1028 return a3;
1029 }
1030 }
1031
1032 Lextok *
for_body(Lextok * a3,int with_else)1033 for_body(Lextok *a3, int with_else)
1034 { Lextok *t1, *t2, *t0, *rv;
1035
1036 rv = nn(ZN, CONST, ZN, ZN); rv->val = 1;
1037 rv = nn(ZN, '+', a3, rv);
1038 rv = nn(a3, ASGN, a3, rv);
1039 add_seq(rv); /* initial increment */
1040
1041 /* completed loop body, main sequence */
1042 t1 = nn(ZN, 0, ZN, ZN);
1043 t1->sq = close_seq(8);
1044
1045 open_seq(0); /* add else -> break sequence */
1046 if (with_else)
1047 { add_seq(nn(ZN, ELSE, ZN, ZN));
1048 }
1049 t2 = nn(ZN, GOTO, ZN, ZN);
1050 t2->sym = break_dest();
1051 add_seq(t2);
1052 t2 = nn(ZN, 0, ZN, ZN);
1053 t2->sq = close_seq(9);
1054
1055 t0 = nn(ZN, 0, ZN, ZN);
1056 t0->sl = seqlist(t2->sq, seqlist(t1->sq, 0));
1057
1058 rv = nn(ZN, DO, ZN, ZN);
1059 rv->sl = t0->sl;
1060
1061 return rv;
1062 }
1063
1064 Lextok *
sel_index(Lextok * a3,Lextok * a5,Lextok * a7)1065 sel_index(Lextok *a3, Lextok *a5, Lextok *a7)
1066 { /* select ( a3 : a5 .. a7 ) */
1067
1068 valid_name(a3, a5, a7, "select");
1069 /* a5->ntyp = a7->ntyp = CONST; */
1070
1071 add_seq(nn(a3, ASGN, a3, a5)); /* start value */
1072 open_seq(0);
1073 add_seq(nn(ZN, 'c', nn(a3, LT, a3, a7), ZN)); /* condition */
1074
1075 pushbreak(); /* new 6.2.1 */
1076 return for_body(a3, 0); /* no else, just a non-deterministic break */
1077 }
1078
1079 static void
walk_atomic(Element * a,Element * b,int added)1080 walk_atomic(Element *a, Element *b, int added)
1081 { Element *f; Symbol *ofn; int oln;
1082 SeqList *h;
1083
1084 ofn = Fname;
1085 oln = lineno;
1086 for (f = a; ; f = f->nxt)
1087 { f->status |= (ATOM|added);
1088 switch (f->n->ntyp) {
1089 case ATOMIC:
1090 if (verbose&32)
1091 printf("spin: %s:%d, warning, atomic inside %s (ignored)\n",
1092 f->n->fn->name, f->n->ln, (added)?"d_step":"atomic");
1093 goto mknonat;
1094 case D_STEP:
1095 if (!(verbose&32))
1096 { if (added) goto mknonat;
1097 break;
1098 }
1099 printf("spin: %s:%d, warning, d_step inside ",
1100 f->n->fn->name, f->n->ln);
1101 if (added)
1102 { printf("d_step (ignored)\n");
1103 goto mknonat;
1104 }
1105 printf("atomic\n");
1106 break;
1107 case NON_ATOMIC:
1108 mknonat: f->n->ntyp = NON_ATOMIC; /* can jump here */
1109 h = f->n->sl;
1110 walk_atomic(h->this->frst, h->this->last, added);
1111 break;
1112 case UNLESS:
1113 if (added)
1114 { printf("spin: error, %s:%d, unless in d_step (ignored)\n",
1115 f->n->fn->name, f->n->ln);
1116 }
1117 }
1118 for (h = f->sub; h; h = h->nxt)
1119 walk_atomic(h->this->frst, h->this->last, added);
1120 if (f == b)
1121 break;
1122 }
1123 Fname = ofn;
1124 lineno = oln;
1125 }
1126
1127 void
dumplabels(void)1128 dumplabels(void)
1129 { Label *l;
1130
1131 for (l = labtab; l; l = l->nxt)
1132 if (l->c != 0 && l->s->name[0] != ':')
1133 { printf("label %s %d ",
1134 l->s->name, l->e->seqno);
1135 if (l->uiid == 0)
1136 printf("<%s>", l->c->name);
1137 else
1138 printf("<%s i%d>", l->c->name, l->uiid);
1139 if (!old_scope_rules)
1140 { printf("\t{scope %s}", l->s->bscp);
1141 }
1142 printf("\n");
1143 }
1144 }
1145