1 /***** spin: pangen5.c *****/
3 /* Copyright (c) 1999-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 */
15 typedef struct BuildStack {
17 struct BuildStack *nxt;
21 extern int verbose, eventmapnr, claimnr, rvopt, export_ast, u_sync;
22 extern Element *Al_El;
24 static FSM_state *fsm_free;
25 static FSM_trans *trans_free;
26 static BuildStack *bs, *bf;
34 static void ana_seq(Sequence *);
35 static void ana_stmnt(FSM_trans *, Lextok *, int);
37 extern void AST_slice(void);
38 extern void AST_store(ProcList *, int);
39 extern int has_global(Lextok *);
40 extern void exit(int);
46 /* fprintf(stderr, "omax %d, max=%d\n", o_max, max_st_id); */
47 if (o_max < max_st_id)
49 fsm_tbl = (FSM_state **) emalloc(max_st_id * sizeof(FSM_state *));
51 memset((char *)fsm_tbl, 0, max_st_id * sizeof(FSM_state *));
52 cur_st_id = max_st_id;
55 for (f = fsm; f; f = f->nxt)
60 FSM_DFS(int from, FSM_use *u)
72 { printf("cannot find state %d\n", from);
73 fatal("fsm_dfs: cannot happen\n", (char *) 0);
80 for (t = f->t; t; t = t->nxt)
82 for (n = 0; n < 2; n++)
83 for (v = t->Val[n]; v; v = v->nxt)
85 return n; /* a read or write */
87 if (!FSM_DFS(t->to, u))
97 for (i = 0; i < cur_st_id; i++)
103 good_dead(Element *e, FSM_use *u)
105 switch (u->special) {
106 case 2: /* ok if it's a receive */
107 if (e->n->ntyp == ASGN
108 && e->n->rgt->ntyp == CONST
109 && e->n->rgt->val == 0)
112 case 1: /* must be able to use oval */
113 if (e->n->ntyp != 'c'
114 && e->n->ntyp != 'r')
115 return 0; /* can't really happen */
122 static int howdeep = 0;
126 eligible(FSM_trans *v)
131 if (el) lt = v->step->n;
133 if (!lt /* dead end */
134 || v->nxt /* has alternatives */
135 || el->esc /* has an escape */
136 || (el->status&CHECK2) /* remotely referenced */
137 || lt->ntyp == ATOMIC
138 || lt->ntyp == NON_ATOMIC /* used for inlines -- should be able to handle this */
140 || lt->ntyp == C_CODE
141 || lt->ntyp == C_EXPR
142 || has_lab(el, 0) /* any label at all */
145 || lt->ntyp == UNLESS
146 || lt->ntyp == D_STEP
154 if (!(el->status&(2|4))) /* not atomic */
155 { int unsafe = (el->status&I_GLOB)?1:has_global(el->n);
164 canfill_in(FSM_trans *v)
165 { Element *el = v->step;
166 Lextok *lt = v->step->n;
168 if (!lt /* dead end */
169 || v->nxt /* has alternatives */
170 || el->esc /* has an escape */
171 || (el->status&CHECK2)) /* remotely referenced */
174 if (!(el->status&(2|4)) /* not atomic */
175 && ((el->status&I_GLOB)
176 || has_global(el->n))) /* and not safe */
183 pushbuild(FSM_trans *v)
186 for (b = bs; b; b = b->nxt)
193 b = (BuildStack *) emalloc(sizeof(BuildStack));
204 fatal("cannot happen, popbuild", (char *) 0);
208 bf = f; /* freelist */
212 build_step(FSM_trans *v)
214 Element *el = v->step;
224 return v->step->merge; /* already done */
226 if (!eligible(v)) /* non-blocking */
229 if (!pushbuild(v)) /* cycle detected */
230 return -1; /* break cycle */
236 { if (++howdeep == 1)
237 printf("spin: %s, line %3d, merge:\n",
240 printf("\t[%d] <seqno %d>\t", howdeep, el->seqno);
241 comment(stdout, lt, 0);
245 r = build_step(f->t);
246 v->step->merge = (r == -1) ? st : r;
249 { printf(" merge value: %d (st=%d,r=%d, line %d)\n",
250 v->step->merge, st, r, el->n->ln);
256 return v->step->merge;
260 FSM_MERGER(char *pname_unused) /* find candidates for safely merging steps */
265 for (f = fsm; f; f = f->nxt) /* all states */
266 for (t = f->t; t; t = t->nxt) /* all edges */
267 { if (!t->step) continue; /* happens with 'unless' */
269 t->step->merge_in = f->in; /* ?? */
277 || lt->ntyp == 's') /* blocking stmnts */
278 continue; /* handled in 2nd scan */
288 t->step->merge_single = t->to;
291 { printf("spin: %s, line %3d, merge_single:\n\t<seqno %d>\t",
292 t->step->n->fn->name,
295 comment(stdout, t->step->n, 0);
300 /* t is an isolated eligible step:
302 * a merge_start can connect to a proper
303 * merge chain or to a merge_single
304 * a merge chain can be preceded by
305 * a merge_start, but not by a merge_single
311 (void) build_step(t);
314 /* 2nd scan -- find possible merge_starts */
316 for (f = fsm; f; f = f->nxt) /* all states */
317 for (t = f->t; t; t = t->nxt) /* all edges */
318 { if (!t->step || t->step->merge)
324 an rv send operation inside an atomic, *loses* atomicity
326 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
331 if (lt->ntyp == 'c' /* potentially blocking stmnts */
333 || (lt->ntyp == 's' && u_sync == 0)) /* added !u_sync in 4.1.3 */
334 { if (!canfill_in(t)) /* atomic, non-global, etc. */
338 if (!g || !g->t || !g->t->step)
340 if (g->t->step->merge)
341 t->step->merge_start = g->t->step->merge;
343 else if (g->t->step->merge_single)
344 t->step->merge_start = g->t->step->merge_single;
348 && t->step->merge_start)
349 { printf("spin: %s, line %3d, merge_START:\n\t<seqno %d>\t",
353 comment(stdout, lt, 0);
368 for (f = fsm; f; f = f->nxt) /* all states */
369 for (t = f->t; t; t = t->nxt) /* all edges */
370 for (n = 0; n < 2; n++) /* reads and writes */
371 for (u = t->Val[n]; u; u = u->nxt)
372 { if (!u->var->context /* global */
373 || u->var->type == CHAN
374 || u->var->type == STRUCT)
377 if (FSM_DFS(t->to, u)) /* cannot hit read before hitting write */
378 u->special = n+1; /* means, reset to 0 after use */
382 for (f = fsm; f; f = f->nxt)
383 for (t = f->t; t; t = t->nxt)
384 for (n = 0; n < 2; n++)
385 for (u = t->Val[n], w = (FSM_use *) 0; u; )
388 if (!w) /* remove from list */
394 { printf("%s : %3d: %d -> %d \t",
395 t->step->n->fn->name,
399 comment(stdout, t->step->n, 0);
400 printf("\t%c%d: %s\n", n==0?'R':'L',
401 u->special, u->var->name);
404 if (good_dead(t->step, u))
405 { u->nxt = t->step->dead; /* insert into dead */
420 u->var = (Symbol *) 0;
427 rel_trans(FSM_trans *t)
433 t->Val[0] = t->Val[1] = (FSM_use *) 0;
439 rel_state(FSM_state *f)
444 f->t = (FSM_trans *) 0;
453 fsm = (FSM_state *) 0;
460 /* fsm_tbl isn't allocated yet */
461 for (f = fsm; f; f = f->nxt)
467 memset(f, 0, sizeof(FSM_state));
468 fsm_free = fsm_free->nxt;
470 f = (FSM_state *) emalloc(sizeof(FSM_state));
472 f->t = (FSM_trans *) 0;
487 memset(t, 0, sizeof(FSM_trans));
488 trans_free = trans_free->nxt;
490 t = (FSM_trans *) emalloc(sizeof(FSM_trans));
497 FSM_EDGE(int from, int to, Element *e)
501 f = mkstate(from); /* find it or else make it */
512 { t = get_trans(from);
514 t->nxt = f->p; /* from is a predecessor of to */
519 ana_stmnt(t, t->step->n, 0);
526 ana_var(FSM_trans *t, Lextok *now, int usage)
529 if (!t || !now || !now->sym)
532 if (now->sym->name[0] == '_'
533 && (strcmp(now->sym->name, "_") == 0
534 || strcmp(now->sym->name, "_pid") == 0
535 || strcmp(now->sym->name, "_last") == 0))
539 for (u = v; u; u = u->nxt)
540 if (u->var == now->sym)
541 return; /* it's already there */
544 { /* not for array vars -- it's hard to tell statically
545 if the index would, at runtime, evaluate to the
546 same values at lval and rval references
550 use_free = use_free->nxt;
552 u = (FSM_use *) emalloc(sizeof(FSM_use));
555 u->nxt = t->Val[usage];
558 ana_stmnt(t, now->lft, RVAL); /* index */
560 if (now->sym->type == STRUCT
563 ana_var(t, now->rgt->lft, usage);
567 ana_stmnt(FSM_trans *t, Lextok *now, int usage)
570 if (!t || !now) return;
603 ana_stmnt(t, now->lft, RVAL);
624 ana_stmnt(t, now->lft, RVAL);
625 ana_stmnt(t, now->rgt, RVAL);
629 ana_stmnt(t, now->lft, LVAL);
630 ana_stmnt(t, now->rgt, RVAL);
635 for (v = now->lft; v; v = v->rgt)
636 ana_stmnt(t, v->lft, RVAL);
640 if (now->lft && !now->lft->ismtyp)
641 ana_stmnt(t, now->lft, RVAL);
645 ana_stmnt(t, now->lft, RVAL);
646 for (v = now->rgt; v; v = v->rgt)
647 ana_stmnt(t, v->lft, RVAL);
652 ana_stmnt(t, now->lft, RVAL);
653 for (v = now->rgt; v; v = v->rgt)
654 { if (v->lft->ntyp == EVAL)
655 ana_stmnt(t, v->lft->lft, RVAL);
657 if (v->lft->ntyp != CONST
658 && now->ntyp != 'R') /* was v->lft->ntyp */
659 ana_stmnt(t, v->lft, LVAL);
664 ana_stmnt(t, now->lft, RVAL);
666 { ana_stmnt(t, now->rgt->lft, RVAL);
667 ana_stmnt(t, now->rgt->rgt, RVAL);
672 ana_var(t, now, usage);
675 case 'p': /* remote ref */
676 ana_stmnt(t, now->lft->lft, RVAL); /* process id */
677 ana_var(t, now, RVAL);
678 ana_var(t, now->rgt, RVAL);
682 printf("spin: bad node type %d line %d (ana_stmnt)\n", now->ntyp, now->ln);
683 fatal("aborting", (char *) 0);
688 ana_src(int dataflow, int merger) /* called from main.c and guided.c */
694 for (p = rdy; p; p = p->nxt)
695 { if (p->tn == eventmapnr
704 if (dataflow || merger)
705 { printf("spin: %d, optimizing '%s'",
706 counter++, p->n->name);
714 { FSM_MERGER(p->n->name);
715 huntele(e, e->status, -1)->merge_in = 1; /* start-state */
721 AST_store(p, huntele(e, e->status, -1)->seqno);
725 for (e = Al_El; e; e = e->Nxt)
727 if (!(e->status&DONE) && (verbose&32))
728 { printf("unreachable code: ");
729 printf("%s, line %3d: ",
730 e->n->fn->name, e->n->ln);
731 comment(stdout, e->n, 0);
743 spit_recvs(FILE *f1, FILE *f2) /* called from pangen2.c */
748 fprintf(f1, "unsigned char Is_Recv[%d];\n", Unique);
750 fprintf(f2, "void\nset_recvs(void)\n{\n");
751 for (e = Al_El; e; e = e->Nxt)
752 { if (!e->n) continue;
754 switch (e->n->ntyp) {
756 markit: fprintf(f2, "\tIs_Recv[%d] = 1;\n", e->Seqno);
760 switch (s->frst->n->ntyp) {
762 fatal("unexpected: do at start of d_step", (char *) 0);
763 case IF: /* conservative: fall through */
764 case 'r': goto markit;
773 fprintf(f2, "int\nno_recvs(int me)\n{\n");
774 fprintf(f2, " int h; uchar ot; short tt;\n");
775 fprintf(f2, " Trans *t;\n");
776 fprintf(f2, " for (h = BASE; h < (int) now._nr_pr; h++)\n");
777 fprintf(f2, " { if (h == me) continue;\n");
778 fprintf(f2, " tt = (short) ((P0 *)pptr(h))->_p;\n");
779 fprintf(f2, " ot = (uchar) ((P0 *)pptr(h))->_t;\n");
780 fprintf(f2, " for (t = trans[ot][tt]; t; t = t->nxt)\n");
781 fprintf(f2, " if (Is_Recv[t->t_id]) return 0;\n");
783 fprintf(f2, " return 1;\n");
795 for (e = s->frst; e; e = e->nxt)
796 { if (e->status & DONE)
803 if (e->n->ntyp == UNLESS)
804 ana_seq(e->sub->this);
806 { for (h = e->sub; h; h = h->nxt)
807 { g = huntstart(h->this->frst);
810 if (g->n->ntyp != 'c'
811 || g->n->lft->ntyp != CONST
812 || g->n->lft->val != 0
814 FSM_EDGE(From, To, e);
815 /* else it's a dead link */
817 for (h = e->sub; h; h = h->nxt)
819 } else if (e->n->ntyp == ATOMIC
820 || e->n->ntyp == D_STEP
821 || e->n->ntyp == NON_ATOMIC)
824 g = huntstart(t->frst);
825 t->last->nxt = e->nxt;
827 FSM_EDGE(From, To, e);
831 { if (e->n->ntyp == GOTO)
832 { g = get_lab(e->n, 1);
833 g = huntele(g, e->status, -1);
836 { g = huntele(e->nxt, e->status, -1);
841 FSM_EDGE(From, To, e);
844 && e->n->ntyp != GOTO
845 && e->n->ntyp != '.')
846 for (h = e->esc; h; h = h->nxt)
847 { g = huntstart(h->this->frst);
849 FSM_EDGE(From, To, ZE);
854 checklast: if (e == s->last)