/***** spin: pangen5.c *****/ /* Copyright (c) 1999-2003 by Lucent Technologies, Bell Laboratories. *//* All Rights Reserved. This software is for educational purposes only. *//* No guarantee whatsoever is expressed or implied by the distribution of *//* this code. Permission is given to distribute this code provided that *//* this introductory message is not removed and no monies are exchanged. *//* Software written by Gerard J. Holzmann. For tool documentation see: *//* http://spinroot.com/ *//* Send all bug-reports and/or questions to: bugs@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 voidfsm_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 intFSM_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 voidnew_dfs(void){ int i; for (i = 0; i < cur_st_id; i++) if (fsm_tbl[i]) fsm_tbl[i]->seen = 0;} static intgood_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 0static int howdeep = 0;#endif static inteligible(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 == 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 intcanfill_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 intpushbuild(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 voidpopbuild(void){ BuildStack *f; if (!bs) fatal("cannot happen, popbuild", (char *) 0); f = bs; bs = bs->nxt; f->nxt = bf; bf = f; /* freelist */} static intbuild_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 voidFSM_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 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#endif if (lt->ntyp == 'c' /* potentially blocking stmnts */ || 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 voidFSM_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; } }} voidrel_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 voidrel_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 voidrel_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 voidFSM_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 voidFSM_EDGE(int from, int to, Element *e){ FSM_state *f;Lines 1–500 of 856. Load more
/***** spin: pangen5.c *****/ /* Copyright (c) 1999-2003 by Lucent Technologies, Bell Laboratories. */ /* All Rights Reserved. This software is for educational purposes only. */ /* No guarantee whatsoever is expressed or implied by the distribution of */ /* this code. Permission is given to distribute this code provided that */ /* this introductory message is not removed and no monies are exchanged. */ /* Software written by Gerard J. Holzmann. For tool documentation see: */ /* http://spinroot.com/ */ /* Send all bug-reports and/or questions to: bugs@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 == 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 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 #endif if (lt->ntyp == 'c' /* potentially blocking stmnts */ || 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;