![cinap_lenrek](/assets/img/avatar_default.png)
from Ori_B: There were a small number of changes needed from the tarball on spinroot.org: - The mkfile needed to be updated - Memory.h needed to not be included - It needed to invoke /bin/cpp instead of gcc -E - It depended on `yychar`, which our yacc doesn't provide. I'm still figuring out how to use spin, but it seems to do the right thing when testing a few of the examples: % cd $home/src/Spin/Examples/ % spin -a peterson.pml % pcc pan.c -D_POSIX_SOURCE % ./6.out (Spin Version 6.4.7 -- 19 August 2017) + Partial Order Reduction Full statespace search for: never claim - (none specified) assertion violations + acceptance cycles - (not selected) invalid end states + State-vector 32 byte, depth reached 24, errors: 0 40 states, stored 27 states, matched 67 transitions (= stored+matched) 0 atomic steps hash conflicts: 0 (resolved) Stats on memory usage (in Megabytes): 0.002 equivalent memory usage for states (stored*(State-vector + overhead)) 0.292 actual memory usage for states 128.000 memory used for hash table (-w24) 0.534 memory used for DFS stack (-m10000) 128.730 total actual memory usage unreached in proctype user /tmp/Spin/Examples/peterson.pml:20, state 10, "-end-" (1 of 10 states) pan: elapsed time 1.25 seconds pan: rate 32 states/second
880 lines
17 KiB
C
880 lines
17 KiB
C
/***** spin: pangen5.c *****/
|
|
|
|
/*
|
|
* This file is part of the public release of Spin. It is subject to the
|
|
* terms in the LICENSE file that is included in this source directory.
|
|
* Tool documentation is available at http://spinroot.com
|
|
*/
|
|
|
|
#include "spin.h"
|
|
#include "y.tab.h"
|
|
|
|
typedef struct BuildStack {
|
|
FSM_trans *t;
|
|
struct BuildStack *nxt;
|
|
} BuildStack;
|
|
|
|
extern ProcList *rdy;
|
|
extern int verbose, eventmapnr, claimnr, rvopt, export_ast, u_sync;
|
|
extern Element *Al_El;
|
|
|
|
static FSM_state *fsm_free;
|
|
static FSM_trans *trans_free;
|
|
static BuildStack *bs, *bf;
|
|
static int max_st_id;
|
|
static int cur_st_id;
|
|
int o_max;
|
|
FSM_state *fsm;
|
|
FSM_state **fsm_tbl;
|
|
FSM_use *use_free;
|
|
|
|
static void ana_seq(Sequence *);
|
|
static void ana_stmnt(FSM_trans *, Lextok *, int);
|
|
|
|
extern void AST_slice(void);
|
|
extern void AST_store(ProcList *, int);
|
|
extern int has_global(Lextok *);
|
|
extern void exit(int);
|
|
|
|
static void
|
|
fsm_table(void)
|
|
{ FSM_state *f;
|
|
max_st_id += 2;
|
|
/* fprintf(stderr, "omax %d, max=%d\n", o_max, max_st_id); */
|
|
if (o_max < max_st_id)
|
|
{ o_max = max_st_id;
|
|
fsm_tbl = (FSM_state **) emalloc(max_st_id * sizeof(FSM_state *));
|
|
} else
|
|
memset((char *)fsm_tbl, 0, max_st_id * sizeof(FSM_state *));
|
|
cur_st_id = max_st_id;
|
|
max_st_id = 0;
|
|
|
|
for (f = fsm; f; f = f->nxt)
|
|
fsm_tbl[f->from] = f;
|
|
}
|
|
|
|
static int
|
|
FSM_DFS(int from, FSM_use *u)
|
|
{ FSM_state *f;
|
|
FSM_trans *t;
|
|
FSM_use *v;
|
|
int n;
|
|
|
|
if (from == 0)
|
|
return 1;
|
|
|
|
f = fsm_tbl[from];
|
|
|
|
if (!f)
|
|
{ printf("cannot find state %d\n", from);
|
|
fatal("fsm_dfs: cannot happen\n", (char *) 0);
|
|
}
|
|
|
|
if (f->seen)
|
|
return 1;
|
|
f->seen = 1;
|
|
|
|
for (t = f->t; t; t = t->nxt)
|
|
{
|
|
for (n = 0; n < 2; n++)
|
|
for (v = t->Val[n]; v; v = v->nxt)
|
|
if (u->var == v->var)
|
|
return n; /* a read or write */
|
|
|
|
if (!FSM_DFS(t->to, u))
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
new_dfs(void)
|
|
{ int i;
|
|
|
|
for (i = 0; i < cur_st_id; i++)
|
|
if (fsm_tbl[i])
|
|
fsm_tbl[i]->seen = 0;
|
|
}
|
|
|
|
static int
|
|
good_dead(Element *e, FSM_use *u)
|
|
{
|
|
switch (u->special) {
|
|
case 2: /* ok if it's a receive */
|
|
if (e->n->ntyp == ASGN
|
|
&& e->n->rgt->ntyp == CONST
|
|
&& e->n->rgt->val == 0)
|
|
return 0;
|
|
break;
|
|
case 1: /* must be able to use oval */
|
|
if (e->n->ntyp != 'c'
|
|
&& e->n->ntyp != 'r')
|
|
return 0; /* can't really happen */
|
|
break;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
#if 0
|
|
static int howdeep = 0;
|
|
#endif
|
|
|
|
static int
|
|
eligible(FSM_trans *v)
|
|
{ Element *el = ZE;
|
|
Lextok *lt = ZN;
|
|
|
|
if (v) el = v->step;
|
|
if (el) lt = v->step->n;
|
|
|
|
if (!lt /* dead end */
|
|
|| v->nxt /* has alternatives */
|
|
|| el->esc /* has an escape */
|
|
|| (el->status&CHECK2) /* remotely referenced */
|
|
|| lt->ntyp == ATOMIC
|
|
|| lt->ntyp == NON_ATOMIC /* used for inlines -- should be able to handle this */
|
|
|| lt->ntyp == IF
|
|
|| lt->ntyp == C_CODE
|
|
|| lt->ntyp == C_EXPR
|
|
|| has_lab(el, 0) /* any label at all */
|
|
|| lt->ntyp == SET_P /* to prevent multiple set_p merges */
|
|
|
|
|| lt->ntyp == DO
|
|
|| lt->ntyp == UNLESS
|
|
|| lt->ntyp == D_STEP
|
|
|| lt->ntyp == ELSE
|
|
|| lt->ntyp == '@'
|
|
|| lt->ntyp == 'c'
|
|
|| lt->ntyp == 'r'
|
|
|| lt->ntyp == 's')
|
|
return 0;
|
|
|
|
if (!(el->status&(2|4))) /* not atomic */
|
|
{ int unsafe = (el->status&I_GLOB)?1:has_global(el->n);
|
|
if (unsafe)
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
canfill_in(FSM_trans *v)
|
|
{ Element *el = v->step;
|
|
Lextok *lt = v->step->n;
|
|
|
|
if (!lt /* dead end */
|
|
|| v->nxt /* has alternatives */
|
|
|| el->esc /* has an escape */
|
|
|| (el->status&CHECK2)) /* remotely referenced */
|
|
return 0;
|
|
|
|
if (!(el->status&(2|4)) /* not atomic */
|
|
&& ((el->status&I_GLOB)
|
|
|| has_global(el->n))) /* and not safe */
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
pushbuild(FSM_trans *v)
|
|
{ BuildStack *b;
|
|
|
|
for (b = bs; b; b = b->nxt)
|
|
if (b->t == v)
|
|
return 0;
|
|
if (bf)
|
|
{ b = bf;
|
|
bf = bf->nxt;
|
|
} else
|
|
b = (BuildStack *) emalloc(sizeof(BuildStack));
|
|
b->t = v;
|
|
b->nxt = bs;
|
|
bs = b;
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
popbuild(void)
|
|
{ BuildStack *f;
|
|
if (!bs)
|
|
fatal("cannot happen, popbuild", (char *) 0);
|
|
f = bs;
|
|
bs = bs->nxt;
|
|
f->nxt = bf;
|
|
bf = f; /* freelist */
|
|
}
|
|
|
|
static int
|
|
build_step(FSM_trans *v)
|
|
{ FSM_state *f;
|
|
Element *el;
|
|
#if 0
|
|
Lextok *lt = ZN;
|
|
#endif
|
|
int st;
|
|
int r;
|
|
|
|
if (!v) return -1;
|
|
|
|
el = v->step;
|
|
st = v->to;
|
|
|
|
if (!el) return -1;
|
|
|
|
if (v->step->merge)
|
|
return v->step->merge; /* already done */
|
|
|
|
if (!eligible(v)) /* non-blocking */
|
|
return -1;
|
|
|
|
if (!pushbuild(v)) /* cycle detected */
|
|
return -1; /* break cycle */
|
|
|
|
f = fsm_tbl[st];
|
|
#if 0
|
|
lt = v->step->n;
|
|
if (verbose&32)
|
|
{ if (++howdeep == 1)
|
|
printf("spin: %s:%d, merge:\n", lt->fn->name, lt->ln);
|
|
printf("\t[%d] <seqno %d>\t", howdeep, el->seqno);
|
|
comment(stdout, lt, 0);
|
|
printf(";\n");
|
|
}
|
|
#endif
|
|
r = build_step(f->t);
|
|
v->step->merge = (r == -1) ? st : r;
|
|
#if 0
|
|
if (verbose&32)
|
|
{ printf(" merge value: %d (st=%d,r=%d, line %d)\n",
|
|
v->step->merge, st, r, el->n->ln);
|
|
howdeep--;
|
|
}
|
|
#endif
|
|
popbuild();
|
|
|
|
return v->step->merge;
|
|
}
|
|
|
|
static void
|
|
FSM_MERGER(/* char *pname */ void) /* find candidates for safely merging steps */
|
|
{ FSM_state *f, *g;
|
|
FSM_trans *t;
|
|
Lextok *lt;
|
|
|
|
for (f = fsm; f; f = f->nxt) /* all states */
|
|
for (t = f->t; t; t = t->nxt) /* all edges */
|
|
{ if (!t->step) continue; /* happens with 'unless' */
|
|
|
|
t->step->merge_in = f->in; /* ?? */
|
|
|
|
if (t->step->merge)
|
|
continue;
|
|
lt = t->step->n;
|
|
|
|
if (lt->ntyp == 'c'
|
|
|| lt->ntyp == 'r'
|
|
|| lt->ntyp == 's') /* blocking stmnts */
|
|
continue; /* handled in 2nd scan */
|
|
|
|
if (!eligible(t))
|
|
continue;
|
|
|
|
g = fsm_tbl[t->to];
|
|
if (!g || !eligible(g->t))
|
|
{
|
|
#define SINGLES
|
|
#ifdef SINGLES
|
|
t->step->merge_single = t->to;
|
|
#if 0
|
|
if ((verbose&32))
|
|
{ printf("spin: %s:%d, merge_single:\n\t<seqno %d>\t",
|
|
t->step->n->fn->name,
|
|
t->step->n->ln,
|
|
t->step->seqno);
|
|
comment(stdout, t->step->n, 0);
|
|
printf(";\n");
|
|
}
|
|
#endif
|
|
#endif
|
|
/* t is an isolated eligible step:
|
|
*
|
|
* a merge_start can connect to a proper
|
|
* merge chain or to a merge_single
|
|
* a merge chain can be preceded by
|
|
* a merge_start, but not by a merge_single
|
|
*/
|
|
|
|
continue;
|
|
}
|
|
|
|
(void) build_step(t);
|
|
}
|
|
|
|
/* 2nd scan -- find possible merge_starts */
|
|
|
|
for (f = fsm; f; f = f->nxt) /* all states */
|
|
for (t = f->t; t; t = t->nxt) /* all edges */
|
|
{ if (!t->step || t->step->merge)
|
|
continue;
|
|
|
|
lt = t->step->n;
|
|
#if 0
|
|
4.1.3:
|
|
an rv send operation ('s') inside an atomic, *loses* atomicity
|
|
when executed, and should therefore never be merged with a subsequent
|
|
statement within the atomic sequence
|
|
the same is not true for non-rv send operations;
|
|
6.2.2:
|
|
RUN statements can start a new process at a higher priority level
|
|
which interferes with statement merging, so it too is not a suitable
|
|
merge target
|
|
#endif
|
|
|
|
if ((lt->ntyp == 'c' && !any_oper(lt->lft, RUN)) /* 2nd clause 6.2.2 */
|
|
|| lt->ntyp == 'r'
|
|
|| (lt->ntyp == 's' && u_sync == 0)) /* added !u_sync in 4.1.3 */
|
|
{ if (!canfill_in(t)) /* atomic, non-global, etc. */
|
|
continue;
|
|
|
|
g = fsm_tbl[t->to];
|
|
if (!g || !g->t || !g->t->step)
|
|
continue;
|
|
if (g->t->step->merge)
|
|
t->step->merge_start = g->t->step->merge;
|
|
#ifdef SINGLES
|
|
else if (g->t->step->merge_single)
|
|
t->step->merge_start = g->t->step->merge_single;
|
|
#endif
|
|
#if 0
|
|
if ((verbose&32)
|
|
&& t->step->merge_start)
|
|
{ printf("spin: %s:%d, merge_START:\n\t<seqno %d>\t",
|
|
lt->fn->name, lt->ln,
|
|
t->step->seqno);
|
|
comment(stdout, lt, 0);
|
|
printf(";\n");
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
FSM_ANA(void)
|
|
{ FSM_state *f;
|
|
FSM_trans *t;
|
|
FSM_use *u, *v, *w;
|
|
int n;
|
|
|
|
for (f = fsm; f; f = f->nxt) /* all states */
|
|
for (t = f->t; t; t = t->nxt) /* all edges */
|
|
for (n = 0; n < 2; n++) /* reads and writes */
|
|
for (u = t->Val[n]; u; u = u->nxt)
|
|
{ if (!u->var->context /* global */
|
|
|| u->var->type == CHAN
|
|
|| u->var->type == STRUCT)
|
|
continue;
|
|
new_dfs();
|
|
if (FSM_DFS(t->to, u)) /* cannot hit read before hitting write */
|
|
u->special = n+1; /* means, reset to 0 after use */
|
|
}
|
|
|
|
if (!export_ast)
|
|
for (f = fsm; f; f = f->nxt)
|
|
for (t = f->t; t; t = t->nxt)
|
|
for (n = 0; n < 2; n++)
|
|
for (u = t->Val[n], w = (FSM_use *) 0; u; )
|
|
{ if (u->special)
|
|
{ v = u->nxt;
|
|
if (!w) /* remove from list */
|
|
t->Val[n] = v;
|
|
else
|
|
w->nxt = v;
|
|
#if q
|
|
if (verbose&32)
|
|
{ printf("%s : %3d: %d -> %d \t",
|
|
t->step->n->fn->name,
|
|
t->step->n->ln,
|
|
f->from,
|
|
t->to);
|
|
comment(stdout, t->step->n, 0);
|
|
printf("\t%c%d: %s\n", n==0?'R':'L',
|
|
u->special, u->var->name);
|
|
}
|
|
#endif
|
|
if (good_dead(t->step, u))
|
|
{ u->nxt = t->step->dead; /* insert into dead */
|
|
t->step->dead = u;
|
|
}
|
|
u = v;
|
|
} else
|
|
{ w = u;
|
|
u = u->nxt;
|
|
} }
|
|
}
|
|
|
|
void
|
|
rel_use(FSM_use *u)
|
|
{
|
|
if (!u) return;
|
|
rel_use(u->nxt);
|
|
u->var = (Symbol *) 0;
|
|
u->special = 0;
|
|
u->nxt = use_free;
|
|
use_free = u;
|
|
}
|
|
|
|
static void
|
|
rel_trans(FSM_trans *t)
|
|
{
|
|
if (!t) return;
|
|
rel_trans(t->nxt);
|
|
rel_use(t->Val[0]);
|
|
rel_use(t->Val[1]);
|
|
t->Val[0] = t->Val[1] = (FSM_use *) 0;
|
|
t->nxt = trans_free;
|
|
trans_free = t;
|
|
}
|
|
|
|
static void
|
|
rel_state(FSM_state *f)
|
|
{
|
|
if (!f) return;
|
|
rel_state(f->nxt);
|
|
rel_trans(f->t);
|
|
f->t = (FSM_trans *) 0;
|
|
f->nxt = fsm_free;
|
|
fsm_free = f;
|
|
}
|
|
|
|
static void
|
|
FSM_DEL(void)
|
|
{
|
|
rel_state(fsm);
|
|
fsm = (FSM_state *) 0;
|
|
}
|
|
|
|
static FSM_state *
|
|
mkstate(int s)
|
|
{ FSM_state *f;
|
|
|
|
/* fsm_tbl isn't allocated yet */
|
|
for (f = fsm; f; f = f->nxt)
|
|
if (f->from == s)
|
|
break;
|
|
if (!f)
|
|
{ if (fsm_free)
|
|
{ f = fsm_free;
|
|
memset(f, 0, sizeof(FSM_state));
|
|
fsm_free = fsm_free->nxt;
|
|
} else
|
|
f = (FSM_state *) emalloc(sizeof(FSM_state));
|
|
f->from = s;
|
|
f->t = (FSM_trans *) 0;
|
|
f->nxt = fsm;
|
|
fsm = f;
|
|
if (s > max_st_id)
|
|
max_st_id = s;
|
|
}
|
|
return f;
|
|
}
|
|
|
|
static FSM_trans *
|
|
get_trans(int to)
|
|
{ FSM_trans *t;
|
|
|
|
if (trans_free)
|
|
{ t = trans_free;
|
|
memset(t, 0, sizeof(FSM_trans));
|
|
trans_free = trans_free->nxt;
|
|
} else
|
|
t = (FSM_trans *) emalloc(sizeof(FSM_trans));
|
|
|
|
t->to = to;
|
|
return t;
|
|
}
|
|
|
|
static void
|
|
FSM_EDGE(int from, int to, Element *e)
|
|
{ FSM_state *f;
|
|
FSM_trans *t;
|
|
|
|
f = mkstate(from); /* find it or else make it */
|
|
t = get_trans(to);
|
|
|
|
t->step = e;
|
|
t->nxt = f->t;
|
|
f->t = t;
|
|
|
|
f = mkstate(to);
|
|
f->in++;
|
|
|
|
if (export_ast)
|
|
{ t = get_trans(from);
|
|
t->step = e;
|
|
t->nxt = f->p; /* from is a predecessor of to */
|
|
f->p = t;
|
|
}
|
|
|
|
if (t->step)
|
|
ana_stmnt(t, t->step->n, 0);
|
|
}
|
|
|
|
#define LVAL 1
|
|
#define RVAL 0
|
|
|
|
static void
|
|
ana_var(FSM_trans *t, Lextok *now, int usage)
|
|
{ FSM_use *u, *v;
|
|
|
|
if (!t || !now || !now->sym)
|
|
return;
|
|
|
|
if (now->sym->name[0] == '_'
|
|
&& (strcmp(now->sym->name, "_") == 0
|
|
|| strcmp(now->sym->name, "_pid") == 0
|
|
|| strcmp(now->sym->name, "_priority") == 0
|
|
|| strcmp(now->sym->name, "_last") == 0))
|
|
return;
|
|
|
|
v = t->Val[usage];
|
|
for (u = v; u; u = u->nxt)
|
|
if (u->var == now->sym)
|
|
return; /* it's already there */
|
|
|
|
if (!now->lft)
|
|
{ /* not for array vars -- it's hard to tell statically
|
|
if the index would, at runtime, evaluate to the
|
|
same values at lval and rval references
|
|
*/
|
|
if (use_free)
|
|
{ u = use_free;
|
|
use_free = use_free->nxt;
|
|
} else
|
|
u = (FSM_use *) emalloc(sizeof(FSM_use));
|
|
|
|
u->var = now->sym;
|
|
u->nxt = t->Val[usage];
|
|
t->Val[usage] = u;
|
|
} else
|
|
ana_stmnt(t, now->lft, RVAL); /* index */
|
|
|
|
if (now->sym->type == STRUCT
|
|
&& now->rgt
|
|
&& now->rgt->lft)
|
|
ana_var(t, now->rgt->lft, usage);
|
|
}
|
|
|
|
static void
|
|
ana_stmnt(FSM_trans *t, Lextok *now, int usage)
|
|
{ Lextok *v;
|
|
|
|
if (!t || !now) return;
|
|
|
|
switch (now->ntyp) {
|
|
case '.':
|
|
case BREAK:
|
|
case GOTO:
|
|
case CONST:
|
|
case TIMEOUT:
|
|
case NONPROGRESS:
|
|
case ELSE:
|
|
case '@':
|
|
case 'q':
|
|
case IF:
|
|
case DO:
|
|
case ATOMIC:
|
|
case NON_ATOMIC:
|
|
case D_STEP:
|
|
case C_CODE:
|
|
case C_EXPR:
|
|
break;
|
|
|
|
case ',': /* reached with SET_P and array initializers */
|
|
if (now->lft && now->lft->rgt)
|
|
{ ana_stmnt(t, now->lft->rgt, RVAL);
|
|
}
|
|
break;
|
|
|
|
case '!':
|
|
case UMIN:
|
|
case '~':
|
|
case ENABLED:
|
|
case GET_P:
|
|
case PC_VAL:
|
|
case LEN:
|
|
case FULL:
|
|
case EMPTY:
|
|
case NFULL:
|
|
case NEMPTY:
|
|
case ASSERT:
|
|
case 'c':
|
|
ana_stmnt(t, now->lft, RVAL);
|
|
break;
|
|
|
|
case SET_P:
|
|
ana_stmnt(t, now->lft, RVAL); /* ',' */
|
|
ana_stmnt(t, now->lft->rgt, RVAL);
|
|
break;
|
|
|
|
case '/':
|
|
case '*':
|
|
case '-':
|
|
case '+':
|
|
case '%':
|
|
case '&':
|
|
case '^':
|
|
case '|':
|
|
case LT:
|
|
case GT:
|
|
case LE:
|
|
case GE:
|
|
case NE:
|
|
case EQ:
|
|
case OR:
|
|
case AND:
|
|
case LSHIFT:
|
|
case RSHIFT:
|
|
ana_stmnt(t, now->lft, RVAL);
|
|
ana_stmnt(t, now->rgt, RVAL);
|
|
break;
|
|
|
|
case ASGN:
|
|
if (check_track(now) == STRUCT) { break; }
|
|
|
|
ana_stmnt(t, now->lft, LVAL);
|
|
if (now->rgt->ntyp)
|
|
ana_stmnt(t, now->rgt, RVAL);
|
|
break;
|
|
|
|
case PRINT:
|
|
case RUN:
|
|
for (v = now->lft; v; v = v->rgt)
|
|
ana_stmnt(t, v->lft, RVAL);
|
|
break;
|
|
|
|
case PRINTM:
|
|
if (now->lft && !now->lft->ismtyp)
|
|
ana_stmnt(t, now->lft, RVAL);
|
|
break;
|
|
|
|
case 's':
|
|
ana_stmnt(t, now->lft, RVAL);
|
|
for (v = now->rgt; v; v = v->rgt)
|
|
ana_stmnt(t, v->lft, RVAL);
|
|
break;
|
|
|
|
case 'R':
|
|
case 'r':
|
|
ana_stmnt(t, now->lft, RVAL);
|
|
for (v = now->rgt; v; v = v->rgt)
|
|
{ if (v->lft->ntyp == EVAL)
|
|
ana_stmnt(t, v->lft->lft, RVAL);
|
|
else
|
|
if (v->lft->ntyp != CONST
|
|
&& now->ntyp != 'R') /* was v->lft->ntyp */
|
|
ana_stmnt(t, v->lft, LVAL);
|
|
}
|
|
break;
|
|
|
|
case '?':
|
|
ana_stmnt(t, now->lft, RVAL);
|
|
if (now->rgt)
|
|
{ ana_stmnt(t, now->rgt->lft, RVAL);
|
|
ana_stmnt(t, now->rgt->rgt, RVAL);
|
|
}
|
|
break;
|
|
|
|
case NAME:
|
|
ana_var(t, now, usage);
|
|
break;
|
|
|
|
case 'p': /* remote ref */
|
|
ana_stmnt(t, now->lft->lft, RVAL); /* process id */
|
|
ana_var(t, now, RVAL);
|
|
ana_var(t, now->rgt, RVAL);
|
|
break;
|
|
|
|
default:
|
|
printf("spin: %s:%d, bad node type %d (ana_stmnt)\n",
|
|
now->fn->name, now->ln, now->ntyp);
|
|
fatal("aborting", (char *) 0);
|
|
}
|
|
}
|
|
|
|
void
|
|
ana_src(int dataflow, int merger) /* called from main.c and guided.c */
|
|
{ ProcList *p;
|
|
Element *e;
|
|
#if 0
|
|
int counter = 1;
|
|
#endif
|
|
for (p = rdy; p; p = p->nxt)
|
|
{
|
|
ana_seq(p->s);
|
|
fsm_table();
|
|
|
|
e = p->s->frst;
|
|
#if 0
|
|
if (dataflow || merger)
|
|
{ printf("spin: %d, optimizing '%s'",
|
|
counter++, p->n->name);
|
|
fflush(stdout);
|
|
}
|
|
#endif
|
|
if (dataflow)
|
|
{ FSM_ANA();
|
|
}
|
|
if (merger)
|
|
{ FSM_MERGER(/* p->n->name */);
|
|
huntele(e, e->status, -1)->merge_in = 1; /* start-state */
|
|
#if 0
|
|
printf("\n");
|
|
#endif
|
|
}
|
|
if (export_ast)
|
|
AST_store(p, huntele(e, e->status, -1)->seqno);
|
|
|
|
FSM_DEL();
|
|
}
|
|
for (e = Al_El; e; e = e->Nxt)
|
|
{
|
|
if (!(e->status&DONE) && (verbose&32))
|
|
{ printf("unreachable code: ");
|
|
printf("%s:%3d ", e->n->fn->name, e->n->ln);
|
|
comment(stdout, e->n, 0);
|
|
printf("\n");
|
|
}
|
|
e->status &= ~DONE;
|
|
}
|
|
if (export_ast)
|
|
{ AST_slice();
|
|
alldone(0); /* changed in 5.3.0: was exit(0) */
|
|
}
|
|
}
|
|
|
|
void
|
|
spit_recvs(FILE *f1, FILE *f2) /* called from pangen2.c */
|
|
{ Element *e;
|
|
Sequence *s;
|
|
extern int Unique;
|
|
|
|
fprintf(f1, "unsigned char Is_Recv[%d];\n", Unique);
|
|
|
|
fprintf(f2, "void\nset_recvs(void)\n{\n");
|
|
for (e = Al_El; e; e = e->Nxt)
|
|
{ if (!e->n) continue;
|
|
|
|
switch (e->n->ntyp) {
|
|
case 'r':
|
|
markit: fprintf(f2, "\tIs_Recv[%d] = 1;\n", e->Seqno);
|
|
break;
|
|
case D_STEP:
|
|
s = e->n->sl->this;
|
|
switch (s->frst->n->ntyp) {
|
|
case DO:
|
|
fatal("unexpected: do at start of d_step", (char *) 0);
|
|
case IF: /* conservative: fall through */
|
|
case 'r': goto markit;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
fprintf(f2, "}\n");
|
|
|
|
if (rvopt)
|
|
{
|
|
fprintf(f2, "int\nno_recvs(int me)\n{\n");
|
|
fprintf(f2, " int h; uchar ot; short tt;\n");
|
|
fprintf(f2, " Trans *t;\n");
|
|
fprintf(f2, " for (h = BASE; h < (int) now._nr_pr; h++)\n");
|
|
fprintf(f2, " { if (h == me) continue;\n");
|
|
fprintf(f2, " tt = (short) ((P0 *)pptr(h))->_p;\n");
|
|
fprintf(f2, " ot = (uchar) ((P0 *)pptr(h))->_t;\n");
|
|
fprintf(f2, " for (t = trans[ot][tt]; t; t = t->nxt)\n");
|
|
fprintf(f2, " if (Is_Recv[t->t_id]) return 0;\n");
|
|
fprintf(f2, " }\n");
|
|
fprintf(f2, " return 1;\n");
|
|
fprintf(f2, "}\n");
|
|
}
|
|
}
|
|
|
|
static void
|
|
ana_seq(Sequence *s)
|
|
{ SeqList *h;
|
|
Sequence *t;
|
|
Element *e, *g;
|
|
int From, To;
|
|
|
|
for (e = s->frst; e; e = e->nxt)
|
|
{ if (e->status & DONE)
|
|
goto checklast;
|
|
|
|
e->status |= DONE;
|
|
|
|
From = e->seqno;
|
|
|
|
if (e->n->ntyp == UNLESS)
|
|
ana_seq(e->sub->this);
|
|
else if (e->sub)
|
|
{ for (h = e->sub; h; h = h->nxt)
|
|
{ g = huntstart(h->this->frst);
|
|
To = g->seqno;
|
|
|
|
if (g->n->ntyp != 'c'
|
|
|| g->n->lft->ntyp != CONST
|
|
|| g->n->lft->val != 0
|
|
|| g->esc)
|
|
FSM_EDGE(From, To, e);
|
|
/* else it's a dead link */
|
|
}
|
|
for (h = e->sub; h; h = h->nxt)
|
|
ana_seq(h->this);
|
|
} else if (e->n->ntyp == ATOMIC
|
|
|| e->n->ntyp == D_STEP
|
|
|| e->n->ntyp == NON_ATOMIC)
|
|
{
|
|
t = e->n->sl->this;
|
|
g = huntstart(t->frst);
|
|
t->last->nxt = e->nxt;
|
|
To = g->seqno;
|
|
FSM_EDGE(From, To, e);
|
|
|
|
ana_seq(t);
|
|
} else
|
|
{ if (e->n->ntyp == GOTO)
|
|
{ g = get_lab(e->n, 1);
|
|
g = huntele(g, e->status, -1);
|
|
if (!g)
|
|
{ fatal("unexpected error 2", (char *) 0);
|
|
}
|
|
To = g->seqno;
|
|
} else if (e->nxt)
|
|
{ g = huntele(e->nxt, e->status, -1);
|
|
if (!g)
|
|
{ fatal("unexpected error 3", (char *) 0);
|
|
}
|
|
To = g->seqno;
|
|
} else
|
|
To = 0;
|
|
|
|
FSM_EDGE(From, To, e);
|
|
|
|
if (e->esc
|
|
&& e->n->ntyp != GOTO
|
|
&& e->n->ntyp != '.')
|
|
for (h = e->esc; h; h = h->nxt)
|
|
{ g = huntstart(h->this->frst);
|
|
To = g->seqno;
|
|
FSM_EDGE(From, To, ZE);
|
|
ana_seq(h->this);
|
|
}
|
|
}
|
|
|
|
checklast: if (e == s->last)
|
|
break;
|
|
}
|
|
}
|