1 /***** spin: pangen5.c *****/
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
12 typedef struct BuildStack {
14 struct BuildStack *nxt;
18 extern int verbose, eventmapnr, claimnr, rvopt, export_ast, u_sync;
19 extern Element *Al_El;
21 static FSM_state *fsm_free;
22 static FSM_trans *trans_free;
23 static BuildStack *bs, *bf;
31 static void ana_seq(Sequence *);
32 static void ana_stmnt(FSM_trans *, Lextok *, int);
34 extern void AST_slice(void);
35 extern void AST_store(ProcList *, int);
36 extern int has_global(Lextok *);
37 extern void exit(int);
43 /* fprintf(stderr, "omax %d, max=%d\n", o_max, max_st_id); */
44 if (o_max < max_st_id)
46 fsm_tbl = (FSM_state **) emalloc(max_st_id * sizeof(FSM_state *));
48 memset((char *)fsm_tbl, 0, max_st_id * sizeof(FSM_state *));
49 cur_st_id = max_st_id;
52 for (f = fsm; f; f = f->nxt)
57 FSM_DFS(int from, FSM_use *u)
69 { printf("cannot find state %d\n", from);
70 fatal("fsm_dfs: cannot happen\n", (char *) 0);
77 for (t = f->t; t; t = t->nxt)
79 for (n = 0; n < 2; n++)
80 for (v = t->Val[n]; v; v = v->nxt)
82 return n; /* a read or write */
84 if (!FSM_DFS(t->to, u))
94 for (i = 0; i < cur_st_id; i++)
100 good_dead(Element *e, FSM_use *u)
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)
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 */
119 static int howdeep = 0;
123 eligible(FSM_trans *v)
128 if (el) lt = v->step->n;
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 */
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 */
143 || lt->ntyp == UNLESS
144 || lt->ntyp == D_STEP
152 if (!(el->status&(2|4))) /* not atomic */
153 { int unsafe = (el->status&I_GLOB)?1:has_global(el->n);
162 canfill_in(FSM_trans *v)
163 { Element *el = v->step;
164 Lextok *lt = v->step->n;
166 if (!lt /* dead end */
167 || v->nxt /* has alternatives */
168 || el->esc /* has an escape */
169 || (el->status&CHECK2)) /* remotely referenced */
172 if (!(el->status&(2|4)) /* not atomic */
173 && ((el->status&I_GLOB)
174 || has_global(el->n))) /* and not safe */
181 pushbuild(FSM_trans *v)
184 for (b = bs; b; b = b->nxt)
191 b = (BuildStack *) emalloc(sizeof(BuildStack));
202 fatal("cannot happen, popbuild", (char *) 0);
206 bf = f; /* freelist */
210 build_step(FSM_trans *v)
227 return v->step->merge; /* already done */
229 if (!eligible(v)) /* non-blocking */
232 if (!pushbuild(v)) /* cycle detected */
233 return -1; /* break cycle */
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);
246 r = build_step(f->t);
247 v->step->merge = (r == -1) ? st : r;
250 { printf(" merge value: %d (st=%d,r=%d, line %d)\n",
251 v->step->merge, st, r, el->n->ln);
257 return v->step->merge;
261 FSM_MERGER(/* char *pname */ void) /* find candidates for safely merging steps */
266 for (f = fsm; 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' */
270 t->step->merge_in = f->in; /* ?? */
278 || lt->ntyp == 's') /* blocking stmnts */
279 continue; /* handled in 2nd scan */
285 if (!g || !eligible(g->t))
289 t->step->merge_single = t->to;
292 { printf("spin: %s:%d, merge_single:\n\t<seqno %d>\t",
293 t->step->n->fn->name,
296 comment(stdout, t->step->n, 0);
301 /* t is an isolated eligible step:
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
312 (void) build_step(t);
315 /* 2nd scan -- find possible merge_starts */
317 for (f = fsm; f; f = f->nxt) /* all states */
318 for (t = f->t; t; t = t->nxt) /* all edges */
319 { if (!t->step || t->step->merge)
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;
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
335 if ((lt->ntyp == 'c' && !any_oper(lt->lft, RUN)) /* 2nd clause 6.2.2 */
337 || (lt->ntyp == 's' && u_sync == 0)) /* added !u_sync in 4.1.3 */
338 { if (!canfill_in(t)) /* atomic, non-global, etc. */
342 if (!g || !g->t || !g->t->step)
344 if (g->t->step->merge)
345 t->step->merge_start = g->t->step->merge;
347 else if (g->t->step->merge_single)
348 t->step->merge_start = g->t->step->merge_single;
352 && t->step->merge_start)
353 { printf("spin: %s:%d, merge_START:\n\t<seqno %d>\t",
354 lt->fn->name, lt->ln,
356 comment(stdout, lt, 0);
371 for (f = fsm; 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)
380 if (FSM_DFS(t->to, u)) /* cannot hit read before hitting write */
381 u->special = n+1; /* means, reset to 0 after use */
385 for (f = fsm; 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; )
391 if (!w) /* remove from list */
397 { printf("%s : %3d: %d -> %d \t",
398 t->step->n->fn->name,
402 comment(stdout, t->step->n, 0);
403 printf("\t%c%d: %s\n", n==0?'R':'L',
404 u->special, u->var->name);
407 if (good_dead(t->step, u))
408 { u->nxt = t->step->dead; /* insert into dead */
423 u->var = (Symbol *) 0;
430 rel_trans(FSM_trans *t)
436 t->Val[0] = t->Val[1] = (FSM_use *) 0;
442 rel_state(FSM_state *f)
447 f->t = (FSM_trans *) 0;
456 fsm = (FSM_state *) 0;
463 /* fsm_tbl isn't allocated yet */
464 for (f = fsm; f; f = f->nxt)
470 memset(f, 0, sizeof(FSM_state));
471 fsm_free = fsm_free->nxt;
473 f = (FSM_state *) emalloc(sizeof(FSM_state));
475 f->t = (FSM_trans *) 0;
490 memset(t, 0, sizeof(FSM_trans));
491 trans_free = trans_free->nxt;
493 t = (FSM_trans *) emalloc(sizeof(FSM_trans));
500 FSM_EDGE(int from, int to, Element *e)
504 f = mkstate(from); /* find it or else make it */
515 { t = get_trans(from);
517 t->nxt = f->p; /* from is a predecessor of to */
522 ana_stmnt(t, t->step->n, 0);
529 ana_var(FSM_trans *t, Lextok *now, int usage)
532 if (!t || !now || !now->sym)
535 if (now->sym->name[0] == '_'
536 && (strcmp(now->sym->name, "_") == 0
537 || strcmp(now->sym->name, "_pid") == 0
538 || strcmp(now->sym->name, "_priority") == 0
539 || strcmp(now->sym->name, "_last") == 0))
543 for (u = v; u; u = u->nxt)
544 if (u->var == now->sym)
545 return; /* it's already there */
548 { /* not for array vars -- it's hard to tell statically
549 if the index would, at runtime, evaluate to the
550 same values at lval and rval references
554 use_free = use_free->nxt;
556 u = (FSM_use *) emalloc(sizeof(FSM_use));
559 u->nxt = t->Val[usage];
562 ana_stmnt(t, now->lft, RVAL); /* index */
564 if (now->sym->type == STRUCT
567 ana_var(t, now->rgt->lft, usage);
571 ana_stmnt(FSM_trans *t, Lextok *now, int usage)
574 if (!t || !now) return;
595 case ',': /* reached with SET_P and array initializers */
596 if (now->lft && now->lft->rgt)
597 { ana_stmnt(t, now->lft->rgt, RVAL);
614 ana_stmnt(t, now->lft, RVAL);
618 ana_stmnt(t, now->lft, RVAL); /* ',' */
619 ana_stmnt(t, now->lft->rgt, RVAL);
640 ana_stmnt(t, now->lft, RVAL);
641 ana_stmnt(t, now->rgt, RVAL);
645 if (check_track(now) == STRUCT) { break; }
647 ana_stmnt(t, now->lft, LVAL);
649 ana_stmnt(t, now->rgt, RVAL);
654 for (v = now->lft; v; v = v->rgt)
655 ana_stmnt(t, v->lft, RVAL);
659 if (now->lft && !now->lft->ismtyp)
660 ana_stmnt(t, now->lft, RVAL);
664 ana_stmnt(t, now->lft, RVAL);
665 for (v = now->rgt; v; v = v->rgt)
666 ana_stmnt(t, v->lft, RVAL);
671 ana_stmnt(t, now->lft, RVAL);
672 for (v = now->rgt; v; v = v->rgt)
673 { if (v->lft->ntyp == EVAL)
674 ana_stmnt(t, v->lft->lft, RVAL);
676 if (v->lft->ntyp != CONST
677 && now->ntyp != 'R') /* was v->lft->ntyp */
678 ana_stmnt(t, v->lft, LVAL);
683 ana_stmnt(t, now->lft, RVAL);
685 { ana_stmnt(t, now->rgt->lft, RVAL);
686 ana_stmnt(t, now->rgt->rgt, RVAL);
691 ana_var(t, now, usage);
694 case 'p': /* remote ref */
695 ana_stmnt(t, now->lft->lft, RVAL); /* process id */
696 ana_var(t, now, RVAL);
697 ana_var(t, now->rgt, RVAL);
701 printf("spin: %s:%d, bad node type %d (ana_stmnt)\n",
702 now->fn->name, now->ln, now->ntyp);
703 fatal("aborting", (char *) 0);
708 ana_src(int dataflow, int merger) /* called from main.c and guided.c */
714 for (p = rdy; p; p = p->nxt)
721 if (dataflow || merger)
722 { printf("spin: %d, optimizing '%s'",
723 counter++, p->n->name);
731 { FSM_MERGER(/* p->n->name */);
732 huntele(e, e->status, -1)->merge_in = 1; /* start-state */
738 AST_store(p, huntele(e, e->status, -1)->seqno);
742 for (e = Al_El; e; e = e->Nxt)
744 if (!(e->status&DONE) && (verbose&32))
745 { printf("unreachable code: ");
746 printf("%s:%3d ", e->n->fn->name, e->n->ln);
747 comment(stdout, e->n, 0);
754 alldone(0); /* changed in 5.3.0: was exit(0) */
759 spit_recvs(FILE *f1, FILE *f2) /* called from pangen2.c */
764 fprintf(f1, "unsigned char Is_Recv[%d];\n", Unique);
766 fprintf(f2, "void\nset_recvs(void)\n{\n");
767 for (e = Al_El; e; e = e->Nxt)
768 { if (!e->n) continue;
770 switch (e->n->ntyp) {
772 markit: fprintf(f2, "\tIs_Recv[%d] = 1;\n", e->Seqno);
776 switch (s->frst->n->ntyp) {
778 fatal("unexpected: do at start of d_step", (char *) 0);
779 case IF: /* conservative: fall through */
780 case 'r': goto markit;
789 fprintf(f2, "int\nno_recvs(int me)\n{\n");
790 fprintf(f2, " int h; uchar ot; short tt;\n");
791 fprintf(f2, " Trans *t;\n");
792 fprintf(f2, " for (h = BASE; h < (int) now._nr_pr; h++)\n");
793 fprintf(f2, " { if (h == me) continue;\n");
794 fprintf(f2, " tt = (short) ((P0 *)pptr(h))->_p;\n");
795 fprintf(f2, " ot = (uchar) ((P0 *)pptr(h))->_t;\n");
796 fprintf(f2, " for (t = trans[ot][tt]; t; t = t->nxt)\n");
797 fprintf(f2, " if (Is_Recv[t->t_id]) return 0;\n");
799 fprintf(f2, " return 1;\n");
811 for (e = s->frst; e; e = e->nxt)
812 { if (e->status & DONE)
819 if (e->n->ntyp == UNLESS)
820 ana_seq(e->sub->this);
822 { for (h = e->sub; h; h = h->nxt)
823 { g = huntstart(h->this->frst);
826 if (g->n->ntyp != 'c'
827 || g->n->lft->ntyp != CONST
828 || g->n->lft->val != 0
830 FSM_EDGE(From, To, e);
831 /* else it's a dead link */
833 for (h = e->sub; h; h = h->nxt)
835 } else if (e->n->ntyp == ATOMIC
836 || e->n->ntyp == D_STEP
837 || e->n->ntyp == NON_ATOMIC)
840 g = huntstart(t->frst);
841 t->last->nxt = e->nxt;
843 FSM_EDGE(From, To, e);
847 { if (e->n->ntyp == GOTO)
848 { g = get_lab(e->n, 1);
849 g = huntele(g, e->status, -1);
851 { fatal("unexpected error 2", (char *) 0);
855 { g = huntele(e->nxt, e->status, -1);
857 { fatal("unexpected error 3", (char *) 0);
863 FSM_EDGE(From, To, e);
866 && e->n->ntyp != GOTO
867 && e->n->ntyp != '.')
868 for (h = e->esc; h; h = h->nxt)
869 { g = huntstart(h->this->frst);
871 FSM_EDGE(From, To, ZE);
876 checklast: if (e == s->last)