1312a1df1SDavid du Colombier /***** spin: pangen6.c *****/
2312a1df1SDavid du Colombier
3312a1df1SDavid du Colombier /* Copyright (c) 2000-2003 by Lucent Technologies, Bell Laboratories. */
4312a1df1SDavid du Colombier /* All Rights Reserved. This software is for educational purposes only. */
5312a1df1SDavid du Colombier /* No guarantee whatsoever is expressed or implied by the distribution of */
6312a1df1SDavid du Colombier /* this code. Permission is given to distribute this code provided that */
7312a1df1SDavid du Colombier /* this introductory message is not removed and no monies are exchanged. */
8312a1df1SDavid du Colombier /* Software written by Gerard J. Holzmann. For tool documentation see: */
9312a1df1SDavid du Colombier /* http://spinroot.com/ */
10312a1df1SDavid du Colombier /* Send all bug-reports and/or questions to: bugs@spinroot.com */
11312a1df1SDavid du Colombier
12312a1df1SDavid du Colombier /* Abstract syntax tree analysis / slicing (spin option -A) */
13312a1df1SDavid du Colombier /* AST_store stores the fsms's for each proctype */
14312a1df1SDavid du Colombier /* AST_track keeps track of variables used in properties */
15312a1df1SDavid du Colombier /* AST_slice starts the slicing algorithm */
16312a1df1SDavid du Colombier /* it first collects more info and then calls */
17312a1df1SDavid du Colombier /* AST_criteria to process the slice criteria */
18312a1df1SDavid du Colombier
19312a1df1SDavid du Colombier #include "spin.h"
20312a1df1SDavid du Colombier #include "y.tab.h"
21312a1df1SDavid du Colombier
22312a1df1SDavid du Colombier extern Ordered *all_names;
23312a1df1SDavid du Colombier extern FSM_use *use_free;
24312a1df1SDavid du Colombier extern FSM_state **fsm_tbl;
25312a1df1SDavid du Colombier extern FSM_state *fsm;
26312a1df1SDavid du Colombier extern int verbose, o_max;
27312a1df1SDavid du Colombier
28312a1df1SDavid du Colombier static FSM_trans *cur_t;
29312a1df1SDavid du Colombier static FSM_trans *expl_par;
30312a1df1SDavid du Colombier static FSM_trans *expl_var;
31312a1df1SDavid du Colombier static FSM_trans *explicit;
32312a1df1SDavid du Colombier
33312a1df1SDavid du Colombier extern void rel_use(FSM_use *);
34312a1df1SDavid du Colombier
35312a1df1SDavid du Colombier #define ulong unsigned long
36312a1df1SDavid du Colombier
37312a1df1SDavid du Colombier typedef struct Pair {
38312a1df1SDavid du Colombier FSM_state *h;
39312a1df1SDavid du Colombier int b;
40312a1df1SDavid du Colombier struct Pair *nxt;
41312a1df1SDavid du Colombier } Pair;
42312a1df1SDavid du Colombier
43312a1df1SDavid du Colombier typedef struct AST {
44312a1df1SDavid du Colombier ProcList *p; /* proctype decl */
45312a1df1SDavid du Colombier int i_st; /* start state */
46312a1df1SDavid du Colombier int nstates, nwords;
47312a1df1SDavid du Colombier int relevant;
48312a1df1SDavid du Colombier Pair *pairs; /* entry and exit nodes of proper subgraphs */
49312a1df1SDavid du Colombier FSM_state *fsm; /* proctype body */
50312a1df1SDavid du Colombier struct AST *nxt; /* linked list */
51312a1df1SDavid du Colombier } AST;
52312a1df1SDavid du Colombier
53312a1df1SDavid du Colombier typedef struct RPN { /* relevant proctype names */
54312a1df1SDavid du Colombier Symbol *rn;
55312a1df1SDavid du Colombier struct RPN *nxt;
56312a1df1SDavid du Colombier } RPN;
57312a1df1SDavid du Colombier
58312a1df1SDavid du Colombier typedef struct ALIAS { /* channel aliasing info */
59312a1df1SDavid du Colombier Lextok *cnm; /* this chan */
60312a1df1SDavid du Colombier int origin; /* debugging - origin of the alias */
61312a1df1SDavid du Colombier struct ALIAS *alias; /* can be an alias for these other chans */
62312a1df1SDavid du Colombier struct ALIAS *nxt; /* linked list */
63312a1df1SDavid du Colombier } ALIAS;
64312a1df1SDavid du Colombier
65312a1df1SDavid du Colombier typedef struct ChanList {
66312a1df1SDavid du Colombier Lextok *s; /* containing stmnt */
67312a1df1SDavid du Colombier Lextok *n; /* point of reference - could be struct */
68312a1df1SDavid du Colombier struct ChanList *nxt; /* linked list */
69312a1df1SDavid du Colombier } ChanList;
70312a1df1SDavid du Colombier
71312a1df1SDavid du Colombier /* a chan alias can be created in one of three ways:
72312a1df1SDavid du Colombier assignement to chan name
73312a1df1SDavid du Colombier a = b -- a is now an alias for b
74312a1df1SDavid du Colombier passing chan name as parameter in run
75312a1df1SDavid du Colombier run x(b) -- proctype x(chan a)
76312a1df1SDavid du Colombier passing chan name through channel
77312a1df1SDavid du Colombier x!b -- x?a
78312a1df1SDavid du Colombier */
79312a1df1SDavid du Colombier
80312a1df1SDavid du Colombier #define USE 1
81312a1df1SDavid du Colombier #define DEF 2
82312a1df1SDavid du Colombier #define DEREF_DEF 4
83312a1df1SDavid du Colombier #define DEREF_USE 8
84312a1df1SDavid du Colombier
85312a1df1SDavid du Colombier static AST *ast;
86312a1df1SDavid du Colombier static ALIAS *chalcur;
87312a1df1SDavid du Colombier static ALIAS *chalias;
88312a1df1SDavid du Colombier static ChanList *chanlist;
89312a1df1SDavid du Colombier static Slicer *slicer;
90312a1df1SDavid du Colombier static Slicer *rel_vars; /* all relevant variables */
91312a1df1SDavid du Colombier static int AST_Changes;
92312a1df1SDavid du Colombier static int AST_Round;
93312a1df1SDavid du Colombier static RPN *rpn;
94312a1df1SDavid du Colombier static int in_recv = 0;
95312a1df1SDavid du Colombier
96312a1df1SDavid du Colombier static int AST_mutual(Lextok *, Lextok *, int);
97312a1df1SDavid du Colombier static void AST_dominant(void);
98312a1df1SDavid du Colombier static void AST_hidden(void);
99312a1df1SDavid du Colombier static void AST_setcur(Lextok *);
100312a1df1SDavid du Colombier static void check_slice(Lextok *, int);
101312a1df1SDavid du Colombier static void curtail(AST *);
102312a1df1SDavid du Colombier static void def_use(Lextok *, int);
103312a1df1SDavid du Colombier static void name_AST_track(Lextok *, int);
104312a1df1SDavid du Colombier static void show_expl(void);
105312a1df1SDavid du Colombier
106312a1df1SDavid du Colombier static int
AST_isini(Lextok * n)107312a1df1SDavid du Colombier AST_isini(Lextok *n) /* is this an initialized channel */
108312a1df1SDavid du Colombier { Symbol *s;
109312a1df1SDavid du Colombier
110312a1df1SDavid du Colombier if (!n || !n->sym) return 0;
111312a1df1SDavid du Colombier
112312a1df1SDavid du Colombier s = n->sym;
113312a1df1SDavid du Colombier
114312a1df1SDavid du Colombier if (s->type == CHAN)
115312a1df1SDavid du Colombier return (s->ini->ntyp == CHAN); /* freshly instantiated */
116312a1df1SDavid du Colombier
117312a1df1SDavid du Colombier if (s->type == STRUCT && n->rgt)
118312a1df1SDavid du Colombier return AST_isini(n->rgt->lft);
119312a1df1SDavid du Colombier
120312a1df1SDavid du Colombier return 0;
121312a1df1SDavid du Colombier }
122312a1df1SDavid du Colombier
123312a1df1SDavid du Colombier static void
AST_var(Lextok * n,Symbol * s,int toplevel)124312a1df1SDavid du Colombier AST_var(Lextok *n, Symbol *s, int toplevel)
125312a1df1SDavid du Colombier {
126312a1df1SDavid du Colombier if (!s) return;
127312a1df1SDavid du Colombier
128312a1df1SDavid du Colombier if (toplevel)
129312a1df1SDavid du Colombier { if (s->context && s->type)
130312a1df1SDavid du Colombier printf(":%s:L:", s->context->name);
131312a1df1SDavid du Colombier else
132312a1df1SDavid du Colombier printf("G:");
133312a1df1SDavid du Colombier }
134312a1df1SDavid du Colombier printf("%s", s->name); /* array indices ignored */
135312a1df1SDavid du Colombier
136312a1df1SDavid du Colombier if (s->type == STRUCT && n && n->rgt && n->rgt->lft)
137312a1df1SDavid du Colombier { printf(":");
138312a1df1SDavid du Colombier AST_var(n->rgt->lft, n->rgt->lft->sym, 0);
139312a1df1SDavid du Colombier }
140312a1df1SDavid du Colombier }
141312a1df1SDavid du Colombier
142312a1df1SDavid du Colombier static void
name_def_indices(Lextok * n,int code)143312a1df1SDavid du Colombier name_def_indices(Lextok *n, int code)
144312a1df1SDavid du Colombier {
145312a1df1SDavid du Colombier if (!n || !n->sym) return;
146312a1df1SDavid du Colombier
147*00d97012SDavid du Colombier if (n->sym->nel > 1 || n->sym->isarray)
148312a1df1SDavid du Colombier def_use(n->lft, code); /* process the index */
149312a1df1SDavid du Colombier
150312a1df1SDavid du Colombier if (n->sym->type == STRUCT /* and possible deeper ones */
151312a1df1SDavid du Colombier && n->rgt)
152312a1df1SDavid du Colombier name_def_indices(n->rgt->lft, code);
153312a1df1SDavid du Colombier }
154312a1df1SDavid du Colombier
155312a1df1SDavid du Colombier static void
name_def_use(Lextok * n,int code)156312a1df1SDavid du Colombier name_def_use(Lextok *n, int code)
157312a1df1SDavid du Colombier { FSM_use *u;
158312a1df1SDavid du Colombier
159312a1df1SDavid du Colombier if (!n) return;
160312a1df1SDavid du Colombier
161312a1df1SDavid du Colombier if ((code&USE)
162312a1df1SDavid du Colombier && cur_t->step
163312a1df1SDavid du Colombier && cur_t->step->n)
164312a1df1SDavid du Colombier { switch (cur_t->step->n->ntyp) {
165312a1df1SDavid du Colombier case 'c': /* possible predicate abstraction? */
166312a1df1SDavid du Colombier n->sym->colnr |= 2; /* yes */
167312a1df1SDavid du Colombier break;
168312a1df1SDavid du Colombier default:
169312a1df1SDavid du Colombier n->sym->colnr |= 1; /* no */
170312a1df1SDavid du Colombier break;
171312a1df1SDavid du Colombier }
172312a1df1SDavid du Colombier }
173312a1df1SDavid du Colombier
174312a1df1SDavid du Colombier for (u = cur_t->Val[0]; u; u = u->nxt)
175312a1df1SDavid du Colombier if (AST_mutual(n, u->n, 1)
176312a1df1SDavid du Colombier && u->special == code)
177312a1df1SDavid du Colombier return;
178312a1df1SDavid du Colombier
179312a1df1SDavid du Colombier if (use_free)
180312a1df1SDavid du Colombier { u = use_free;
181312a1df1SDavid du Colombier use_free = use_free->nxt;
182312a1df1SDavid du Colombier } else
183312a1df1SDavid du Colombier u = (FSM_use *) emalloc(sizeof(FSM_use));
184312a1df1SDavid du Colombier
185312a1df1SDavid du Colombier u->n = n;
186312a1df1SDavid du Colombier u->special = code;
187312a1df1SDavid du Colombier u->nxt = cur_t->Val[0];
188312a1df1SDavid du Colombier cur_t->Val[0] = u;
189312a1df1SDavid du Colombier
190312a1df1SDavid du Colombier name_def_indices(n, USE|(code&(~DEF))); /* not def, but perhaps deref */
191312a1df1SDavid du Colombier }
192312a1df1SDavid du Colombier
193312a1df1SDavid du Colombier static void
def_use(Lextok * now,int code)194312a1df1SDavid du Colombier def_use(Lextok *now, int code)
195312a1df1SDavid du Colombier { Lextok *v;
196312a1df1SDavid du Colombier
197312a1df1SDavid du Colombier if (now)
198312a1df1SDavid du Colombier switch (now->ntyp) {
199312a1df1SDavid du Colombier case '!':
200312a1df1SDavid du Colombier case UMIN:
201312a1df1SDavid du Colombier case '~':
202312a1df1SDavid du Colombier case 'c':
203312a1df1SDavid du Colombier case ENABLED:
204312a1df1SDavid du Colombier case ASSERT:
205312a1df1SDavid du Colombier case EVAL:
206312a1df1SDavid du Colombier def_use(now->lft, USE|code);
207312a1df1SDavid du Colombier break;
208312a1df1SDavid du Colombier
209312a1df1SDavid du Colombier case LEN:
210312a1df1SDavid du Colombier case FULL:
211312a1df1SDavid du Colombier case EMPTY:
212312a1df1SDavid du Colombier case NFULL:
213312a1df1SDavid du Colombier case NEMPTY:
214312a1df1SDavid du Colombier def_use(now->lft, DEREF_USE|USE|code);
215312a1df1SDavid du Colombier break;
216312a1df1SDavid du Colombier
217312a1df1SDavid du Colombier case '/':
218312a1df1SDavid du Colombier case '*':
219312a1df1SDavid du Colombier case '-':
220312a1df1SDavid du Colombier case '+':
221312a1df1SDavid du Colombier case '%':
222312a1df1SDavid du Colombier case '&':
223312a1df1SDavid du Colombier case '^':
224312a1df1SDavid du Colombier case '|':
225312a1df1SDavid du Colombier case LE:
226312a1df1SDavid du Colombier case GE:
227312a1df1SDavid du Colombier case GT:
228312a1df1SDavid du Colombier case LT:
229312a1df1SDavid du Colombier case NE:
230312a1df1SDavid du Colombier case EQ:
231312a1df1SDavid du Colombier case OR:
232312a1df1SDavid du Colombier case AND:
233312a1df1SDavid du Colombier case LSHIFT:
234312a1df1SDavid du Colombier case RSHIFT:
235312a1df1SDavid du Colombier def_use(now->lft, USE|code);
236312a1df1SDavid du Colombier def_use(now->rgt, USE|code);
237312a1df1SDavid du Colombier break;
238312a1df1SDavid du Colombier
239312a1df1SDavid du Colombier case ASGN:
240312a1df1SDavid du Colombier def_use(now->lft, DEF|code);
241312a1df1SDavid du Colombier def_use(now->rgt, USE|code);
242312a1df1SDavid du Colombier break;
243312a1df1SDavid du Colombier
244312a1df1SDavid du Colombier case TYPE: /* name in parameter list */
245312a1df1SDavid du Colombier name_def_use(now, code);
246312a1df1SDavid du Colombier break;
247312a1df1SDavid du Colombier
248312a1df1SDavid du Colombier case NAME:
249312a1df1SDavid du Colombier name_def_use(now, code);
250312a1df1SDavid du Colombier break;
251312a1df1SDavid du Colombier
252312a1df1SDavid du Colombier case RUN:
253312a1df1SDavid du Colombier name_def_use(now, USE); /* procname - not really needed */
254312a1df1SDavid du Colombier for (v = now->lft; v; v = v->rgt)
255312a1df1SDavid du Colombier def_use(v->lft, USE); /* params */
256312a1df1SDavid du Colombier break;
257312a1df1SDavid du Colombier
258312a1df1SDavid du Colombier case 's':
259312a1df1SDavid du Colombier def_use(now->lft, DEREF_DEF|DEREF_USE|USE|code);
260312a1df1SDavid du Colombier for (v = now->rgt; v; v = v->rgt)
261312a1df1SDavid du Colombier def_use(v->lft, USE|code);
262312a1df1SDavid du Colombier break;
263312a1df1SDavid du Colombier
264312a1df1SDavid du Colombier case 'r':
265312a1df1SDavid du Colombier def_use(now->lft, DEREF_DEF|DEREF_USE|USE|code);
266312a1df1SDavid du Colombier for (v = now->rgt; v; v = v->rgt)
267312a1df1SDavid du Colombier { if (v->lft->ntyp == EVAL)
268312a1df1SDavid du Colombier def_use(v->lft, code); /* will add USE */
269312a1df1SDavid du Colombier else if (v->lft->ntyp != CONST)
270312a1df1SDavid du Colombier def_use(v->lft, DEF|code);
271312a1df1SDavid du Colombier }
272312a1df1SDavid du Colombier break;
273312a1df1SDavid du Colombier
274312a1df1SDavid du Colombier case 'R':
275312a1df1SDavid du Colombier def_use(now->lft, DEREF_USE|USE|code);
276312a1df1SDavid du Colombier for (v = now->rgt; v; v = v->rgt)
277312a1df1SDavid du Colombier { if (v->lft->ntyp == EVAL)
278312a1df1SDavid du Colombier def_use(v->lft, code); /* will add USE */
279312a1df1SDavid du Colombier }
280312a1df1SDavid du Colombier break;
281312a1df1SDavid du Colombier
282312a1df1SDavid du Colombier case '?':
283312a1df1SDavid du Colombier def_use(now->lft, USE|code);
284312a1df1SDavid du Colombier if (now->rgt)
285312a1df1SDavid du Colombier { def_use(now->rgt->lft, code);
286312a1df1SDavid du Colombier def_use(now->rgt->rgt, code);
287312a1df1SDavid du Colombier }
288312a1df1SDavid du Colombier break;
289312a1df1SDavid du Colombier
290312a1df1SDavid du Colombier case PRINT:
291312a1df1SDavid du Colombier for (v = now->lft; v; v = v->rgt)
292312a1df1SDavid du Colombier def_use(v->lft, USE|code);
293312a1df1SDavid du Colombier break;
294312a1df1SDavid du Colombier
295312a1df1SDavid du Colombier case PRINTM:
296312a1df1SDavid du Colombier def_use(now->lft, USE);
297312a1df1SDavid du Colombier break;
298312a1df1SDavid du Colombier
299312a1df1SDavid du Colombier case CONST:
300312a1df1SDavid du Colombier case ELSE: /* ? */
301312a1df1SDavid du Colombier case NONPROGRESS:
302312a1df1SDavid du Colombier case PC_VAL:
303312a1df1SDavid du Colombier case 'p':
304312a1df1SDavid du Colombier case 'q':
305312a1df1SDavid du Colombier break;
306312a1df1SDavid du Colombier
307312a1df1SDavid du Colombier case '.':
308312a1df1SDavid du Colombier case GOTO:
309312a1df1SDavid du Colombier case BREAK:
310312a1df1SDavid du Colombier case '@':
311312a1df1SDavid du Colombier case D_STEP:
312312a1df1SDavid du Colombier case ATOMIC:
313312a1df1SDavid du Colombier case NON_ATOMIC:
314312a1df1SDavid du Colombier case IF:
315312a1df1SDavid du Colombier case DO:
316312a1df1SDavid du Colombier case UNLESS:
317312a1df1SDavid du Colombier case TIMEOUT:
318312a1df1SDavid du Colombier case C_CODE:
319312a1df1SDavid du Colombier case C_EXPR:
320312a1df1SDavid du Colombier default:
321312a1df1SDavid du Colombier break;
322312a1df1SDavid du Colombier }
323312a1df1SDavid du Colombier }
324312a1df1SDavid du Colombier
325312a1df1SDavid du Colombier static int
AST_add_alias(Lextok * n,int nr)326312a1df1SDavid du Colombier AST_add_alias(Lextok *n, int nr)
327312a1df1SDavid du Colombier { ALIAS *ca;
328312a1df1SDavid du Colombier int res;
329312a1df1SDavid du Colombier
330312a1df1SDavid du Colombier for (ca = chalcur->alias; ca; ca = ca->nxt)
331312a1df1SDavid du Colombier if (AST_mutual(ca->cnm, n, 1))
332312a1df1SDavid du Colombier { res = (ca->origin&nr);
333312a1df1SDavid du Colombier ca->origin |= nr; /* 1, 2, or 4 - run, asgn, or rcv */
334312a1df1SDavid du Colombier return (res == 0); /* 0 if already there with same origin */
335312a1df1SDavid du Colombier }
336312a1df1SDavid du Colombier
337312a1df1SDavid du Colombier ca = (ALIAS *) emalloc(sizeof(ALIAS));
338312a1df1SDavid du Colombier ca->cnm = n;
339312a1df1SDavid du Colombier ca->origin = nr;
340312a1df1SDavid du Colombier ca->nxt = chalcur->alias;
341312a1df1SDavid du Colombier chalcur->alias = ca;
342312a1df1SDavid du Colombier return 1;
343312a1df1SDavid du Colombier }
344312a1df1SDavid du Colombier
345312a1df1SDavid du Colombier static void
AST_run_alias(char * pn,char * s,Lextok * t,int parno)346312a1df1SDavid du Colombier AST_run_alias(char *pn, char *s, Lextok *t, int parno)
347312a1df1SDavid du Colombier { Lextok *v;
348312a1df1SDavid du Colombier int cnt;
349312a1df1SDavid du Colombier
350312a1df1SDavid du Colombier if (!t) return;
351312a1df1SDavid du Colombier
352312a1df1SDavid du Colombier if (t->ntyp == RUN)
353312a1df1SDavid du Colombier { if (strcmp(t->sym->name, s) == 0)
354312a1df1SDavid du Colombier for (v = t->lft, cnt = 1; v; v = v->rgt, cnt++)
355312a1df1SDavid du Colombier if (cnt == parno)
356312a1df1SDavid du Colombier { AST_add_alias(v->lft, 1); /* RUN */
357312a1df1SDavid du Colombier break;
358312a1df1SDavid du Colombier }
359312a1df1SDavid du Colombier } else
360312a1df1SDavid du Colombier { AST_run_alias(pn, s, t->lft, parno);
361312a1df1SDavid du Colombier AST_run_alias(pn, s, t->rgt, parno);
362312a1df1SDavid du Colombier }
363312a1df1SDavid du Colombier }
364312a1df1SDavid du Colombier
365312a1df1SDavid du Colombier static void
AST_findrun(char * s,int parno)366312a1df1SDavid du Colombier AST_findrun(char *s, int parno)
367312a1df1SDavid du Colombier { FSM_state *f;
368312a1df1SDavid du Colombier FSM_trans *t;
369312a1df1SDavid du Colombier AST *a;
370312a1df1SDavid du Colombier
371312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt) /* automata */
372312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt) /* control states */
373312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt) /* transitions */
374312a1df1SDavid du Colombier { if (t->step)
375312a1df1SDavid du Colombier AST_run_alias(a->p->n->name, s, t->step->n, parno);
376312a1df1SDavid du Colombier }
377312a1df1SDavid du Colombier }
378312a1df1SDavid du Colombier
379312a1df1SDavid du Colombier static void
AST_par_chans(ProcList * p)380312a1df1SDavid du Colombier AST_par_chans(ProcList *p) /* find local chan's init'd to chan passed as param */
381312a1df1SDavid du Colombier { Ordered *walk;
382312a1df1SDavid du Colombier Symbol *sp;
383312a1df1SDavid du Colombier
384312a1df1SDavid du Colombier for (walk = all_names; walk; walk = walk->next)
385312a1df1SDavid du Colombier { sp = walk->entry;
386312a1df1SDavid du Colombier if (sp
387312a1df1SDavid du Colombier && sp->context
388312a1df1SDavid du Colombier && strcmp(sp->context->name, p->n->name) == 0
389312a1df1SDavid du Colombier && sp->Nid >= 0 /* not itself a param */
390312a1df1SDavid du Colombier && sp->type == CHAN
391312a1df1SDavid du Colombier && sp->ini->ntyp == NAME) /* != CONST and != CHAN */
392312a1df1SDavid du Colombier { Lextok *x = nn(ZN, 0, ZN, ZN);
393312a1df1SDavid du Colombier x->sym = sp;
394312a1df1SDavid du Colombier AST_setcur(x);
395312a1df1SDavid du Colombier AST_add_alias(sp->ini, 2); /* ASGN */
396312a1df1SDavid du Colombier } }
397312a1df1SDavid du Colombier }
398312a1df1SDavid du Colombier
399312a1df1SDavid du Colombier static void
AST_para(ProcList * p)400312a1df1SDavid du Colombier AST_para(ProcList *p)
401312a1df1SDavid du Colombier { Lextok *f, *t, *c;
402312a1df1SDavid du Colombier int cnt = 0;
403312a1df1SDavid du Colombier
404312a1df1SDavid du Colombier AST_par_chans(p);
405312a1df1SDavid du Colombier
406312a1df1SDavid du Colombier for (f = p->p; f; f = f->rgt) /* list of types */
407312a1df1SDavid du Colombier for (t = f->lft; t; t = t->rgt)
408312a1df1SDavid du Colombier { if (t->ntyp != ',')
409312a1df1SDavid du Colombier c = t;
410312a1df1SDavid du Colombier else
411312a1df1SDavid du Colombier c = t->lft; /* expanded struct */
412312a1df1SDavid du Colombier
413312a1df1SDavid du Colombier cnt++;
414312a1df1SDavid du Colombier if (Sym_typ(c) == CHAN)
415312a1df1SDavid du Colombier { ALIAS *na = (ALIAS *) emalloc(sizeof(ALIAS));
416312a1df1SDavid du Colombier
417312a1df1SDavid du Colombier na->cnm = c;
418312a1df1SDavid du Colombier na->nxt = chalias;
419312a1df1SDavid du Colombier chalcur = chalias = na;
420312a1df1SDavid du Colombier #if 0
421312a1df1SDavid du Colombier printf("%s -- (par) -- ", p->n->name);
422312a1df1SDavid du Colombier AST_var(c, c->sym, 1);
423312a1df1SDavid du Colombier printf(" => <<");
424312a1df1SDavid du Colombier #endif
425312a1df1SDavid du Colombier AST_findrun(p->n->name, cnt);
426312a1df1SDavid du Colombier #if 0
427312a1df1SDavid du Colombier printf(">>\n");
428312a1df1SDavid du Colombier #endif
429312a1df1SDavid du Colombier }
430312a1df1SDavid du Colombier }
431312a1df1SDavid du Colombier }
432312a1df1SDavid du Colombier
433312a1df1SDavid du Colombier static void
AST_haschan(Lextok * c)434312a1df1SDavid du Colombier AST_haschan(Lextok *c)
435312a1df1SDavid du Colombier {
436312a1df1SDavid du Colombier if (!c) return;
437312a1df1SDavid du Colombier if (Sym_typ(c) == CHAN)
438312a1df1SDavid du Colombier { AST_add_alias(c, 2); /* ASGN */
439312a1df1SDavid du Colombier #if 0
440312a1df1SDavid du Colombier printf("<<");
441312a1df1SDavid du Colombier AST_var(c, c->sym, 1);
442312a1df1SDavid du Colombier printf(">>\n");
443312a1df1SDavid du Colombier #endif
444312a1df1SDavid du Colombier } else
445312a1df1SDavid du Colombier { AST_haschan(c->rgt);
446312a1df1SDavid du Colombier AST_haschan(c->lft);
447312a1df1SDavid du Colombier }
448312a1df1SDavid du Colombier }
449312a1df1SDavid du Colombier
450312a1df1SDavid du Colombier static int
AST_nrpar(Lextok * n)451312a1df1SDavid du Colombier AST_nrpar(Lextok *n) /* 's' or 'r' */
452312a1df1SDavid du Colombier { Lextok *m;
453312a1df1SDavid du Colombier int j = 0;
454312a1df1SDavid du Colombier
455312a1df1SDavid du Colombier for (m = n->rgt; m; m = m->rgt)
456312a1df1SDavid du Colombier j++;
457312a1df1SDavid du Colombier return j;
458312a1df1SDavid du Colombier }
459312a1df1SDavid du Colombier
460312a1df1SDavid du Colombier static int
AST_ord(Lextok * n,Lextok * s)461312a1df1SDavid du Colombier AST_ord(Lextok *n, Lextok *s)
462312a1df1SDavid du Colombier { Lextok *m;
463312a1df1SDavid du Colombier int j = 0;
464312a1df1SDavid du Colombier
465312a1df1SDavid du Colombier for (m = n->rgt; m; m = m->rgt)
466312a1df1SDavid du Colombier { j++;
467312a1df1SDavid du Colombier if (s->sym == m->lft->sym)
468312a1df1SDavid du Colombier return j;
469312a1df1SDavid du Colombier }
470312a1df1SDavid du Colombier return 0;
471312a1df1SDavid du Colombier }
472312a1df1SDavid du Colombier
473312a1df1SDavid du Colombier #if 0
474312a1df1SDavid du Colombier static void
475312a1df1SDavid du Colombier AST_ownership(Symbol *s)
476312a1df1SDavid du Colombier {
477312a1df1SDavid du Colombier if (!s) return;
478312a1df1SDavid du Colombier printf("%s:", s->name);
479312a1df1SDavid du Colombier AST_ownership(s->owner);
480312a1df1SDavid du Colombier }
481312a1df1SDavid du Colombier #endif
482312a1df1SDavid du Colombier
483312a1df1SDavid du Colombier static int
AST_mutual(Lextok * a,Lextok * b,int toplevel)484312a1df1SDavid du Colombier AST_mutual(Lextok *a, Lextok *b, int toplevel)
485312a1df1SDavid du Colombier { Symbol *as, *bs;
486312a1df1SDavid du Colombier
487312a1df1SDavid du Colombier if (!a && !b) return 1;
488312a1df1SDavid du Colombier
489312a1df1SDavid du Colombier if (!a || !b) return 0;
490312a1df1SDavid du Colombier
491312a1df1SDavid du Colombier as = a->sym;
492312a1df1SDavid du Colombier bs = b->sym;
493312a1df1SDavid du Colombier
494312a1df1SDavid du Colombier if (!as || !bs) return 0;
495312a1df1SDavid du Colombier
496312a1df1SDavid du Colombier if (toplevel && as->context != bs->context)
497312a1df1SDavid du Colombier return 0;
498312a1df1SDavid du Colombier
499312a1df1SDavid du Colombier if (as->type != bs->type)
500312a1df1SDavid du Colombier return 0;
501312a1df1SDavid du Colombier
502312a1df1SDavid du Colombier if (strcmp(as->name, bs->name) != 0)
503312a1df1SDavid du Colombier return 0;
504312a1df1SDavid du Colombier
505*00d97012SDavid du Colombier if (as->type == STRUCT && a->rgt && b->rgt) /* we know that a and b are not null */
506312a1df1SDavid du Colombier return AST_mutual(a->rgt->lft, b->rgt->lft, 0);
507312a1df1SDavid du Colombier
508312a1df1SDavid du Colombier return 1;
509312a1df1SDavid du Colombier }
510312a1df1SDavid du Colombier
511312a1df1SDavid du Colombier static void
AST_setcur(Lextok * n)512312a1df1SDavid du Colombier AST_setcur(Lextok *n) /* set chalcur */
513312a1df1SDavid du Colombier { ALIAS *ca;
514312a1df1SDavid du Colombier
515312a1df1SDavid du Colombier for (ca = chalias; ca; ca = ca->nxt)
516312a1df1SDavid du Colombier if (AST_mutual(ca->cnm, n, 1)) /* if same chan */
517312a1df1SDavid du Colombier { chalcur = ca;
518312a1df1SDavid du Colombier return;
519312a1df1SDavid du Colombier }
520312a1df1SDavid du Colombier
521312a1df1SDavid du Colombier ca = (ALIAS *) emalloc(sizeof(ALIAS));
522312a1df1SDavid du Colombier ca->cnm = n;
523312a1df1SDavid du Colombier ca->nxt = chalias;
524312a1df1SDavid du Colombier chalcur = chalias = ca;
525312a1df1SDavid du Colombier }
526312a1df1SDavid du Colombier
527312a1df1SDavid du Colombier static void
AST_other(AST * a)528312a1df1SDavid du Colombier AST_other(AST *a) /* check chan params in asgns and recvs */
529312a1df1SDavid du Colombier { FSM_state *f;
530312a1df1SDavid du Colombier FSM_trans *t;
531312a1df1SDavid du Colombier FSM_use *u;
532312a1df1SDavid du Colombier ChanList *cl;
533312a1df1SDavid du Colombier
534312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt) /* control states */
535312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt) /* transitions */
536312a1df1SDavid du Colombier for (u = t->Val[0]; u; u = u->nxt) /* def/use info */
537312a1df1SDavid du Colombier if (Sym_typ(u->n) == CHAN
538312a1df1SDavid du Colombier && (u->special&DEF)) /* def of chan-name */
539312a1df1SDavid du Colombier { AST_setcur(u->n);
540312a1df1SDavid du Colombier switch (t->step->n->ntyp) {
541312a1df1SDavid du Colombier case ASGN:
542312a1df1SDavid du Colombier AST_haschan(t->step->n->rgt);
543312a1df1SDavid du Colombier break;
544312a1df1SDavid du Colombier case 'r':
545312a1df1SDavid du Colombier /* guess sends where name may originate */
546312a1df1SDavid du Colombier for (cl = chanlist; cl; cl = cl->nxt) /* all sends */
547*00d97012SDavid du Colombier { int aa = AST_nrpar(cl->s);
548*00d97012SDavid du Colombier int bb = AST_nrpar(t->step->n);
549*00d97012SDavid du Colombier if (aa != bb) /* matching nrs of params */
550312a1df1SDavid du Colombier continue;
551312a1df1SDavid du Colombier
552*00d97012SDavid du Colombier aa = AST_ord(cl->s, cl->n);
553*00d97012SDavid du Colombier bb = AST_ord(t->step->n, u->n);
554*00d97012SDavid du Colombier if (aa != bb) /* same position in parlist */
555312a1df1SDavid du Colombier continue;
556312a1df1SDavid du Colombier
557312a1df1SDavid du Colombier AST_add_alias(cl->n, 4); /* RCV assume possible match */
558312a1df1SDavid du Colombier }
559312a1df1SDavid du Colombier break;
560312a1df1SDavid du Colombier default:
561312a1df1SDavid du Colombier printf("type = %d\n", t->step->n->ntyp);
562312a1df1SDavid du Colombier non_fatal("unexpected chan def type", (char *) 0);
563312a1df1SDavid du Colombier break;
564312a1df1SDavid du Colombier } }
565312a1df1SDavid du Colombier }
566312a1df1SDavid du Colombier
567312a1df1SDavid du Colombier static void
AST_aliases(void)568312a1df1SDavid du Colombier AST_aliases(void)
569312a1df1SDavid du Colombier { ALIAS *na, *ca;
570312a1df1SDavid du Colombier
571312a1df1SDavid du Colombier for (na = chalias; na; na = na->nxt)
572312a1df1SDavid du Colombier { printf("\npossible aliases of ");
573312a1df1SDavid du Colombier AST_var(na->cnm, na->cnm->sym, 1);
574312a1df1SDavid du Colombier printf("\n\t");
575312a1df1SDavid du Colombier for (ca = na->alias; ca; ca = ca->nxt)
576312a1df1SDavid du Colombier { if (!ca->cnm->sym)
577312a1df1SDavid du Colombier printf("no valid name ");
578312a1df1SDavid du Colombier else
579312a1df1SDavid du Colombier AST_var(ca->cnm, ca->cnm->sym, 1);
580312a1df1SDavid du Colombier printf("<");
581312a1df1SDavid du Colombier if (ca->origin & 1) printf("RUN ");
582312a1df1SDavid du Colombier if (ca->origin & 2) printf("ASGN ");
583312a1df1SDavid du Colombier if (ca->origin & 4) printf("RCV ");
584312a1df1SDavid du Colombier printf("[%s]", AST_isini(ca->cnm)?"Initzd":"Name");
585312a1df1SDavid du Colombier printf(">");
586312a1df1SDavid du Colombier if (ca->nxt) printf(", ");
587312a1df1SDavid du Colombier }
588312a1df1SDavid du Colombier printf("\n");
589312a1df1SDavid du Colombier }
590312a1df1SDavid du Colombier printf("\n");
591312a1df1SDavid du Colombier }
592312a1df1SDavid du Colombier
593312a1df1SDavid du Colombier static void
AST_indirect(FSM_use * uin,FSM_trans * t,char * cause,char * pn)594312a1df1SDavid du Colombier AST_indirect(FSM_use *uin, FSM_trans *t, char *cause, char *pn)
595312a1df1SDavid du Colombier { FSM_use *u;
596312a1df1SDavid du Colombier
597312a1df1SDavid du Colombier /* this is a newly discovered relevant statement */
598312a1df1SDavid du Colombier /* all vars it uses to contribute to its DEF are new criteria */
599312a1df1SDavid du Colombier
600312a1df1SDavid du Colombier if (!(t->relevant&1)) AST_Changes++;
601312a1df1SDavid du Colombier
602312a1df1SDavid du Colombier t->round = AST_Round;
603312a1df1SDavid du Colombier t->relevant = 1;
604312a1df1SDavid du Colombier
605312a1df1SDavid du Colombier if ((verbose&32) && t->step)
606312a1df1SDavid du Colombier { printf("\tDR %s [[ ", pn);
607312a1df1SDavid du Colombier comment(stdout, t->step->n, 0);
608312a1df1SDavid du Colombier printf("]]\n\t\tfully relevant %s", cause);
609312a1df1SDavid du Colombier if (uin) { printf(" due to "); AST_var(uin->n, uin->n->sym, 1); }
610312a1df1SDavid du Colombier printf("\n");
611312a1df1SDavid du Colombier }
612312a1df1SDavid du Colombier for (u = t->Val[0]; u; u = u->nxt)
613312a1df1SDavid du Colombier if (u != uin
614312a1df1SDavid du Colombier && (u->special&(USE|DEREF_USE)))
615312a1df1SDavid du Colombier { if (verbose&32)
616312a1df1SDavid du Colombier { printf("\t\t\tuses(%d): ", u->special);
617312a1df1SDavid du Colombier AST_var(u->n, u->n->sym, 1);
618312a1df1SDavid du Colombier printf("\n");
619312a1df1SDavid du Colombier }
620312a1df1SDavid du Colombier name_AST_track(u->n, u->special); /* add to slice criteria */
621312a1df1SDavid du Colombier }
622312a1df1SDavid du Colombier }
623312a1df1SDavid du Colombier
624312a1df1SDavid du Colombier static void
def_relevant(char * pn,FSM_trans * t,Lextok * n,int ischan)625312a1df1SDavid du Colombier def_relevant(char *pn, FSM_trans *t, Lextok *n, int ischan)
626312a1df1SDavid du Colombier { FSM_use *u;
627312a1df1SDavid du Colombier ALIAS *na, *ca;
628312a1df1SDavid du Colombier int chanref;
629312a1df1SDavid du Colombier
630312a1df1SDavid du Colombier /* look for all DEF's of n
631312a1df1SDavid du Colombier * mark those stmnts relevant
632312a1df1SDavid du Colombier * mark all var USEs in those stmnts as criteria
633312a1df1SDavid du Colombier */
634312a1df1SDavid du Colombier
635312a1df1SDavid du Colombier if (n->ntyp != ELSE)
636312a1df1SDavid du Colombier for (u = t->Val[0]; u; u = u->nxt)
637312a1df1SDavid du Colombier { chanref = (Sym_typ(u->n) == CHAN);
638312a1df1SDavid du Colombier
639312a1df1SDavid du Colombier if (ischan != chanref /* no possible match */
640312a1df1SDavid du Colombier || !(u->special&(DEF|DEREF_DEF))) /* not a def */
641312a1df1SDavid du Colombier continue;
642312a1df1SDavid du Colombier
643312a1df1SDavid du Colombier if (AST_mutual(u->n, n, 1))
644312a1df1SDavid du Colombier { AST_indirect(u, t, "(exact match)", pn);
645312a1df1SDavid du Colombier continue;
646312a1df1SDavid du Colombier }
647312a1df1SDavid du Colombier
648312a1df1SDavid du Colombier if (chanref)
649312a1df1SDavid du Colombier for (na = chalias; na; na = na->nxt)
650312a1df1SDavid du Colombier { if (!AST_mutual(u->n, na->cnm, 1))
651312a1df1SDavid du Colombier continue;
652312a1df1SDavid du Colombier for (ca = na->alias; ca; ca = ca->nxt)
653312a1df1SDavid du Colombier if (AST_mutual(ca->cnm, n, 1)
654312a1df1SDavid du Colombier && AST_isini(ca->cnm))
655312a1df1SDavid du Colombier { AST_indirect(u, t, "(alias match)", pn);
656312a1df1SDavid du Colombier break;
657312a1df1SDavid du Colombier }
658312a1df1SDavid du Colombier if (ca) break;
659312a1df1SDavid du Colombier } }
660312a1df1SDavid du Colombier }
661312a1df1SDavid du Colombier
662312a1df1SDavid du Colombier static void
AST_relevant(Lextok * n)663312a1df1SDavid du Colombier AST_relevant(Lextok *n)
664312a1df1SDavid du Colombier { AST *a;
665312a1df1SDavid du Colombier FSM_state *f;
666312a1df1SDavid du Colombier FSM_trans *t;
667312a1df1SDavid du Colombier int ischan;
668312a1df1SDavid du Colombier
669312a1df1SDavid du Colombier /* look for all DEF's of n
670312a1df1SDavid du Colombier * mark those stmnts relevant
671312a1df1SDavid du Colombier * mark all var USEs in those stmnts as criteria
672312a1df1SDavid du Colombier */
673312a1df1SDavid du Colombier
674312a1df1SDavid du Colombier if (!n) return;
675312a1df1SDavid du Colombier ischan = (Sym_typ(n) == CHAN);
676312a1df1SDavid du Colombier
677312a1df1SDavid du Colombier if (verbose&32)
678312a1df1SDavid du Colombier { printf("<<ast_relevant (ntyp=%d) ", n->ntyp);
679312a1df1SDavid du Colombier AST_var(n, n->sym, 1);
680312a1df1SDavid du Colombier printf(">>\n");
681312a1df1SDavid du Colombier }
682312a1df1SDavid du Colombier
683312a1df1SDavid du Colombier for (t = expl_par; t; t = t->nxt) /* param assignments */
684312a1df1SDavid du Colombier { if (!(t->relevant&1))
685312a1df1SDavid du Colombier def_relevant(":params:", t, n, ischan);
686312a1df1SDavid du Colombier }
687312a1df1SDavid du Colombier
688312a1df1SDavid du Colombier for (t = expl_var; t; t = t->nxt)
689312a1df1SDavid du Colombier { if (!(t->relevant&1)) /* var inits */
690312a1df1SDavid du Colombier def_relevant(":vars:", t, n, ischan);
691312a1df1SDavid du Colombier }
692312a1df1SDavid du Colombier
693312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt) /* all other stmnts */
694*00d97012SDavid du Colombier { if (a->p->b != N_CLAIM && a->p->b != E_TRACE && a->p->b != N_TRACE)
695312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
696312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
697312a1df1SDavid du Colombier { if (!(t->relevant&1))
698312a1df1SDavid du Colombier def_relevant(a->p->n->name, t, n, ischan);
699312a1df1SDavid du Colombier } }
700312a1df1SDavid du Colombier }
701312a1df1SDavid du Colombier
702312a1df1SDavid du Colombier static int
AST_relpar(char * s)703312a1df1SDavid du Colombier AST_relpar(char *s)
704312a1df1SDavid du Colombier { FSM_trans *t, *T;
705312a1df1SDavid du Colombier FSM_use *u;
706312a1df1SDavid du Colombier
707312a1df1SDavid du Colombier for (T = expl_par; T; T = (T == expl_par)?expl_var: (FSM_trans *) 0)
708312a1df1SDavid du Colombier for (t = T; t; t = t->nxt)
709312a1df1SDavid du Colombier { if (t->relevant&1)
710312a1df1SDavid du Colombier for (u = t->Val[0]; u; u = u->nxt)
711312a1df1SDavid du Colombier { if (u->n->sym->type
712312a1df1SDavid du Colombier && u->n->sym->context
713312a1df1SDavid du Colombier && strcmp(u->n->sym->context->name, s) == 0)
714312a1df1SDavid du Colombier {
715312a1df1SDavid du Colombier if (verbose&32)
716312a1df1SDavid du Colombier { printf("proctype %s relevant, due to symbol ", s);
717312a1df1SDavid du Colombier AST_var(u->n, u->n->sym, 1);
718312a1df1SDavid du Colombier printf("\n");
719312a1df1SDavid du Colombier }
720312a1df1SDavid du Colombier return 1;
721312a1df1SDavid du Colombier } } }
722312a1df1SDavid du Colombier return 0;
723312a1df1SDavid du Colombier }
724312a1df1SDavid du Colombier
725312a1df1SDavid du Colombier static void
AST_dorelevant(void)726312a1df1SDavid du Colombier AST_dorelevant(void)
727312a1df1SDavid du Colombier { AST *a;
728312a1df1SDavid du Colombier RPN *r;
729312a1df1SDavid du Colombier
730312a1df1SDavid du Colombier for (r = rpn; r; r = r->nxt)
731312a1df1SDavid du Colombier { for (a = ast; a; a = a->nxt)
732312a1df1SDavid du Colombier if (strcmp(a->p->n->name, r->rn->name) == 0)
733312a1df1SDavid du Colombier { a->relevant |= 1;
734312a1df1SDavid du Colombier break;
735312a1df1SDavid du Colombier }
736312a1df1SDavid du Colombier if (!a)
737312a1df1SDavid du Colombier fatal("cannot find proctype %s", r->rn->name);
738312a1df1SDavid du Colombier }
739312a1df1SDavid du Colombier }
740312a1df1SDavid du Colombier
741312a1df1SDavid du Colombier static void
AST_procisrelevant(Symbol * s)742312a1df1SDavid du Colombier AST_procisrelevant(Symbol *s)
743312a1df1SDavid du Colombier { RPN *r;
744312a1df1SDavid du Colombier for (r = rpn; r; r = r->nxt)
745312a1df1SDavid du Colombier if (strcmp(r->rn->name, s->name) == 0)
746312a1df1SDavid du Colombier return;
747312a1df1SDavid du Colombier r = (RPN *) emalloc(sizeof(RPN));
748312a1df1SDavid du Colombier r->rn = s;
749312a1df1SDavid du Colombier r->nxt = rpn;
750312a1df1SDavid du Colombier rpn = r;
751312a1df1SDavid du Colombier }
752312a1df1SDavid du Colombier
753312a1df1SDavid du Colombier static int
AST_proc_isrel(char * s)754312a1df1SDavid du Colombier AST_proc_isrel(char *s)
755312a1df1SDavid du Colombier { AST *a;
756312a1df1SDavid du Colombier
757312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt)
758312a1df1SDavid du Colombier if (strcmp(a->p->n->name, s) == 0)
759312a1df1SDavid du Colombier return (a->relevant&1);
760312a1df1SDavid du Colombier non_fatal("cannot happen, missing proc in ast", (char *) 0);
761312a1df1SDavid du Colombier return 0;
762312a1df1SDavid du Colombier }
763312a1df1SDavid du Colombier
764312a1df1SDavid du Colombier static int
AST_scoutrun(Lextok * t)765312a1df1SDavid du Colombier AST_scoutrun(Lextok *t)
766312a1df1SDavid du Colombier {
767312a1df1SDavid du Colombier if (!t) return 0;
768312a1df1SDavid du Colombier
769312a1df1SDavid du Colombier if (t->ntyp == RUN)
770312a1df1SDavid du Colombier return AST_proc_isrel(t->sym->name);
771312a1df1SDavid du Colombier return (AST_scoutrun(t->lft) || AST_scoutrun(t->rgt));
772312a1df1SDavid du Colombier }
773312a1df1SDavid du Colombier
774312a1df1SDavid du Colombier static void
AST_tagruns(void)775312a1df1SDavid du Colombier AST_tagruns(void)
776312a1df1SDavid du Colombier { AST *a;
777312a1df1SDavid du Colombier FSM_state *f;
778312a1df1SDavid du Colombier FSM_trans *t;
779312a1df1SDavid du Colombier
780312a1df1SDavid du Colombier /* if any stmnt inside a proctype is relevant
781312a1df1SDavid du Colombier * or any parameter passed in a run
782312a1df1SDavid du Colombier * then so are all the run statements on that proctype
783312a1df1SDavid du Colombier */
784312a1df1SDavid du Colombier
785312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt)
786*00d97012SDavid du Colombier { if (a->p->b == N_CLAIM || a->p->b == I_PROC
787*00d97012SDavid du Colombier || a->p->b == E_TRACE || a->p->b == N_TRACE)
788312a1df1SDavid du Colombier { a->relevant |= 1; /* the proctype is relevant */
789312a1df1SDavid du Colombier continue;
790312a1df1SDavid du Colombier }
791312a1df1SDavid du Colombier if (AST_relpar(a->p->n->name))
792312a1df1SDavid du Colombier a->relevant |= 1;
793312a1df1SDavid du Colombier else
794312a1df1SDavid du Colombier { for (f = a->fsm; f; f = f->nxt)
795312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
796312a1df1SDavid du Colombier if (t->relevant)
797312a1df1SDavid du Colombier goto yes;
798312a1df1SDavid du Colombier yes: if (f)
799312a1df1SDavid du Colombier a->relevant |= 1;
800312a1df1SDavid du Colombier }
801312a1df1SDavid du Colombier }
802312a1df1SDavid du Colombier
803312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt)
804312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
805312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
806312a1df1SDavid du Colombier if (t->step
807312a1df1SDavid du Colombier && AST_scoutrun(t->step->n))
808312a1df1SDavid du Colombier { AST_indirect((FSM_use *)0, t, ":run:", a->p->n->name);
809312a1df1SDavid du Colombier /* BUT, not all actual params are relevant */
810312a1df1SDavid du Colombier }
811312a1df1SDavid du Colombier }
812312a1df1SDavid du Colombier
813312a1df1SDavid du Colombier static void
AST_report(AST * a,Element * e)814312a1df1SDavid du Colombier AST_report(AST *a, Element *e) /* ALSO deduce irrelevant vars */
815312a1df1SDavid du Colombier {
816312a1df1SDavid du Colombier if (!(a->relevant&2))
817312a1df1SDavid du Colombier { a->relevant |= 2;
818312a1df1SDavid du Colombier printf("spin: redundant in proctype %s (for given property):\n",
819312a1df1SDavid du Colombier a->p->n->name);
820312a1df1SDavid du Colombier }
821*00d97012SDavid du Colombier printf(" %s:%d (state %d)",
822312a1df1SDavid du Colombier e->n?e->n->fn->name:"-",
823*00d97012SDavid du Colombier e->n?e->n->ln:-1,
824312a1df1SDavid du Colombier e->seqno);
825312a1df1SDavid du Colombier printf(" [");
826312a1df1SDavid du Colombier comment(stdout, e->n, 0);
827312a1df1SDavid du Colombier printf("]\n");
828312a1df1SDavid du Colombier }
829312a1df1SDavid du Colombier
830312a1df1SDavid du Colombier static int
AST_always(Lextok * n)831312a1df1SDavid du Colombier AST_always(Lextok *n)
832312a1df1SDavid du Colombier {
833312a1df1SDavid du Colombier if (!n) return 0;
834312a1df1SDavid du Colombier
835312a1df1SDavid du Colombier if (n->ntyp == '@' /* -end */
836312a1df1SDavid du Colombier || n->ntyp == 'p') /* remote reference */
837312a1df1SDavid du Colombier return 1;
838312a1df1SDavid du Colombier return AST_always(n->lft) || AST_always(n->rgt);
839312a1df1SDavid du Colombier }
840312a1df1SDavid du Colombier
841312a1df1SDavid du Colombier static void
AST_edge_dump(AST * a,FSM_state * f)842312a1df1SDavid du Colombier AST_edge_dump(AST *a, FSM_state *f)
843312a1df1SDavid du Colombier { FSM_trans *t;
844312a1df1SDavid du Colombier FSM_use *u;
845312a1df1SDavid du Colombier
846312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt) /* edges */
847312a1df1SDavid du Colombier {
848312a1df1SDavid du Colombier if (t->step && AST_always(t->step->n))
849312a1df1SDavid du Colombier t->relevant |= 1; /* always relevant */
850312a1df1SDavid du Colombier
851312a1df1SDavid du Colombier if (verbose&32)
852312a1df1SDavid du Colombier { switch (t->relevant) {
853312a1df1SDavid du Colombier case 0: printf(" "); break;
854312a1df1SDavid du Colombier case 1: printf("*%3d ", t->round); break;
855312a1df1SDavid du Colombier case 2: printf("+%3d ", t->round); break;
856312a1df1SDavid du Colombier case 3: printf("#%3d ", t->round); break;
857312a1df1SDavid du Colombier default: printf("? "); break;
858312a1df1SDavid du Colombier }
859312a1df1SDavid du Colombier
860312a1df1SDavid du Colombier printf("%d\t->\t%d\t", f->from, t->to);
861312a1df1SDavid du Colombier if (t->step)
862312a1df1SDavid du Colombier comment(stdout, t->step->n, 0);
863312a1df1SDavid du Colombier else
864312a1df1SDavid du Colombier printf("Unless");
865312a1df1SDavid du Colombier
866312a1df1SDavid du Colombier for (u = t->Val[0]; u; u = u->nxt)
867312a1df1SDavid du Colombier { printf(" <");
868312a1df1SDavid du Colombier AST_var(u->n, u->n->sym, 1);
869312a1df1SDavid du Colombier printf(":%d>", u->special);
870312a1df1SDavid du Colombier }
871312a1df1SDavid du Colombier printf("\n");
872312a1df1SDavid du Colombier } else
873312a1df1SDavid du Colombier { if (t->relevant)
874312a1df1SDavid du Colombier continue;
875312a1df1SDavid du Colombier
876312a1df1SDavid du Colombier if (t->step)
877312a1df1SDavid du Colombier switch(t->step->n->ntyp) {
878312a1df1SDavid du Colombier case ASGN:
879312a1df1SDavid du Colombier case 's':
880312a1df1SDavid du Colombier case 'r':
881312a1df1SDavid du Colombier case 'c':
882312a1df1SDavid du Colombier if (t->step->n->lft->ntyp != CONST)
883312a1df1SDavid du Colombier AST_report(a, t->step);
884312a1df1SDavid du Colombier break;
885312a1df1SDavid du Colombier
886312a1df1SDavid du Colombier case PRINT: /* don't report */
887312a1df1SDavid du Colombier case PRINTM:
888312a1df1SDavid du Colombier case ASSERT:
889312a1df1SDavid du Colombier case C_CODE:
890312a1df1SDavid du Colombier case C_EXPR:
891312a1df1SDavid du Colombier default:
892312a1df1SDavid du Colombier break;
893312a1df1SDavid du Colombier } } }
894312a1df1SDavid du Colombier }
895312a1df1SDavid du Colombier
896312a1df1SDavid du Colombier static void
AST_dfs(AST * a,int s,int vis)897312a1df1SDavid du Colombier AST_dfs(AST *a, int s, int vis)
898312a1df1SDavid du Colombier { FSM_state *f;
899312a1df1SDavid du Colombier FSM_trans *t;
900312a1df1SDavid du Colombier
901312a1df1SDavid du Colombier f = fsm_tbl[s];
902312a1df1SDavid du Colombier if (f->seen) return;
903312a1df1SDavid du Colombier
904312a1df1SDavid du Colombier f->seen = 1;
905312a1df1SDavid du Colombier if (vis) AST_edge_dump(a, f);
906312a1df1SDavid du Colombier
907312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
908312a1df1SDavid du Colombier AST_dfs(a, t->to, vis);
909312a1df1SDavid du Colombier }
910312a1df1SDavid du Colombier
911312a1df1SDavid du Colombier static void
AST_dump(AST * a)912312a1df1SDavid du Colombier AST_dump(AST *a)
913312a1df1SDavid du Colombier { FSM_state *f;
914312a1df1SDavid du Colombier
915312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
916312a1df1SDavid du Colombier { f->seen = 0;
917312a1df1SDavid du Colombier fsm_tbl[f->from] = f;
918312a1df1SDavid du Colombier }
919312a1df1SDavid du Colombier
920312a1df1SDavid du Colombier if (verbose&32)
921312a1df1SDavid du Colombier printf("AST_START %s from %d\n", a->p->n->name, a->i_st);
922312a1df1SDavid du Colombier
923312a1df1SDavid du Colombier AST_dfs(a, a->i_st, 1);
924312a1df1SDavid du Colombier }
925312a1df1SDavid du Colombier
926312a1df1SDavid du Colombier static void
AST_sends(AST * a)927312a1df1SDavid du Colombier AST_sends(AST *a)
928312a1df1SDavid du Colombier { FSM_state *f;
929312a1df1SDavid du Colombier FSM_trans *t;
930312a1df1SDavid du Colombier FSM_use *u;
931312a1df1SDavid du Colombier ChanList *cl;
932312a1df1SDavid du Colombier
933312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt) /* control states */
934312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt) /* transitions */
935312a1df1SDavid du Colombier { if (t->step
936312a1df1SDavid du Colombier && t->step->n
937312a1df1SDavid du Colombier && t->step->n->ntyp == 's')
938312a1df1SDavid du Colombier for (u = t->Val[0]; u; u = u->nxt)
939312a1df1SDavid du Colombier { if (Sym_typ(u->n) == CHAN
940312a1df1SDavid du Colombier && ((u->special&USE) && !(u->special&DEREF_USE)))
941312a1df1SDavid du Colombier {
942312a1df1SDavid du Colombier #if 0
943312a1df1SDavid du Colombier printf("%s -- (%d->%d) -- ",
944312a1df1SDavid du Colombier a->p->n->name, f->from, t->to);
945312a1df1SDavid du Colombier AST_var(u->n, u->n->sym, 1);
946312a1df1SDavid du Colombier printf(" -> chanlist\n");
947312a1df1SDavid du Colombier #endif
948312a1df1SDavid du Colombier cl = (ChanList *) emalloc(sizeof(ChanList));
949312a1df1SDavid du Colombier cl->s = t->step->n;
950312a1df1SDavid du Colombier cl->n = u->n;
951312a1df1SDavid du Colombier cl->nxt = chanlist;
952312a1df1SDavid du Colombier chanlist = cl;
953312a1df1SDavid du Colombier } } } }
954312a1df1SDavid du Colombier
955312a1df1SDavid du Colombier static ALIAS *
AST_alfind(Lextok * n)956312a1df1SDavid du Colombier AST_alfind(Lextok *n)
957312a1df1SDavid du Colombier { ALIAS *na;
958312a1df1SDavid du Colombier
959312a1df1SDavid du Colombier for (na = chalias; na; na = na->nxt)
960312a1df1SDavid du Colombier if (AST_mutual(na->cnm, n, 1))
961312a1df1SDavid du Colombier return na;
962312a1df1SDavid du Colombier return (ALIAS *) 0;
963312a1df1SDavid du Colombier }
964312a1df1SDavid du Colombier
965312a1df1SDavid du Colombier static void
AST_trans(void)966312a1df1SDavid du Colombier AST_trans(void)
967312a1df1SDavid du Colombier { ALIAS *na, *ca, *da, *ea;
968312a1df1SDavid du Colombier int nchanges;
969312a1df1SDavid du Colombier
970312a1df1SDavid du Colombier do {
971312a1df1SDavid du Colombier nchanges = 0;
972312a1df1SDavid du Colombier for (na = chalias; na; na = na->nxt)
973312a1df1SDavid du Colombier { chalcur = na;
974312a1df1SDavid du Colombier for (ca = na->alias; ca; ca = ca->nxt)
975312a1df1SDavid du Colombier { da = AST_alfind(ca->cnm);
976312a1df1SDavid du Colombier if (da)
977312a1df1SDavid du Colombier for (ea = da->alias; ea; ea = ea->nxt)
978312a1df1SDavid du Colombier { nchanges += AST_add_alias(ea->cnm,
979312a1df1SDavid du Colombier ea->origin|ca->origin);
980312a1df1SDavid du Colombier } } }
981312a1df1SDavid du Colombier } while (nchanges > 0);
982312a1df1SDavid du Colombier
983312a1df1SDavid du Colombier chalcur = (ALIAS *) 0;
984312a1df1SDavid du Colombier }
985312a1df1SDavid du Colombier
986312a1df1SDavid du Colombier static void
AST_def_use(AST * a)987312a1df1SDavid du Colombier AST_def_use(AST *a)
988312a1df1SDavid du Colombier { FSM_state *f;
989312a1df1SDavid du Colombier FSM_trans *t;
990312a1df1SDavid du Colombier
991312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt) /* control states */
992312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt) /* all edges */
993312a1df1SDavid du Colombier { cur_t = t;
994312a1df1SDavid du Colombier rel_use(t->Val[0]); /* redo Val; doesn't cover structs */
995312a1df1SDavid du Colombier rel_use(t->Val[1]);
996312a1df1SDavid du Colombier t->Val[0] = t->Val[1] = (FSM_use *) 0;
997312a1df1SDavid du Colombier
998312a1df1SDavid du Colombier if (!t->step) continue;
999312a1df1SDavid du Colombier
1000312a1df1SDavid du Colombier def_use(t->step->n, 0); /* def/use info, including structs */
1001312a1df1SDavid du Colombier }
1002312a1df1SDavid du Colombier cur_t = (FSM_trans *) 0;
1003312a1df1SDavid du Colombier }
1004312a1df1SDavid du Colombier
1005312a1df1SDavid du Colombier static void
name_AST_track(Lextok * n,int code)1006312a1df1SDavid du Colombier name_AST_track(Lextok *n, int code)
1007312a1df1SDavid du Colombier { extern int nr_errs;
1008312a1df1SDavid du Colombier #if 0
1009312a1df1SDavid du Colombier printf("AST_name: ");
1010312a1df1SDavid du Colombier AST_var(n, n->sym, 1);
1011312a1df1SDavid du Colombier printf(" -- %d\n", code);
1012312a1df1SDavid du Colombier #endif
1013312a1df1SDavid du Colombier if (in_recv && (code&DEF) && (code&USE))
1014312a1df1SDavid du Colombier { printf("spin: error: DEF and USE of same var in rcv stmnt: ");
1015312a1df1SDavid du Colombier AST_var(n, n->sym, 1);
1016312a1df1SDavid du Colombier printf(" -- %d\n", code);
1017312a1df1SDavid du Colombier nr_errs++;
1018312a1df1SDavid du Colombier }
1019312a1df1SDavid du Colombier check_slice(n, code);
1020312a1df1SDavid du Colombier }
1021312a1df1SDavid du Colombier
1022312a1df1SDavid du Colombier void
AST_track(Lextok * now,int code)1023312a1df1SDavid du Colombier AST_track(Lextok *now, int code) /* called from main.c */
1024312a1df1SDavid du Colombier { Lextok *v; extern int export_ast;
1025312a1df1SDavid du Colombier
1026312a1df1SDavid du Colombier if (!export_ast) return;
1027312a1df1SDavid du Colombier
1028312a1df1SDavid du Colombier if (now)
1029312a1df1SDavid du Colombier switch (now->ntyp) {
1030312a1df1SDavid du Colombier case LEN:
1031312a1df1SDavid du Colombier case FULL:
1032312a1df1SDavid du Colombier case EMPTY:
1033312a1df1SDavid du Colombier case NFULL:
1034312a1df1SDavid du Colombier case NEMPTY:
1035312a1df1SDavid du Colombier AST_track(now->lft, DEREF_USE|USE|code);
1036312a1df1SDavid du Colombier break;
1037312a1df1SDavid du Colombier
1038312a1df1SDavid du Colombier case '/':
1039312a1df1SDavid du Colombier case '*':
1040312a1df1SDavid du Colombier case '-':
1041312a1df1SDavid du Colombier case '+':
1042312a1df1SDavid du Colombier case '%':
1043312a1df1SDavid du Colombier case '&':
1044312a1df1SDavid du Colombier case '^':
1045312a1df1SDavid du Colombier case '|':
1046312a1df1SDavid du Colombier case LE:
1047312a1df1SDavid du Colombier case GE:
1048312a1df1SDavid du Colombier case GT:
1049312a1df1SDavid du Colombier case LT:
1050312a1df1SDavid du Colombier case NE:
1051312a1df1SDavid du Colombier case EQ:
1052312a1df1SDavid du Colombier case OR:
1053312a1df1SDavid du Colombier case AND:
1054312a1df1SDavid du Colombier case LSHIFT:
1055312a1df1SDavid du Colombier case RSHIFT:
1056312a1df1SDavid du Colombier AST_track(now->rgt, USE|code);
1057312a1df1SDavid du Colombier /* fall through */
1058312a1df1SDavid du Colombier case '!':
1059312a1df1SDavid du Colombier case UMIN:
1060312a1df1SDavid du Colombier case '~':
1061312a1df1SDavid du Colombier case 'c':
1062312a1df1SDavid du Colombier case ENABLED:
1063312a1df1SDavid du Colombier case ASSERT:
1064312a1df1SDavid du Colombier AST_track(now->lft, USE|code);
1065312a1df1SDavid du Colombier break;
1066312a1df1SDavid du Colombier
1067312a1df1SDavid du Colombier case EVAL:
1068312a1df1SDavid du Colombier AST_track(now->lft, USE|(code&(~DEF)));
1069312a1df1SDavid du Colombier break;
1070312a1df1SDavid du Colombier
1071312a1df1SDavid du Colombier case NAME:
1072312a1df1SDavid du Colombier name_AST_track(now, code);
1073*00d97012SDavid du Colombier if (now->sym->nel > 1 || now->sym->isarray)
1074312a1df1SDavid du Colombier AST_track(now->lft, USE|code); /* index */
1075312a1df1SDavid du Colombier break;
1076312a1df1SDavid du Colombier
1077312a1df1SDavid du Colombier case 'R':
1078312a1df1SDavid du Colombier AST_track(now->lft, DEREF_USE|USE|code);
1079312a1df1SDavid du Colombier for (v = now->rgt; v; v = v->rgt)
1080312a1df1SDavid du Colombier AST_track(v->lft, code); /* a deeper eval can add USE */
1081312a1df1SDavid du Colombier break;
1082312a1df1SDavid du Colombier
1083312a1df1SDavid du Colombier case '?':
1084312a1df1SDavid du Colombier AST_track(now->lft, USE|code);
1085312a1df1SDavid du Colombier if (now->rgt)
1086312a1df1SDavid du Colombier { AST_track(now->rgt->lft, code);
1087312a1df1SDavid du Colombier AST_track(now->rgt->rgt, code);
1088312a1df1SDavid du Colombier }
1089312a1df1SDavid du Colombier break;
1090312a1df1SDavid du Colombier
1091312a1df1SDavid du Colombier /* added for control deps: */
1092312a1df1SDavid du Colombier case TYPE:
1093312a1df1SDavid du Colombier name_AST_track(now, code);
1094312a1df1SDavid du Colombier break;
1095312a1df1SDavid du Colombier case ASGN:
1096312a1df1SDavid du Colombier AST_track(now->lft, DEF|code);
1097312a1df1SDavid du Colombier AST_track(now->rgt, USE|code);
1098312a1df1SDavid du Colombier break;
1099312a1df1SDavid du Colombier case RUN:
1100312a1df1SDavid du Colombier name_AST_track(now, USE);
1101312a1df1SDavid du Colombier for (v = now->lft; v; v = v->rgt)
1102312a1df1SDavid du Colombier AST_track(v->lft, USE|code);
1103312a1df1SDavid du Colombier break;
1104312a1df1SDavid du Colombier case 's':
1105312a1df1SDavid du Colombier AST_track(now->lft, DEREF_DEF|DEREF_USE|USE|code);
1106312a1df1SDavid du Colombier for (v = now->rgt; v; v = v->rgt)
1107312a1df1SDavid du Colombier AST_track(v->lft, USE|code);
1108312a1df1SDavid du Colombier break;
1109312a1df1SDavid du Colombier case 'r':
1110312a1df1SDavid du Colombier AST_track(now->lft, DEREF_DEF|DEREF_USE|USE|code);
1111312a1df1SDavid du Colombier for (v = now->rgt; v; v = v->rgt)
1112312a1df1SDavid du Colombier { in_recv++;
1113312a1df1SDavid du Colombier AST_track(v->lft, DEF|code);
1114312a1df1SDavid du Colombier in_recv--;
1115312a1df1SDavid du Colombier }
1116312a1df1SDavid du Colombier break;
1117312a1df1SDavid du Colombier case PRINT:
1118312a1df1SDavid du Colombier for (v = now->lft; v; v = v->rgt)
1119312a1df1SDavid du Colombier AST_track(v->lft, USE|code);
1120312a1df1SDavid du Colombier break;
1121312a1df1SDavid du Colombier case PRINTM:
1122312a1df1SDavid du Colombier AST_track(now->lft, USE);
1123312a1df1SDavid du Colombier break;
1124312a1df1SDavid du Colombier /* end add */
1125312a1df1SDavid du Colombier case 'p':
1126312a1df1SDavid du Colombier #if 0
1127312a1df1SDavid du Colombier 'p' -sym-> _p
1128312a1df1SDavid du Colombier /
1129312a1df1SDavid du Colombier '?' -sym-> a (proctype)
1130312a1df1SDavid du Colombier /
1131312a1df1SDavid du Colombier b (pid expr)
1132312a1df1SDavid du Colombier #endif
1133312a1df1SDavid du Colombier AST_track(now->lft->lft, USE|code);
1134312a1df1SDavid du Colombier AST_procisrelevant(now->lft->sym);
1135312a1df1SDavid du Colombier break;
1136312a1df1SDavid du Colombier
1137312a1df1SDavid du Colombier case CONST:
1138312a1df1SDavid du Colombier case ELSE:
1139312a1df1SDavid du Colombier case NONPROGRESS:
1140312a1df1SDavid du Colombier case PC_VAL:
1141312a1df1SDavid du Colombier case 'q':
1142312a1df1SDavid du Colombier break;
1143312a1df1SDavid du Colombier
1144312a1df1SDavid du Colombier case '.':
1145312a1df1SDavid du Colombier case GOTO:
1146312a1df1SDavid du Colombier case BREAK:
1147312a1df1SDavid du Colombier case '@':
1148312a1df1SDavid du Colombier case D_STEP:
1149312a1df1SDavid du Colombier case ATOMIC:
1150312a1df1SDavid du Colombier case NON_ATOMIC:
1151312a1df1SDavid du Colombier case IF:
1152312a1df1SDavid du Colombier case DO:
1153312a1df1SDavid du Colombier case UNLESS:
1154312a1df1SDavid du Colombier case TIMEOUT:
1155312a1df1SDavid du Colombier case C_CODE:
1156312a1df1SDavid du Colombier case C_EXPR:
1157312a1df1SDavid du Colombier break;
1158312a1df1SDavid du Colombier
1159312a1df1SDavid du Colombier default:
1160312a1df1SDavid du Colombier printf("AST_track, NOT EXPECTED ntyp: %d\n", now->ntyp);
1161312a1df1SDavid du Colombier break;
1162312a1df1SDavid du Colombier }
1163312a1df1SDavid du Colombier }
1164312a1df1SDavid du Colombier
1165312a1df1SDavid du Colombier static int
AST_dump_rel(void)1166312a1df1SDavid du Colombier AST_dump_rel(void)
1167312a1df1SDavid du Colombier { Slicer *rv;
1168312a1df1SDavid du Colombier Ordered *walk;
1169312a1df1SDavid du Colombier char buf[64];
1170312a1df1SDavid du Colombier int banner=0;
1171312a1df1SDavid du Colombier
1172312a1df1SDavid du Colombier if (verbose&32)
1173312a1df1SDavid du Colombier { printf("Relevant variables:\n");
1174312a1df1SDavid du Colombier for (rv = rel_vars; rv; rv = rv->nxt)
1175312a1df1SDavid du Colombier { printf("\t");
1176312a1df1SDavid du Colombier AST_var(rv->n, rv->n->sym, 1);
1177312a1df1SDavid du Colombier printf("\n");
1178312a1df1SDavid du Colombier }
1179312a1df1SDavid du Colombier return 1;
1180312a1df1SDavid du Colombier }
1181312a1df1SDavid du Colombier for (rv = rel_vars; rv; rv = rv->nxt)
1182312a1df1SDavid du Colombier rv->n->sym->setat = 1; /* mark it */
1183312a1df1SDavid du Colombier
1184312a1df1SDavid du Colombier for (walk = all_names; walk; walk = walk->next)
1185312a1df1SDavid du Colombier { Symbol *s;
1186312a1df1SDavid du Colombier s = walk->entry;
1187312a1df1SDavid du Colombier if (!s->setat
1188312a1df1SDavid du Colombier && (s->type != MTYPE || s->ini->ntyp != CONST)
1189312a1df1SDavid du Colombier && s->type != STRUCT /* report only fields */
1190312a1df1SDavid du Colombier && s->type != PROCTYPE
1191312a1df1SDavid du Colombier && !s->owner
1192312a1df1SDavid du Colombier && sputtype(buf, s->type))
1193312a1df1SDavid du Colombier { if (!banner)
1194312a1df1SDavid du Colombier { banner = 1;
1195312a1df1SDavid du Colombier printf("spin: redundant vars (for given property):\n");
1196312a1df1SDavid du Colombier }
1197312a1df1SDavid du Colombier printf("\t");
1198312a1df1SDavid du Colombier symvar(s);
1199312a1df1SDavid du Colombier } }
1200312a1df1SDavid du Colombier return banner;
1201312a1df1SDavid du Colombier }
1202312a1df1SDavid du Colombier
1203312a1df1SDavid du Colombier static void
AST_suggestions(void)1204312a1df1SDavid du Colombier AST_suggestions(void)
1205312a1df1SDavid du Colombier { Symbol *s;
1206312a1df1SDavid du Colombier Ordered *walk;
1207312a1df1SDavid du Colombier FSM_state *f;
1208312a1df1SDavid du Colombier FSM_trans *t;
1209312a1df1SDavid du Colombier AST *a;
1210312a1df1SDavid du Colombier int banner=0;
1211312a1df1SDavid du Colombier int talked=0;
1212312a1df1SDavid du Colombier
1213312a1df1SDavid du Colombier for (walk = all_names; walk; walk = walk->next)
1214312a1df1SDavid du Colombier { s = walk->entry;
1215312a1df1SDavid du Colombier if (s->colnr == 2 /* only used in conditionals */
1216312a1df1SDavid du Colombier && (s->type == BYTE
1217312a1df1SDavid du Colombier || s->type == SHORT
1218312a1df1SDavid du Colombier || s->type == INT
1219312a1df1SDavid du Colombier || s->type == MTYPE))
1220312a1df1SDavid du Colombier { if (!banner)
1221312a1df1SDavid du Colombier { banner = 1;
1222312a1df1SDavid du Colombier printf("spin: consider using predicate");
1223312a1df1SDavid du Colombier printf(" abstraction to replace:\n");
1224312a1df1SDavid du Colombier }
1225312a1df1SDavid du Colombier printf("\t");
1226312a1df1SDavid du Colombier symvar(s);
1227312a1df1SDavid du Colombier } }
1228312a1df1SDavid du Colombier
1229312a1df1SDavid du Colombier /* look for source and sink processes */
1230312a1df1SDavid du Colombier
1231312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt) /* automata */
1232312a1df1SDavid du Colombier { banner = 0;
1233312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt) /* control states */
1234312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt) /* transitions */
1235312a1df1SDavid du Colombier { if (t->step)
1236312a1df1SDavid du Colombier switch (t->step->n->ntyp) {
1237312a1df1SDavid du Colombier case 's':
1238312a1df1SDavid du Colombier banner |= 1;
1239312a1df1SDavid du Colombier break;
1240312a1df1SDavid du Colombier case 'r':
1241312a1df1SDavid du Colombier banner |= 2;
1242312a1df1SDavid du Colombier break;
1243312a1df1SDavid du Colombier case '.':
1244312a1df1SDavid du Colombier case D_STEP:
1245312a1df1SDavid du Colombier case ATOMIC:
1246312a1df1SDavid du Colombier case NON_ATOMIC:
1247312a1df1SDavid du Colombier case IF:
1248312a1df1SDavid du Colombier case DO:
1249312a1df1SDavid du Colombier case UNLESS:
1250312a1df1SDavid du Colombier case '@':
1251312a1df1SDavid du Colombier case GOTO:
1252312a1df1SDavid du Colombier case BREAK:
1253312a1df1SDavid du Colombier case PRINT:
1254312a1df1SDavid du Colombier case PRINTM:
1255312a1df1SDavid du Colombier case ASSERT:
1256312a1df1SDavid du Colombier case C_CODE:
1257312a1df1SDavid du Colombier case C_EXPR:
1258312a1df1SDavid du Colombier break;
1259312a1df1SDavid du Colombier default:
1260312a1df1SDavid du Colombier banner |= 4;
1261312a1df1SDavid du Colombier goto no_good;
1262312a1df1SDavid du Colombier }
1263312a1df1SDavid du Colombier }
1264312a1df1SDavid du Colombier no_good: if (banner == 1 || banner == 2)
1265312a1df1SDavid du Colombier { printf("spin: proctype %s defines a %s process\n",
1266312a1df1SDavid du Colombier a->p->n->name,
1267312a1df1SDavid du Colombier banner==1?"source":"sink");
1268312a1df1SDavid du Colombier talked |= banner;
1269312a1df1SDavid du Colombier } else if (banner == 3)
1270312a1df1SDavid du Colombier { printf("spin: proctype %s mimics a buffer\n",
1271312a1df1SDavid du Colombier a->p->n->name);
1272312a1df1SDavid du Colombier talked |= 4;
1273312a1df1SDavid du Colombier }
1274312a1df1SDavid du Colombier }
1275312a1df1SDavid du Colombier if (talked&1)
1276312a1df1SDavid du Colombier { printf("\tto reduce complexity, consider merging the code of\n");
1277312a1df1SDavid du Colombier printf("\teach source process into the code of its target\n");
1278312a1df1SDavid du Colombier }
1279312a1df1SDavid du Colombier if (talked&2)
1280312a1df1SDavid du Colombier { printf("\tto reduce complexity, consider merging the code of\n");
1281312a1df1SDavid du Colombier printf("\teach sink process into the code of its source\n");
1282312a1df1SDavid du Colombier }
1283312a1df1SDavid du Colombier if (talked&4)
1284312a1df1SDavid du Colombier printf("\tto reduce complexity, avoid buffer processes\n");
1285312a1df1SDavid du Colombier }
1286312a1df1SDavid du Colombier
1287312a1df1SDavid du Colombier static void
AST_preserve(void)1288312a1df1SDavid du Colombier AST_preserve(void)
1289312a1df1SDavid du Colombier { Slicer *sc, *nx, *rv;
1290312a1df1SDavid du Colombier
1291312a1df1SDavid du Colombier for (sc = slicer; sc; sc = nx)
1292312a1df1SDavid du Colombier { if (!sc->used)
1293312a1df1SDavid du Colombier break; /* done */
1294312a1df1SDavid du Colombier
1295312a1df1SDavid du Colombier nx = sc->nxt;
1296312a1df1SDavid du Colombier
1297312a1df1SDavid du Colombier for (rv = rel_vars; rv; rv = rv->nxt)
1298312a1df1SDavid du Colombier if (AST_mutual(sc->n, rv->n, 1))
1299312a1df1SDavid du Colombier break;
1300312a1df1SDavid du Colombier
1301312a1df1SDavid du Colombier if (!rv) /* not already there */
1302312a1df1SDavid du Colombier { sc->nxt = rel_vars;
1303312a1df1SDavid du Colombier rel_vars = sc;
1304312a1df1SDavid du Colombier } }
1305312a1df1SDavid du Colombier slicer = sc;
1306312a1df1SDavid du Colombier }
1307312a1df1SDavid du Colombier
1308312a1df1SDavid du Colombier static void
check_slice(Lextok * n,int code)1309312a1df1SDavid du Colombier check_slice(Lextok *n, int code)
1310312a1df1SDavid du Colombier { Slicer *sc;
1311312a1df1SDavid du Colombier
1312312a1df1SDavid du Colombier for (sc = slicer; sc; sc = sc->nxt)
1313312a1df1SDavid du Colombier if (AST_mutual(sc->n, n, 1)
1314312a1df1SDavid du Colombier && sc->code == code)
1315312a1df1SDavid du Colombier return; /* already there */
1316312a1df1SDavid du Colombier
1317312a1df1SDavid du Colombier sc = (Slicer *) emalloc(sizeof(Slicer));
1318312a1df1SDavid du Colombier sc->n = n;
1319312a1df1SDavid du Colombier
1320312a1df1SDavid du Colombier sc->code = code;
1321312a1df1SDavid du Colombier sc->used = 0;
1322312a1df1SDavid du Colombier sc->nxt = slicer;
1323312a1df1SDavid du Colombier slicer = sc;
1324312a1df1SDavid du Colombier }
1325312a1df1SDavid du Colombier
1326312a1df1SDavid du Colombier static void
AST_data_dep(void)1327312a1df1SDavid du Colombier AST_data_dep(void)
1328312a1df1SDavid du Colombier { Slicer *sc;
1329312a1df1SDavid du Colombier
1330312a1df1SDavid du Colombier /* mark all def-relevant transitions */
1331312a1df1SDavid du Colombier for (sc = slicer; sc; sc = sc->nxt)
1332312a1df1SDavid du Colombier { sc->used = 1;
1333312a1df1SDavid du Colombier if (verbose&32)
1334312a1df1SDavid du Colombier { printf("spin: slice criterion ");
1335312a1df1SDavid du Colombier AST_var(sc->n, sc->n->sym, 1);
1336312a1df1SDavid du Colombier printf(" type=%d\n", Sym_typ(sc->n));
1337312a1df1SDavid du Colombier }
1338312a1df1SDavid du Colombier AST_relevant(sc->n);
1339312a1df1SDavid du Colombier }
1340312a1df1SDavid du Colombier AST_tagruns(); /* mark 'run's relevant if target proctype is relevant */
1341312a1df1SDavid du Colombier }
1342312a1df1SDavid du Colombier
1343312a1df1SDavid du Colombier static int
AST_blockable(AST * a,int s)1344312a1df1SDavid du Colombier AST_blockable(AST *a, int s)
1345312a1df1SDavid du Colombier { FSM_state *f;
1346312a1df1SDavid du Colombier FSM_trans *t;
1347312a1df1SDavid du Colombier
1348312a1df1SDavid du Colombier f = fsm_tbl[s];
1349312a1df1SDavid du Colombier
1350312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
1351312a1df1SDavid du Colombier { if (t->relevant&2)
1352312a1df1SDavid du Colombier return 1;
1353312a1df1SDavid du Colombier
1354312a1df1SDavid du Colombier if (t->step && t->step->n)
1355312a1df1SDavid du Colombier switch (t->step->n->ntyp) {
1356312a1df1SDavid du Colombier case IF:
1357312a1df1SDavid du Colombier case DO:
1358312a1df1SDavid du Colombier case ATOMIC:
1359312a1df1SDavid du Colombier case NON_ATOMIC:
1360312a1df1SDavid du Colombier case D_STEP:
1361312a1df1SDavid du Colombier if (AST_blockable(a, t->to))
1362312a1df1SDavid du Colombier { t->round = AST_Round;
1363312a1df1SDavid du Colombier t->relevant |= 2;
1364312a1df1SDavid du Colombier return 1;
1365312a1df1SDavid du Colombier }
1366312a1df1SDavid du Colombier /* else fall through */
1367312a1df1SDavid du Colombier default:
1368312a1df1SDavid du Colombier break;
1369312a1df1SDavid du Colombier }
1370312a1df1SDavid du Colombier else if (AST_blockable(a, t->to)) /* Unless */
1371312a1df1SDavid du Colombier { t->round = AST_Round;
1372312a1df1SDavid du Colombier t->relevant |= 2;
1373312a1df1SDavid du Colombier return 1;
1374312a1df1SDavid du Colombier }
1375312a1df1SDavid du Colombier }
1376312a1df1SDavid du Colombier return 0;
1377312a1df1SDavid du Colombier }
1378312a1df1SDavid du Colombier
1379312a1df1SDavid du Colombier static void
AST_spread(AST * a,int s)1380312a1df1SDavid du Colombier AST_spread(AST *a, int s)
1381312a1df1SDavid du Colombier { FSM_state *f;
1382312a1df1SDavid du Colombier FSM_trans *t;
1383312a1df1SDavid du Colombier
1384312a1df1SDavid du Colombier f = fsm_tbl[s];
1385312a1df1SDavid du Colombier
1386312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
1387312a1df1SDavid du Colombier { if (t->relevant&2)
1388312a1df1SDavid du Colombier continue;
1389312a1df1SDavid du Colombier
1390312a1df1SDavid du Colombier if (t->step && t->step->n)
1391312a1df1SDavid du Colombier switch (t->step->n->ntyp) {
1392312a1df1SDavid du Colombier case IF:
1393312a1df1SDavid du Colombier case DO:
1394312a1df1SDavid du Colombier case ATOMIC:
1395312a1df1SDavid du Colombier case NON_ATOMIC:
1396312a1df1SDavid du Colombier case D_STEP:
1397312a1df1SDavid du Colombier AST_spread(a, t->to);
1398312a1df1SDavid du Colombier /* fall thru */
1399312a1df1SDavid du Colombier default:
1400312a1df1SDavid du Colombier t->round = AST_Round;
1401312a1df1SDavid du Colombier t->relevant |= 2;
1402312a1df1SDavid du Colombier break;
1403312a1df1SDavid du Colombier }
1404312a1df1SDavid du Colombier else /* Unless */
1405312a1df1SDavid du Colombier { AST_spread(a, t->to);
1406312a1df1SDavid du Colombier t->round = AST_Round;
1407312a1df1SDavid du Colombier t->relevant |= 2;
1408312a1df1SDavid du Colombier }
1409312a1df1SDavid du Colombier }
1410312a1df1SDavid du Colombier }
1411312a1df1SDavid du Colombier
1412312a1df1SDavid du Colombier static int
AST_notrelevant(Lextok * n)1413312a1df1SDavid du Colombier AST_notrelevant(Lextok *n)
1414312a1df1SDavid du Colombier { Slicer *s;
1415312a1df1SDavid du Colombier
1416312a1df1SDavid du Colombier for (s = rel_vars; s; s = s->nxt)
1417312a1df1SDavid du Colombier if (AST_mutual(s->n, n, 1))
1418312a1df1SDavid du Colombier return 0;
1419312a1df1SDavid du Colombier for (s = slicer; s; s = s->nxt)
1420312a1df1SDavid du Colombier if (AST_mutual(s->n, n, 1))
1421312a1df1SDavid du Colombier return 0;
1422312a1df1SDavid du Colombier return 1;
1423312a1df1SDavid du Colombier }
1424312a1df1SDavid du Colombier
1425312a1df1SDavid du Colombier static int
AST_withchan(Lextok * n)1426312a1df1SDavid du Colombier AST_withchan(Lextok *n)
1427312a1df1SDavid du Colombier {
1428312a1df1SDavid du Colombier if (!n) return 0;
1429312a1df1SDavid du Colombier if (Sym_typ(n) == CHAN)
1430312a1df1SDavid du Colombier return 1;
1431312a1df1SDavid du Colombier return AST_withchan(n->lft) || AST_withchan(n->rgt);
1432312a1df1SDavid du Colombier }
1433312a1df1SDavid du Colombier
1434312a1df1SDavid du Colombier static int
AST_suspect(FSM_trans * t)1435312a1df1SDavid du Colombier AST_suspect(FSM_trans *t)
1436312a1df1SDavid du Colombier { FSM_use *u;
1437312a1df1SDavid du Colombier /* check for possible overkill */
1438312a1df1SDavid du Colombier if (!t || !t->step || !AST_withchan(t->step->n))
1439312a1df1SDavid du Colombier return 0;
1440312a1df1SDavid du Colombier for (u = t->Val[0]; u; u = u->nxt)
1441312a1df1SDavid du Colombier if (AST_notrelevant(u->n))
1442312a1df1SDavid du Colombier return 1;
1443312a1df1SDavid du Colombier return 0;
1444312a1df1SDavid du Colombier }
1445312a1df1SDavid du Colombier
1446312a1df1SDavid du Colombier static void
AST_shouldconsider(AST * a,int s)1447312a1df1SDavid du Colombier AST_shouldconsider(AST *a, int s)
1448312a1df1SDavid du Colombier { FSM_state *f;
1449312a1df1SDavid du Colombier FSM_trans *t;
1450312a1df1SDavid du Colombier
1451312a1df1SDavid du Colombier f = fsm_tbl[s];
1452312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
1453312a1df1SDavid du Colombier { if (t->step && t->step->n)
1454312a1df1SDavid du Colombier switch (t->step->n->ntyp) {
1455312a1df1SDavid du Colombier case IF:
1456312a1df1SDavid du Colombier case DO:
1457312a1df1SDavid du Colombier case ATOMIC:
1458312a1df1SDavid du Colombier case NON_ATOMIC:
1459312a1df1SDavid du Colombier case D_STEP:
1460312a1df1SDavid du Colombier AST_shouldconsider(a, t->to);
1461312a1df1SDavid du Colombier break;
1462312a1df1SDavid du Colombier default:
1463312a1df1SDavid du Colombier AST_track(t->step->n, 0);
1464312a1df1SDavid du Colombier /*
1465312a1df1SDavid du Colombier AST_track is called here for a blockable stmnt from which
1466312a1df1SDavid du Colombier a relevant stmnmt was shown to be reachable
1467312a1df1SDavid du Colombier for a condition this makes all USEs relevant
1468312a1df1SDavid du Colombier but for a channel operation it only makes the executability
1469312a1df1SDavid du Colombier relevant -- in those cases, parameters that aren't already
1470312a1df1SDavid du Colombier relevant may be replaceable with arbitrary tokens
1471312a1df1SDavid du Colombier */
1472312a1df1SDavid du Colombier if (AST_suspect(t))
1473312a1df1SDavid du Colombier { printf("spin: possibly redundant parameters in: ");
1474312a1df1SDavid du Colombier comment(stdout, t->step->n, 0);
1475312a1df1SDavid du Colombier printf("\n");
1476312a1df1SDavid du Colombier }
1477312a1df1SDavid du Colombier break;
1478312a1df1SDavid du Colombier }
1479312a1df1SDavid du Colombier else /* an Unless */
1480312a1df1SDavid du Colombier AST_shouldconsider(a, t->to);
1481312a1df1SDavid du Colombier }
1482312a1df1SDavid du Colombier }
1483312a1df1SDavid du Colombier
1484312a1df1SDavid du Colombier static int
FSM_critical(AST * a,int s)1485312a1df1SDavid du Colombier FSM_critical(AST *a, int s)
1486312a1df1SDavid du Colombier { FSM_state *f;
1487312a1df1SDavid du Colombier FSM_trans *t;
1488312a1df1SDavid du Colombier
1489312a1df1SDavid du Colombier /* is a 1-relevant stmnt reachable from this state? */
1490312a1df1SDavid du Colombier
1491312a1df1SDavid du Colombier f = fsm_tbl[s];
1492312a1df1SDavid du Colombier if (f->seen)
1493312a1df1SDavid du Colombier goto done;
1494312a1df1SDavid du Colombier f->seen = 1;
1495312a1df1SDavid du Colombier f->cr = 0;
1496312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
1497312a1df1SDavid du Colombier if ((t->relevant&1)
1498312a1df1SDavid du Colombier || FSM_critical(a, t->to))
1499312a1df1SDavid du Colombier { f->cr = 1;
1500312a1df1SDavid du Colombier
1501312a1df1SDavid du Colombier if (verbose&32)
1502312a1df1SDavid du Colombier { printf("\t\t\t\tcritical(%d) ", t->relevant);
1503312a1df1SDavid du Colombier comment(stdout, t->step->n, 0);
1504312a1df1SDavid du Colombier printf("\n");
1505312a1df1SDavid du Colombier }
1506312a1df1SDavid du Colombier break;
1507312a1df1SDavid du Colombier }
1508312a1df1SDavid du Colombier #if 0
1509312a1df1SDavid du Colombier else {
1510312a1df1SDavid du Colombier if (verbose&32)
1511312a1df1SDavid du Colombier { printf("\t\t\t\tnot-crit ");
1512312a1df1SDavid du Colombier comment(stdout, t->step->n, 0);
1513312a1df1SDavid du Colombier printf("\n");
1514312a1df1SDavid du Colombier }
1515312a1df1SDavid du Colombier }
1516312a1df1SDavid du Colombier #endif
1517312a1df1SDavid du Colombier done:
1518312a1df1SDavid du Colombier return f->cr;
1519312a1df1SDavid du Colombier }
1520312a1df1SDavid du Colombier
1521312a1df1SDavid du Colombier static void
AST_ctrl(AST * a)1522312a1df1SDavid du Colombier AST_ctrl(AST *a)
1523312a1df1SDavid du Colombier { FSM_state *f;
1524312a1df1SDavid du Colombier FSM_trans *t;
1525312a1df1SDavid du Colombier int hit;
1526312a1df1SDavid du Colombier
1527312a1df1SDavid du Colombier /* add all blockable transitions
1528312a1df1SDavid du Colombier * from which relevant transitions can be reached
1529312a1df1SDavid du Colombier */
1530312a1df1SDavid du Colombier if (verbose&32)
1531312a1df1SDavid du Colombier printf("CTL -- %s\n", a->p->n->name);
1532312a1df1SDavid du Colombier
1533312a1df1SDavid du Colombier /* 1 : mark all blockable edges */
1534312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
1535312a1df1SDavid du Colombier { if (!(f->scratch&2)) /* not part of irrelevant subgraph */
1536312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
1537312a1df1SDavid du Colombier { if (t->step && t->step->n)
1538312a1df1SDavid du Colombier switch (t->step->n->ntyp) {
1539312a1df1SDavid du Colombier case 'r':
1540312a1df1SDavid du Colombier case 's':
1541312a1df1SDavid du Colombier case 'c':
1542312a1df1SDavid du Colombier case ELSE:
1543312a1df1SDavid du Colombier t->round = AST_Round;
1544312a1df1SDavid du Colombier t->relevant |= 2; /* mark for next phases */
1545312a1df1SDavid du Colombier if (verbose&32)
1546312a1df1SDavid du Colombier { printf("\tpremark ");
1547312a1df1SDavid du Colombier comment(stdout, t->step->n, 0);
1548312a1df1SDavid du Colombier printf("\n");
1549312a1df1SDavid du Colombier }
1550312a1df1SDavid du Colombier break;
1551312a1df1SDavid du Colombier default:
1552312a1df1SDavid du Colombier break;
1553312a1df1SDavid du Colombier } } }
1554312a1df1SDavid du Colombier
1555312a1df1SDavid du Colombier /* 2: keep only 2-marked stmnts from which 1-marked stmnts can be reached */
1556312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
1557312a1df1SDavid du Colombier { fsm_tbl[f->from] = f;
1558312a1df1SDavid du Colombier f->seen = 0; /* used in dfs from FSM_critical */
1559312a1df1SDavid du Colombier }
1560312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
1561312a1df1SDavid du Colombier { if (!FSM_critical(a, f->from))
1562312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
1563312a1df1SDavid du Colombier if (t->relevant&2)
1564312a1df1SDavid du Colombier { t->relevant &= ~2; /* clear mark */
1565312a1df1SDavid du Colombier if (verbose&32)
1566312a1df1SDavid du Colombier { printf("\t\tnomark ");
1567*00d97012SDavid du Colombier if (t->step && t->step->n)
1568312a1df1SDavid du Colombier comment(stdout, t->step->n, 0);
1569312a1df1SDavid du Colombier printf("\n");
1570312a1df1SDavid du Colombier } } }
1571312a1df1SDavid du Colombier
1572312a1df1SDavid du Colombier /* 3 : lift marks across IF/DO etc. */
1573312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
1574312a1df1SDavid du Colombier { hit = 0;
1575312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
1576312a1df1SDavid du Colombier { if (t->step && t->step->n)
1577312a1df1SDavid du Colombier switch (t->step->n->ntyp) {
1578312a1df1SDavid du Colombier case IF:
1579312a1df1SDavid du Colombier case DO:
1580312a1df1SDavid du Colombier case ATOMIC:
1581312a1df1SDavid du Colombier case NON_ATOMIC:
1582312a1df1SDavid du Colombier case D_STEP:
1583312a1df1SDavid du Colombier if (AST_blockable(a, t->to))
1584312a1df1SDavid du Colombier hit = 1;
1585312a1df1SDavid du Colombier break;
1586312a1df1SDavid du Colombier default:
1587312a1df1SDavid du Colombier break;
1588312a1df1SDavid du Colombier }
1589312a1df1SDavid du Colombier else if (AST_blockable(a, t->to)) /* Unless */
1590312a1df1SDavid du Colombier hit = 1;
1591312a1df1SDavid du Colombier
1592312a1df1SDavid du Colombier if (hit) break;
1593312a1df1SDavid du Colombier }
1594312a1df1SDavid du Colombier if (hit) /* at least one outgoing trans can block */
1595312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
1596312a1df1SDavid du Colombier { t->round = AST_Round;
1597312a1df1SDavid du Colombier t->relevant |= 2; /* lift */
1598312a1df1SDavid du Colombier if (verbose&32)
1599312a1df1SDavid du Colombier { printf("\t\t\tliftmark ");
1600*00d97012SDavid du Colombier if (t->step && t->step->n)
1601312a1df1SDavid du Colombier comment(stdout, t->step->n, 0);
1602312a1df1SDavid du Colombier printf("\n");
1603312a1df1SDavid du Colombier }
1604312a1df1SDavid du Colombier AST_spread(a, t->to); /* and spread to all guards */
1605312a1df1SDavid du Colombier } }
1606312a1df1SDavid du Colombier
1607312a1df1SDavid du Colombier /* 4: nodes with 2-marked out-edges contribute new slice criteria */
1608312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
1609312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
1610312a1df1SDavid du Colombier if (t->relevant&2)
1611312a1df1SDavid du Colombier { AST_shouldconsider(a, f->from);
1612312a1df1SDavid du Colombier break; /* inner loop */
1613312a1df1SDavid du Colombier }
1614312a1df1SDavid du Colombier }
1615312a1df1SDavid du Colombier
1616312a1df1SDavid du Colombier static void
AST_control_dep(void)1617312a1df1SDavid du Colombier AST_control_dep(void)
1618312a1df1SDavid du Colombier { AST *a;
1619312a1df1SDavid du Colombier
1620312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt)
1621*00d97012SDavid du Colombier { if (a->p->b != N_CLAIM && a->p->b != E_TRACE && a->p->b != N_TRACE)
1622*00d97012SDavid du Colombier { AST_ctrl(a);
1623*00d97012SDavid du Colombier } }
1624312a1df1SDavid du Colombier }
1625312a1df1SDavid du Colombier
1626312a1df1SDavid du Colombier static void
AST_prelabel(void)1627312a1df1SDavid du Colombier AST_prelabel(void)
1628312a1df1SDavid du Colombier { AST *a;
1629312a1df1SDavid du Colombier FSM_state *f;
1630312a1df1SDavid du Colombier FSM_trans *t;
1631312a1df1SDavid du Colombier
1632312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt)
1633*00d97012SDavid du Colombier { if (a->p->b != N_CLAIM && a->p->b != E_TRACE && a->p->b != N_TRACE)
1634312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
1635312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
1636312a1df1SDavid du Colombier { if (t->step
1637312a1df1SDavid du Colombier && t->step->n
1638312a1df1SDavid du Colombier && t->step->n->ntyp == ASSERT
1639312a1df1SDavid du Colombier )
1640312a1df1SDavid du Colombier { t->relevant |= 1;
1641312a1df1SDavid du Colombier } } }
1642312a1df1SDavid du Colombier }
1643312a1df1SDavid du Colombier
1644312a1df1SDavid du Colombier static void
AST_criteria(void)1645312a1df1SDavid du Colombier AST_criteria(void)
1646312a1df1SDavid du Colombier { /*
1647312a1df1SDavid du Colombier * remote labels are handled separately -- by making
1648312a1df1SDavid du Colombier * sure they are not pruned away during optimization
1649312a1df1SDavid du Colombier */
1650312a1df1SDavid du Colombier AST_Changes = 1; /* to get started */
1651312a1df1SDavid du Colombier for (AST_Round = 1; slicer && AST_Changes; AST_Round++)
1652312a1df1SDavid du Colombier { AST_Changes = 0;
1653312a1df1SDavid du Colombier AST_data_dep();
1654312a1df1SDavid du Colombier AST_preserve(); /* moves processed vars from slicer to rel_vars */
1655312a1df1SDavid du Colombier AST_dominant(); /* mark data-irrelevant subgraphs */
1656312a1df1SDavid du Colombier AST_control_dep(); /* can add data deps, which add control deps */
1657312a1df1SDavid du Colombier
1658312a1df1SDavid du Colombier if (verbose&32)
1659312a1df1SDavid du Colombier printf("\n\nROUND %d -- changes %d\n",
1660312a1df1SDavid du Colombier AST_Round, AST_Changes);
1661312a1df1SDavid du Colombier }
1662312a1df1SDavid du Colombier }
1663312a1df1SDavid du Colombier
1664312a1df1SDavid du Colombier static void
AST_alias_analysis(void)1665312a1df1SDavid du Colombier AST_alias_analysis(void) /* aliasing of promela channels */
1666312a1df1SDavid du Colombier { AST *a;
1667312a1df1SDavid du Colombier
1668312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt)
1669312a1df1SDavid du Colombier AST_sends(a); /* collect chan-names that are send across chans */
1670312a1df1SDavid du Colombier
1671312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt)
1672312a1df1SDavid du Colombier AST_para(a->p); /* aliasing of chans thru proctype parameters */
1673312a1df1SDavid du Colombier
1674312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt)
1675312a1df1SDavid du Colombier AST_other(a); /* chan params in asgns and recvs */
1676312a1df1SDavid du Colombier
1677312a1df1SDavid du Colombier AST_trans(); /* transitive closure of alias table */
1678312a1df1SDavid du Colombier
1679312a1df1SDavid du Colombier if (verbose&32)
1680312a1df1SDavid du Colombier AST_aliases(); /* show channel aliasing info */
1681312a1df1SDavid du Colombier }
1682312a1df1SDavid du Colombier
1683312a1df1SDavid du Colombier void
AST_slice(void)1684312a1df1SDavid du Colombier AST_slice(void)
1685312a1df1SDavid du Colombier { AST *a;
1686312a1df1SDavid du Colombier int spurious = 0;
1687312a1df1SDavid du Colombier
1688312a1df1SDavid du Colombier if (!slicer)
1689*00d97012SDavid du Colombier { printf("spin: warning: no slice criteria found (no assertions and no claim)\n");
1690312a1df1SDavid du Colombier spurious = 1;
1691312a1df1SDavid du Colombier }
1692312a1df1SDavid du Colombier AST_dorelevant(); /* mark procs refered to in remote refs */
1693312a1df1SDavid du Colombier
1694312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt)
1695312a1df1SDavid du Colombier AST_def_use(a); /* compute standard def/use information */
1696312a1df1SDavid du Colombier
1697312a1df1SDavid du Colombier AST_hidden(); /* parameter passing and local var inits */
1698312a1df1SDavid du Colombier
1699312a1df1SDavid du Colombier AST_alias_analysis(); /* channel alias analysis */
1700312a1df1SDavid du Colombier
1701312a1df1SDavid du Colombier AST_prelabel(); /* mark all 'assert(...)' stmnts as relevant */
1702312a1df1SDavid du Colombier AST_criteria(); /* process the slice criteria from
1703312a1df1SDavid du Colombier * asserts and from the never claim
1704312a1df1SDavid du Colombier */
1705312a1df1SDavid du Colombier if (!spurious || (verbose&32))
1706312a1df1SDavid du Colombier { spurious = 1;
1707312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt)
1708312a1df1SDavid du Colombier { AST_dump(a); /* marked up result */
1709312a1df1SDavid du Colombier if (a->relevant&2) /* it printed something */
1710312a1df1SDavid du Colombier spurious = 0;
1711312a1df1SDavid du Colombier }
1712312a1df1SDavid du Colombier if (!AST_dump_rel() /* relevant variables */
1713312a1df1SDavid du Colombier && spurious)
1714312a1df1SDavid du Colombier printf("spin: no redundancies found (for given property)\n");
1715312a1df1SDavid du Colombier }
1716312a1df1SDavid du Colombier AST_suggestions();
1717312a1df1SDavid du Colombier
1718312a1df1SDavid du Colombier if (verbose&32)
1719312a1df1SDavid du Colombier show_expl();
1720312a1df1SDavid du Colombier }
1721312a1df1SDavid du Colombier
1722312a1df1SDavid du Colombier void
AST_store(ProcList * p,int start_state)1723312a1df1SDavid du Colombier AST_store(ProcList *p, int start_state)
1724312a1df1SDavid du Colombier { AST *n_ast;
1725312a1df1SDavid du Colombier
1726*00d97012SDavid du Colombier if (p->b != N_CLAIM && p->b != E_TRACE && p->b != N_TRACE)
1727312a1df1SDavid du Colombier { n_ast = (AST *) emalloc(sizeof(AST));
1728312a1df1SDavid du Colombier n_ast->p = p;
1729312a1df1SDavid du Colombier n_ast->i_st = start_state;
1730312a1df1SDavid du Colombier n_ast->relevant = 0;
1731312a1df1SDavid du Colombier n_ast->fsm = fsm;
1732312a1df1SDavid du Colombier n_ast->nxt = ast;
1733312a1df1SDavid du Colombier ast = n_ast;
1734312a1df1SDavid du Colombier }
1735312a1df1SDavid du Colombier fsm = (FSM_state *) 0; /* hide it from FSM_DEL */
1736312a1df1SDavid du Colombier }
1737312a1df1SDavid du Colombier
1738312a1df1SDavid du Colombier static void
AST_add_explicit(Lextok * d,Lextok * u)1739312a1df1SDavid du Colombier AST_add_explicit(Lextok *d, Lextok *u)
1740312a1df1SDavid du Colombier { FSM_trans *e = (FSM_trans *) emalloc(sizeof(FSM_trans));
1741312a1df1SDavid du Colombier
1742312a1df1SDavid du Colombier e->to = 0; /* or start_state ? */
1743312a1df1SDavid du Colombier e->relevant = 0; /* to be determined */
1744312a1df1SDavid du Colombier e->step = (Element *) 0; /* left blank */
1745312a1df1SDavid du Colombier e->Val[0] = e->Val[1] = (FSM_use *) 0;
1746312a1df1SDavid du Colombier
1747312a1df1SDavid du Colombier cur_t = e;
1748312a1df1SDavid du Colombier
1749312a1df1SDavid du Colombier def_use(u, USE);
1750312a1df1SDavid du Colombier def_use(d, DEF);
1751312a1df1SDavid du Colombier
1752312a1df1SDavid du Colombier cur_t = (FSM_trans *) 0;
1753312a1df1SDavid du Colombier
1754312a1df1SDavid du Colombier e->nxt = explicit;
1755312a1df1SDavid du Colombier explicit = e;
1756312a1df1SDavid du Colombier }
1757312a1df1SDavid du Colombier
1758312a1df1SDavid du Colombier static void
AST_fp1(char * s,Lextok * t,Lextok * f,int parno)1759312a1df1SDavid du Colombier AST_fp1(char *s, Lextok *t, Lextok *f, int parno)
1760312a1df1SDavid du Colombier { Lextok *v;
1761312a1df1SDavid du Colombier int cnt;
1762312a1df1SDavid du Colombier
1763312a1df1SDavid du Colombier if (!t) return;
1764312a1df1SDavid du Colombier
1765312a1df1SDavid du Colombier if (t->ntyp == RUN)
1766312a1df1SDavid du Colombier { if (strcmp(t->sym->name, s) == 0)
1767312a1df1SDavid du Colombier for (v = t->lft, cnt = 1; v; v = v->rgt, cnt++)
1768312a1df1SDavid du Colombier if (cnt == parno)
1769312a1df1SDavid du Colombier { AST_add_explicit(f, v->lft);
1770312a1df1SDavid du Colombier break;
1771312a1df1SDavid du Colombier }
1772312a1df1SDavid du Colombier } else
1773312a1df1SDavid du Colombier { AST_fp1(s, t->lft, f, parno);
1774312a1df1SDavid du Colombier AST_fp1(s, t->rgt, f, parno);
1775312a1df1SDavid du Colombier }
1776312a1df1SDavid du Colombier }
1777312a1df1SDavid du Colombier
1778312a1df1SDavid du Colombier static void
AST_mk1(char * s,Lextok * c,int parno)1779312a1df1SDavid du Colombier AST_mk1(char *s, Lextok *c, int parno)
1780312a1df1SDavid du Colombier { AST *a;
1781312a1df1SDavid du Colombier FSM_state *f;
1782312a1df1SDavid du Colombier FSM_trans *t;
1783312a1df1SDavid du Colombier
1784312a1df1SDavid du Colombier /* concoct an extra FSM_trans *t with the asgn of
1785312a1df1SDavid du Colombier * formal par c to matching actual pars made explicit
1786312a1df1SDavid du Colombier */
1787312a1df1SDavid du Colombier
1788312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt) /* automata */
1789312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt) /* control states */
1790312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt) /* transitions */
1791312a1df1SDavid du Colombier { if (t->step)
1792312a1df1SDavid du Colombier AST_fp1(s, t->step->n, c, parno);
1793312a1df1SDavid du Colombier }
1794312a1df1SDavid du Colombier }
1795312a1df1SDavid du Colombier
1796312a1df1SDavid du Colombier static void
AST_par_init(void)1797312a1df1SDavid du Colombier AST_par_init(void) /* parameter passing -- hidden assignments */
1798312a1df1SDavid du Colombier { AST *a;
1799312a1df1SDavid du Colombier Lextok *f, *t, *c;
1800312a1df1SDavid du Colombier int cnt;
1801312a1df1SDavid du Colombier
1802312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt)
1803*00d97012SDavid du Colombier { if (a->p->b == N_CLAIM || a->p->b == I_PROC
1804*00d97012SDavid du Colombier || a->p->b == E_TRACE || a->p->b == N_TRACE)
1805*00d97012SDavid du Colombier { continue; /* has no params */
1806*00d97012SDavid du Colombier }
1807312a1df1SDavid du Colombier cnt = 0;
1808312a1df1SDavid du Colombier for (f = a->p->p; f; f = f->rgt) /* types */
1809312a1df1SDavid du Colombier for (t = f->lft; t; t = t->rgt) /* formals */
1810312a1df1SDavid du Colombier { cnt++; /* formal par count */
1811312a1df1SDavid du Colombier c = (t->ntyp != ',')? t : t->lft; /* the formal parameter */
1812312a1df1SDavid du Colombier AST_mk1(a->p->n->name, c, cnt); /* all matching run statements */
1813312a1df1SDavid du Colombier } }
1814312a1df1SDavid du Colombier }
1815312a1df1SDavid du Colombier
1816312a1df1SDavid du Colombier static void
AST_var_init(void)1817312a1df1SDavid du Colombier AST_var_init(void) /* initialized vars (not chans) - hidden assignments */
1818312a1df1SDavid du Colombier { Ordered *walk;
1819312a1df1SDavid du Colombier Lextok *x;
1820312a1df1SDavid du Colombier Symbol *sp;
1821312a1df1SDavid du Colombier AST *a;
1822312a1df1SDavid du Colombier
1823312a1df1SDavid du Colombier for (walk = all_names; walk; walk = walk->next)
1824312a1df1SDavid du Colombier { sp = walk->entry;
1825312a1df1SDavid du Colombier if (sp
1826312a1df1SDavid du Colombier && !sp->context /* globals */
1827312a1df1SDavid du Colombier && sp->type != PROCTYPE
1828312a1df1SDavid du Colombier && sp->ini
1829312a1df1SDavid du Colombier && (sp->type != MTYPE || sp->ini->ntyp != CONST) /* not mtype defs */
1830312a1df1SDavid du Colombier && sp->ini->ntyp != CHAN)
1831312a1df1SDavid du Colombier { x = nn(ZN, TYPE, ZN, ZN);
1832312a1df1SDavid du Colombier x->sym = sp;
1833312a1df1SDavid du Colombier AST_add_explicit(x, sp->ini);
1834312a1df1SDavid du Colombier } }
1835312a1df1SDavid du Colombier
1836312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt)
1837*00d97012SDavid du Colombier { if (a->p->b != N_CLAIM
1838*00d97012SDavid du Colombier && a->p->b != E_TRACE && a->p->b != N_TRACE) /* has no locals */
1839312a1df1SDavid du Colombier for (walk = all_names; walk; walk = walk->next)
1840312a1df1SDavid du Colombier { sp = walk->entry;
1841312a1df1SDavid du Colombier if (sp
1842312a1df1SDavid du Colombier && sp->context
1843312a1df1SDavid du Colombier && strcmp(sp->context->name, a->p->n->name) == 0
1844312a1df1SDavid du Colombier && sp->Nid >= 0 /* not a param */
1845312a1df1SDavid du Colombier && sp->type != LABEL
1846312a1df1SDavid du Colombier && sp->ini
1847312a1df1SDavid du Colombier && sp->ini->ntyp != CHAN)
1848312a1df1SDavid du Colombier { x = nn(ZN, TYPE, ZN, ZN);
1849312a1df1SDavid du Colombier x->sym = sp;
1850312a1df1SDavid du Colombier AST_add_explicit(x, sp->ini);
1851312a1df1SDavid du Colombier } } }
1852312a1df1SDavid du Colombier }
1853312a1df1SDavid du Colombier
1854312a1df1SDavid du Colombier static void
show_expl(void)1855312a1df1SDavid du Colombier show_expl(void)
1856312a1df1SDavid du Colombier { FSM_trans *t, *T;
1857312a1df1SDavid du Colombier FSM_use *u;
1858312a1df1SDavid du Colombier
1859312a1df1SDavid du Colombier printf("\nExplicit List:\n");
1860312a1df1SDavid du Colombier for (T = expl_par; T; T = (T == expl_par)?expl_var: (FSM_trans *) 0)
1861312a1df1SDavid du Colombier { for (t = T; t; t = t->nxt)
1862312a1df1SDavid du Colombier { if (!t->Val[0]) continue;
1863312a1df1SDavid du Colombier printf("%s", t->relevant?"*":" ");
1864312a1df1SDavid du Colombier printf("%3d", t->round);
1865312a1df1SDavid du Colombier for (u = t->Val[0]; u; u = u->nxt)
1866312a1df1SDavid du Colombier { printf("\t<");
1867312a1df1SDavid du Colombier AST_var(u->n, u->n->sym, 1);
1868312a1df1SDavid du Colombier printf(":%d>, ", u->special);
1869312a1df1SDavid du Colombier }
1870312a1df1SDavid du Colombier printf("\n");
1871312a1df1SDavid du Colombier }
1872312a1df1SDavid du Colombier printf("==\n");
1873312a1df1SDavid du Colombier }
1874312a1df1SDavid du Colombier printf("End\n");
1875312a1df1SDavid du Colombier }
1876312a1df1SDavid du Colombier
1877312a1df1SDavid du Colombier static void
AST_hidden(void)1878312a1df1SDavid du Colombier AST_hidden(void) /* reveal all hidden assignments */
1879312a1df1SDavid du Colombier {
1880312a1df1SDavid du Colombier AST_par_init();
1881312a1df1SDavid du Colombier expl_par = explicit;
1882312a1df1SDavid du Colombier explicit = (FSM_trans *) 0;
1883312a1df1SDavid du Colombier
1884312a1df1SDavid du Colombier AST_var_init();
1885312a1df1SDavid du Colombier expl_var = explicit;
1886312a1df1SDavid du Colombier explicit = (FSM_trans *) 0;
1887312a1df1SDavid du Colombier }
1888312a1df1SDavid du Colombier
1889312a1df1SDavid du Colombier #define BPW (8*sizeof(ulong)) /* bits per word */
1890312a1df1SDavid du Colombier
1891312a1df1SDavid du Colombier static int
bad_scratch(FSM_state * f,int upto)1892312a1df1SDavid du Colombier bad_scratch(FSM_state *f, int upto)
1893312a1df1SDavid du Colombier { FSM_trans *t;
1894312a1df1SDavid du Colombier #if 0
1895312a1df1SDavid du Colombier 1. all internal branch-points have else-s
1896312a1df1SDavid du Colombier 2. all non-branchpoints have non-blocking out-edge
1897312a1df1SDavid du Colombier 3. all internal edges are non-relevant
1898312a1df1SDavid du Colombier subgraphs like this need NOT contribute control-dependencies
1899312a1df1SDavid du Colombier #endif
1900312a1df1SDavid du Colombier
1901312a1df1SDavid du Colombier if (!f->seen
1902312a1df1SDavid du Colombier || (f->scratch&4))
1903312a1df1SDavid du Colombier return 0;
1904312a1df1SDavid du Colombier
1905312a1df1SDavid du Colombier if (f->scratch&8)
1906312a1df1SDavid du Colombier return 1;
1907312a1df1SDavid du Colombier
1908312a1df1SDavid du Colombier f->scratch |= 4;
1909312a1df1SDavid du Colombier
1910312a1df1SDavid du Colombier if (verbose&32) printf("X[%d:%d:%d] ", f->from, upto, f->scratch);
1911312a1df1SDavid du Colombier
1912312a1df1SDavid du Colombier if (f->scratch&1)
1913312a1df1SDavid du Colombier { if (verbose&32)
1914312a1df1SDavid du Colombier printf("\tbad scratch: %d\n", f->from);
1915312a1df1SDavid du Colombier bad: f->scratch &= ~4;
1916312a1df1SDavid du Colombier /* f->scratch |= 8; wrong */
1917312a1df1SDavid du Colombier return 1;
1918312a1df1SDavid du Colombier }
1919312a1df1SDavid du Colombier
1920312a1df1SDavid du Colombier if (f->from != upto)
1921312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
1922312a1df1SDavid du Colombier if (bad_scratch(fsm_tbl[t->to], upto))
1923312a1df1SDavid du Colombier goto bad;
1924312a1df1SDavid du Colombier
1925312a1df1SDavid du Colombier return 0;
1926312a1df1SDavid du Colombier }
1927312a1df1SDavid du Colombier
1928312a1df1SDavid du Colombier static void
mark_subgraph(FSM_state * f,int upto)1929312a1df1SDavid du Colombier mark_subgraph(FSM_state *f, int upto)
1930312a1df1SDavid du Colombier { FSM_trans *t;
1931312a1df1SDavid du Colombier
1932312a1df1SDavid du Colombier if (f->from == upto
1933312a1df1SDavid du Colombier || !f->seen
1934312a1df1SDavid du Colombier || (f->scratch&2))
1935312a1df1SDavid du Colombier return;
1936312a1df1SDavid du Colombier
1937312a1df1SDavid du Colombier f->scratch |= 2;
1938312a1df1SDavid du Colombier
1939312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
1940312a1df1SDavid du Colombier mark_subgraph(fsm_tbl[t->to], upto);
1941312a1df1SDavid du Colombier }
1942312a1df1SDavid du Colombier
1943312a1df1SDavid du Colombier static void
AST_pair(AST * a,FSM_state * h,int y)1944312a1df1SDavid du Colombier AST_pair(AST *a, FSM_state *h, int y)
1945312a1df1SDavid du Colombier { Pair *p;
1946312a1df1SDavid du Colombier
1947312a1df1SDavid du Colombier for (p = a->pairs; p; p = p->nxt)
1948312a1df1SDavid du Colombier if (p->h == h
1949312a1df1SDavid du Colombier && p->b == y)
1950312a1df1SDavid du Colombier return;
1951312a1df1SDavid du Colombier
1952312a1df1SDavid du Colombier p = (Pair *) emalloc(sizeof(Pair));
1953312a1df1SDavid du Colombier p->h = h;
1954312a1df1SDavid du Colombier p->b = y;
1955312a1df1SDavid du Colombier p->nxt = a->pairs;
1956312a1df1SDavid du Colombier a->pairs = p;
1957312a1df1SDavid du Colombier }
1958312a1df1SDavid du Colombier
1959312a1df1SDavid du Colombier static void
AST_checkpairs(AST * a)1960312a1df1SDavid du Colombier AST_checkpairs(AST *a)
1961312a1df1SDavid du Colombier { Pair *p;
1962312a1df1SDavid du Colombier
1963312a1df1SDavid du Colombier for (p = a->pairs; p; p = p->nxt)
1964312a1df1SDavid du Colombier { if (verbose&32)
1965312a1df1SDavid du Colombier printf(" inspect pair %d %d\n", p->b, p->h->from);
1966312a1df1SDavid du Colombier if (!bad_scratch(p->h, p->b)) /* subgraph is clean */
1967312a1df1SDavid du Colombier { if (verbose&32)
1968312a1df1SDavid du Colombier printf("subgraph: %d .. %d\n", p->b, p->h->from);
1969312a1df1SDavid du Colombier mark_subgraph(p->h, p->b);
1970312a1df1SDavid du Colombier }
1971312a1df1SDavid du Colombier }
1972312a1df1SDavid du Colombier }
1973312a1df1SDavid du Colombier
1974312a1df1SDavid du Colombier static void
subgraph(AST * a,FSM_state * f,int out)1975312a1df1SDavid du Colombier subgraph(AST *a, FSM_state *f, int out)
1976312a1df1SDavid du Colombier { FSM_state *h;
1977312a1df1SDavid du Colombier int i, j;
1978312a1df1SDavid du Colombier ulong *g;
1979312a1df1SDavid du Colombier #if 0
1980312a1df1SDavid du Colombier reverse dominance suggests that this is a possible
1981312a1df1SDavid du Colombier entry and exit node for a proper subgraph
1982312a1df1SDavid du Colombier #endif
1983312a1df1SDavid du Colombier h = fsm_tbl[out];
1984312a1df1SDavid du Colombier
1985312a1df1SDavid du Colombier i = f->from / BPW;
1986312a1df1SDavid du Colombier j = f->from % BPW;
1987312a1df1SDavid du Colombier g = h->mod;
1988312a1df1SDavid du Colombier
1989312a1df1SDavid du Colombier if (verbose&32)
1990312a1df1SDavid du Colombier printf("possible pair %d %d -- %d\n",
1991312a1df1SDavid du Colombier f->from, h->from, (g[i]&(1<<j))?1:0);
1992312a1df1SDavid du Colombier
1993312a1df1SDavid du Colombier if (g[i]&(1<<j)) /* also a forward dominance pair */
1994312a1df1SDavid du Colombier AST_pair(a, h, f->from); /* record this pair */
1995312a1df1SDavid du Colombier }
1996312a1df1SDavid du Colombier
1997312a1df1SDavid du Colombier static void
act_dom(AST * a)1998312a1df1SDavid du Colombier act_dom(AST *a)
1999312a1df1SDavid du Colombier { FSM_state *f;
2000312a1df1SDavid du Colombier FSM_trans *t;
2001312a1df1SDavid du Colombier int i, j, cnt;
2002312a1df1SDavid du Colombier
2003312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
2004312a1df1SDavid du Colombier { if (!f->seen) continue;
2005312a1df1SDavid du Colombier #if 0
2006312a1df1SDavid du Colombier f->from is the exit-node of a proper subgraph, with
2007312a1df1SDavid du Colombier the dominator its entry-node, if:
2008312a1df1SDavid du Colombier a. this node has more than 1 reachable predecessor
2009312a1df1SDavid du Colombier b. the dominator has more than 1 reachable successor
2010312a1df1SDavid du Colombier (need reachability - in case of reverse dominance)
2011312a1df1SDavid du Colombier d. the dominator is reachable, and not equal to this node
2012312a1df1SDavid du Colombier #endif
2013312a1df1SDavid du Colombier for (t = f->p, i = 0; t; t = t->nxt)
2014312a1df1SDavid du Colombier i += fsm_tbl[t->to]->seen;
2015312a1df1SDavid du Colombier if (i <= 1) continue; /* a. */
2016312a1df1SDavid du Colombier
2017312a1df1SDavid du Colombier for (cnt = 1; cnt < a->nstates; cnt++) /* 0 is endstate */
2018312a1df1SDavid du Colombier { if (cnt == f->from
2019312a1df1SDavid du Colombier || !fsm_tbl[cnt]->seen)
2020312a1df1SDavid du Colombier continue; /* c. */
2021312a1df1SDavid du Colombier
2022312a1df1SDavid du Colombier i = cnt / BPW;
2023312a1df1SDavid du Colombier j = cnt % BPW;
2024312a1df1SDavid du Colombier if (!(f->dom[i]&(1<<j)))
2025312a1df1SDavid du Colombier continue;
2026312a1df1SDavid du Colombier
2027312a1df1SDavid du Colombier for (t = fsm_tbl[cnt]->t, i = 0; t; t = t->nxt)
2028312a1df1SDavid du Colombier i += fsm_tbl[t->to]->seen;
2029312a1df1SDavid du Colombier if (i <= 1)
2030312a1df1SDavid du Colombier continue; /* b. */
2031312a1df1SDavid du Colombier
2032312a1df1SDavid du Colombier if (f->mod) /* final check in 2nd phase */
2033312a1df1SDavid du Colombier subgraph(a, f, cnt); /* possible entry-exit pair */
2034312a1df1SDavid du Colombier }
2035312a1df1SDavid du Colombier }
2036312a1df1SDavid du Colombier }
2037312a1df1SDavid du Colombier
2038312a1df1SDavid du Colombier static void
reachability(AST * a)2039312a1df1SDavid du Colombier reachability(AST *a)
2040312a1df1SDavid du Colombier { FSM_state *f;
2041312a1df1SDavid du Colombier
2042312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
2043312a1df1SDavid du Colombier f->seen = 0; /* clear */
2044312a1df1SDavid du Colombier AST_dfs(a, a->i_st, 0); /* mark 'seen' */
2045312a1df1SDavid du Colombier }
2046312a1df1SDavid du Colombier
2047312a1df1SDavid du Colombier static int
see_else(FSM_state * f)2048312a1df1SDavid du Colombier see_else(FSM_state *f)
2049312a1df1SDavid du Colombier { FSM_trans *t;
2050312a1df1SDavid du Colombier
2051312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
2052312a1df1SDavid du Colombier { if (t->step
2053312a1df1SDavid du Colombier && t->step->n)
2054312a1df1SDavid du Colombier switch (t->step->n->ntyp) {
2055312a1df1SDavid du Colombier case ELSE:
2056312a1df1SDavid du Colombier return 1;
2057312a1df1SDavid du Colombier case IF:
2058312a1df1SDavid du Colombier case DO:
2059312a1df1SDavid du Colombier case ATOMIC:
2060312a1df1SDavid du Colombier case NON_ATOMIC:
2061312a1df1SDavid du Colombier case D_STEP:
2062312a1df1SDavid du Colombier if (see_else(fsm_tbl[t->to]))
2063312a1df1SDavid du Colombier return 1;
2064312a1df1SDavid du Colombier default:
2065312a1df1SDavid du Colombier break;
2066312a1df1SDavid du Colombier }
2067312a1df1SDavid du Colombier }
2068312a1df1SDavid du Colombier return 0;
2069312a1df1SDavid du Colombier }
2070312a1df1SDavid du Colombier
2071312a1df1SDavid du Colombier static int
is_guard(FSM_state * f)2072312a1df1SDavid du Colombier is_guard(FSM_state *f)
2073312a1df1SDavid du Colombier { FSM_state *g;
2074312a1df1SDavid du Colombier FSM_trans *t;
2075312a1df1SDavid du Colombier
2076312a1df1SDavid du Colombier for (t = f->p; t; t = t->nxt)
2077312a1df1SDavid du Colombier { g = fsm_tbl[t->to];
2078312a1df1SDavid du Colombier if (!g->seen)
2079312a1df1SDavid du Colombier continue;
2080312a1df1SDavid du Colombier
2081312a1df1SDavid du Colombier if (t->step
2082312a1df1SDavid du Colombier && t->step->n)
2083312a1df1SDavid du Colombier switch(t->step->n->ntyp) {
2084312a1df1SDavid du Colombier case IF:
2085312a1df1SDavid du Colombier case DO:
2086312a1df1SDavid du Colombier return 1;
2087312a1df1SDavid du Colombier case ATOMIC:
2088312a1df1SDavid du Colombier case NON_ATOMIC:
2089312a1df1SDavid du Colombier case D_STEP:
2090312a1df1SDavid du Colombier if (is_guard(g))
2091312a1df1SDavid du Colombier return 1;
2092312a1df1SDavid du Colombier default:
2093312a1df1SDavid du Colombier break;
2094312a1df1SDavid du Colombier }
2095312a1df1SDavid du Colombier }
2096312a1df1SDavid du Colombier return 0;
2097312a1df1SDavid du Colombier }
2098312a1df1SDavid du Colombier
2099312a1df1SDavid du Colombier static void
curtail(AST * a)2100312a1df1SDavid du Colombier curtail(AST *a)
2101312a1df1SDavid du Colombier { FSM_state *f, *g;
2102312a1df1SDavid du Colombier FSM_trans *t;
2103312a1df1SDavid du Colombier int i, haselse, isrel, blocking;
2104312a1df1SDavid du Colombier #if 0
2105312a1df1SDavid du Colombier mark nodes that do not satisfy these requirements:
2106312a1df1SDavid du Colombier 1. all internal branch-points have else-s
2107312a1df1SDavid du Colombier 2. all non-branchpoints have non-blocking out-edge
2108312a1df1SDavid du Colombier 3. all internal edges are non-data-relevant
2109312a1df1SDavid du Colombier #endif
2110312a1df1SDavid du Colombier if (verbose&32)
2111312a1df1SDavid du Colombier printf("Curtail %s:\n", a->p->n->name);
2112312a1df1SDavid du Colombier
2113312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
2114312a1df1SDavid du Colombier { if (!f->seen
2115312a1df1SDavid du Colombier || (f->scratch&(1|2)))
2116312a1df1SDavid du Colombier continue;
2117312a1df1SDavid du Colombier
2118312a1df1SDavid du Colombier isrel = haselse = i = blocking = 0;
2119312a1df1SDavid du Colombier
2120312a1df1SDavid du Colombier for (t = f->t; t; t = t->nxt)
2121312a1df1SDavid du Colombier { g = fsm_tbl[t->to];
2122312a1df1SDavid du Colombier
2123312a1df1SDavid du Colombier isrel |= (t->relevant&1); /* data relevant */
2124312a1df1SDavid du Colombier i += g->seen;
2125312a1df1SDavid du Colombier
2126312a1df1SDavid du Colombier if (t->step
2127312a1df1SDavid du Colombier && t->step->n)
2128312a1df1SDavid du Colombier { switch (t->step->n->ntyp) {
2129312a1df1SDavid du Colombier case IF:
2130312a1df1SDavid du Colombier case DO:
2131312a1df1SDavid du Colombier haselse |= see_else(g);
2132312a1df1SDavid du Colombier break;
2133312a1df1SDavid du Colombier case 'c':
2134312a1df1SDavid du Colombier case 's':
2135312a1df1SDavid du Colombier case 'r':
2136312a1df1SDavid du Colombier blocking = 1;
2137312a1df1SDavid du Colombier break;
2138312a1df1SDavid du Colombier } } }
2139312a1df1SDavid du Colombier #if 0
2140312a1df1SDavid du Colombier if (verbose&32)
2141312a1df1SDavid du Colombier printf("prescratch %d -- %d %d %d %d -- %d\n",
2142312a1df1SDavid du Colombier f->from, i, isrel, blocking, haselse, is_guard(f));
2143312a1df1SDavid du Colombier #endif
2144312a1df1SDavid du Colombier if (isrel /* 3. */
2145312a1df1SDavid du Colombier || (i == 1 && blocking) /* 2. */
2146312a1df1SDavid du Colombier || (i > 1 && !haselse)) /* 1. */
2147312a1df1SDavid du Colombier { if (!is_guard(f))
2148312a1df1SDavid du Colombier { f->scratch |= 1;
2149312a1df1SDavid du Colombier if (verbose&32)
2150312a1df1SDavid du Colombier printf("scratch %d -- %d %d %d %d\n",
2151312a1df1SDavid du Colombier f->from, i, isrel, blocking, haselse);
2152312a1df1SDavid du Colombier }
2153312a1df1SDavid du Colombier }
2154312a1df1SDavid du Colombier }
2155312a1df1SDavid du Colombier }
2156312a1df1SDavid du Colombier
2157312a1df1SDavid du Colombier static void
init_dom(AST * a)2158312a1df1SDavid du Colombier init_dom(AST *a)
2159312a1df1SDavid du Colombier { FSM_state *f;
2160312a1df1SDavid du Colombier int i, j, cnt;
2161312a1df1SDavid du Colombier #if 0
2162312a1df1SDavid du Colombier (1) D(s0) = {s0}
2163312a1df1SDavid du Colombier (2) for s in S - {s0} do D(s) = S
2164312a1df1SDavid du Colombier #endif
2165312a1df1SDavid du Colombier
2166312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
2167312a1df1SDavid du Colombier { if (!f->seen) continue;
2168312a1df1SDavid du Colombier
2169312a1df1SDavid du Colombier f->dom = (ulong *)
2170312a1df1SDavid du Colombier emalloc(a->nwords * sizeof(ulong));
2171312a1df1SDavid du Colombier
2172312a1df1SDavid du Colombier if (f->from == a->i_st)
2173312a1df1SDavid du Colombier { i = a->i_st / BPW;
2174312a1df1SDavid du Colombier j = a->i_st % BPW;
2175312a1df1SDavid du Colombier f->dom[i] = (1<<j); /* (1) */
2176312a1df1SDavid du Colombier } else /* (2) */
2177312a1df1SDavid du Colombier { for (i = 0; i < a->nwords; i++)
2178312a1df1SDavid du Colombier f->dom[i] = (ulong) ~0; /* all 1's */
2179312a1df1SDavid du Colombier
2180312a1df1SDavid du Colombier if (a->nstates % BPW)
2181f3793cddSDavid du Colombier for (i = (a->nstates % BPW); i < (int) BPW; i++)
2182312a1df1SDavid du Colombier f->dom[a->nwords-1] &= ~(1<<i); /* clear tail */
2183312a1df1SDavid du Colombier
2184312a1df1SDavid du Colombier for (cnt = 0; cnt < a->nstates; cnt++)
2185312a1df1SDavid du Colombier if (!fsm_tbl[cnt]->seen)
2186312a1df1SDavid du Colombier { i = cnt / BPW;
2187312a1df1SDavid du Colombier j = cnt % BPW;
2188312a1df1SDavid du Colombier f->dom[i] &= ~(1<<j);
2189312a1df1SDavid du Colombier } } }
2190312a1df1SDavid du Colombier }
2191312a1df1SDavid du Colombier
2192312a1df1SDavid du Colombier static int
dom_perculate(AST * a,FSM_state * f)2193312a1df1SDavid du Colombier dom_perculate(AST *a, FSM_state *f)
2194312a1df1SDavid du Colombier { static ulong *ndom = (ulong *) 0;
2195312a1df1SDavid du Colombier static int on = 0;
2196312a1df1SDavid du Colombier int i, j, cnt = 0;
2197312a1df1SDavid du Colombier FSM_state *g;
2198312a1df1SDavid du Colombier FSM_trans *t;
2199312a1df1SDavid du Colombier
2200312a1df1SDavid du Colombier if (on < a->nwords)
2201312a1df1SDavid du Colombier { on = a->nwords;
2202312a1df1SDavid du Colombier ndom = (ulong *)
2203312a1df1SDavid du Colombier emalloc(on * sizeof(ulong));
2204312a1df1SDavid du Colombier }
2205312a1df1SDavid du Colombier
2206312a1df1SDavid du Colombier for (i = 0; i < a->nwords; i++)
2207312a1df1SDavid du Colombier ndom[i] = (ulong) ~0;
2208312a1df1SDavid du Colombier
2209312a1df1SDavid du Colombier for (t = f->p; t; t = t->nxt) /* all reachable predecessors */
2210312a1df1SDavid du Colombier { g = fsm_tbl[t->to];
2211312a1df1SDavid du Colombier if (g->seen)
2212312a1df1SDavid du Colombier for (i = 0; i < a->nwords; i++)
2213312a1df1SDavid du Colombier ndom[i] &= g->dom[i]; /* (5b) */
2214312a1df1SDavid du Colombier }
2215312a1df1SDavid du Colombier
2216312a1df1SDavid du Colombier i = f->from / BPW;
2217312a1df1SDavid du Colombier j = f->from % BPW;
2218312a1df1SDavid du Colombier ndom[i] |= (1<<j); /* (5a) */
2219312a1df1SDavid du Colombier
2220312a1df1SDavid du Colombier for (i = 0; i < a->nwords; i++)
2221312a1df1SDavid du Colombier if (f->dom[i] != ndom[i])
2222312a1df1SDavid du Colombier { cnt++;
2223312a1df1SDavid du Colombier f->dom[i] = ndom[i];
2224312a1df1SDavid du Colombier }
2225312a1df1SDavid du Colombier
2226312a1df1SDavid du Colombier return cnt;
2227312a1df1SDavid du Colombier }
2228312a1df1SDavid du Colombier
2229312a1df1SDavid du Colombier static void
dom_forward(AST * a)2230312a1df1SDavid du Colombier dom_forward(AST *a)
2231312a1df1SDavid du Colombier { FSM_state *f;
2232312a1df1SDavid du Colombier int cnt;
2233312a1df1SDavid du Colombier
2234312a1df1SDavid du Colombier init_dom(a); /* (1,2) */
2235312a1df1SDavid du Colombier do {
2236312a1df1SDavid du Colombier cnt = 0;
2237312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
2238312a1df1SDavid du Colombier { if (f->seen
2239312a1df1SDavid du Colombier && f->from != a->i_st) /* (4) */
2240312a1df1SDavid du Colombier cnt += dom_perculate(a, f); /* (5) */
2241312a1df1SDavid du Colombier }
2242312a1df1SDavid du Colombier } while (cnt); /* (3) */
2243312a1df1SDavid du Colombier dom_perculate(a, fsm_tbl[a->i_st]);
2244312a1df1SDavid du Colombier }
2245312a1df1SDavid du Colombier
2246312a1df1SDavid du Colombier static void
AST_dominant(void)2247312a1df1SDavid du Colombier AST_dominant(void)
2248312a1df1SDavid du Colombier { FSM_state *f;
2249312a1df1SDavid du Colombier FSM_trans *t;
2250312a1df1SDavid du Colombier AST *a;
2251312a1df1SDavid du Colombier int oi;
2252*00d97012SDavid du Colombier static FSM_state no_state;
2253312a1df1SDavid du Colombier #if 0
2254312a1df1SDavid du Colombier find dominators
2255312a1df1SDavid du Colombier Aho, Sethi, & Ullman, Compilers - principles, techniques, and tools
2256312a1df1SDavid du Colombier Addison-Wesley, 1986, p.671.
2257312a1df1SDavid du Colombier
2258312a1df1SDavid du Colombier (1) D(s0) = {s0}
2259312a1df1SDavid du Colombier (2) for s in S - {s0} do D(s) = S
2260312a1df1SDavid du Colombier
2261312a1df1SDavid du Colombier (3) while any D(s) changes do
2262312a1df1SDavid du Colombier (4) for s in S - {s0} do
2263312a1df1SDavid du Colombier (5) D(s) = {s} union with intersection of all D(p)
2264312a1df1SDavid du Colombier where p are the immediate predecessors of s
2265312a1df1SDavid du Colombier
2266312a1df1SDavid du Colombier the purpose is to find proper subgraphs
2267312a1df1SDavid du Colombier (one entry node, one exit node)
2268312a1df1SDavid du Colombier #endif
2269312a1df1SDavid du Colombier if (AST_Round == 1) /* computed once, reused in every round */
2270312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt)
2271312a1df1SDavid du Colombier { a->nstates = 0;
2272312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
2273312a1df1SDavid du Colombier { a->nstates++; /* count */
2274312a1df1SDavid du Colombier fsm_tbl[f->from] = f; /* fast lookup */
2275312a1df1SDavid du Colombier f->scratch = 0; /* clear scratch marks */
2276312a1df1SDavid du Colombier }
2277312a1df1SDavid du Colombier for (oi = 0; oi < a->nstates; oi++)
2278312a1df1SDavid du Colombier if (!fsm_tbl[oi])
2279312a1df1SDavid du Colombier fsm_tbl[oi] = &no_state;
2280312a1df1SDavid du Colombier
2281312a1df1SDavid du Colombier a->nwords = (a->nstates + BPW - 1) / BPW; /* round up */
2282312a1df1SDavid du Colombier
2283312a1df1SDavid du Colombier if (verbose&32)
2284312a1df1SDavid du Colombier { printf("%s (%d): ", a->p->n->name, a->i_st);
2285312a1df1SDavid du Colombier printf("states=%d (max %d), words = %d, bpw %d, overflow %d\n",
2286312a1df1SDavid du Colombier a->nstates, o_max, a->nwords,
2287312a1df1SDavid du Colombier (int) BPW, (int) (a->nstates % BPW));
2288312a1df1SDavid du Colombier }
2289312a1df1SDavid du Colombier
2290312a1df1SDavid du Colombier reachability(a);
2291312a1df1SDavid du Colombier dom_forward(a); /* forward dominance relation */
2292312a1df1SDavid du Colombier
2293312a1df1SDavid du Colombier curtail(a); /* mark ineligible edges */
2294312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
2295312a1df1SDavid du Colombier { t = f->p;
2296312a1df1SDavid du Colombier f->p = f->t;
2297312a1df1SDavid du Colombier f->t = t; /* invert edges */
2298312a1df1SDavid du Colombier
2299312a1df1SDavid du Colombier f->mod = f->dom;
2300312a1df1SDavid du Colombier f->dom = (ulong *) 0;
2301312a1df1SDavid du Colombier }
2302312a1df1SDavid du Colombier oi = a->i_st;
2303312a1df1SDavid du Colombier if (fsm_tbl[0]->seen) /* end-state reachable - else leave it */
2304312a1df1SDavid du Colombier a->i_st = 0; /* becomes initial state */
2305312a1df1SDavid du Colombier
2306312a1df1SDavid du Colombier dom_forward(a); /* reverse dominance -- don't redo reachability! */
2307312a1df1SDavid du Colombier act_dom(a); /* mark proper subgraphs, if any */
2308312a1df1SDavid du Colombier AST_checkpairs(a); /* selectively place 2 scratch-marks */
2309312a1df1SDavid du Colombier
2310312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
2311312a1df1SDavid du Colombier { t = f->p;
2312312a1df1SDavid du Colombier f->p = f->t;
2313312a1df1SDavid du Colombier f->t = t; /* restore */
2314312a1df1SDavid du Colombier }
2315312a1df1SDavid du Colombier a->i_st = oi; /* restore */
2316312a1df1SDavid du Colombier } else
2317312a1df1SDavid du Colombier for (a = ast; a; a = a->nxt)
2318312a1df1SDavid du Colombier { for (f = a->fsm; f; f = f->nxt)
2319312a1df1SDavid du Colombier { fsm_tbl[f->from] = f;
2320312a1df1SDavid du Colombier f->scratch &= 1; /* preserve 1-marks */
2321312a1df1SDavid du Colombier }
2322312a1df1SDavid du Colombier for (oi = 0; oi < a->nstates; oi++)
2323312a1df1SDavid du Colombier if (!fsm_tbl[oi])
2324312a1df1SDavid du Colombier fsm_tbl[oi] = &no_state;
2325312a1df1SDavid du Colombier
2326312a1df1SDavid du Colombier curtail(a); /* mark ineligible edges */
2327312a1df1SDavid du Colombier
2328312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
2329312a1df1SDavid du Colombier { t = f->p;
2330312a1df1SDavid du Colombier f->p = f->t;
2331312a1df1SDavid du Colombier f->t = t; /* invert edges */
2332312a1df1SDavid du Colombier }
2333312a1df1SDavid du Colombier
2334312a1df1SDavid du Colombier AST_checkpairs(a); /* recompute 2-marks */
2335312a1df1SDavid du Colombier
2336312a1df1SDavid du Colombier for (f = a->fsm; f; f = f->nxt)
2337312a1df1SDavid du Colombier { t = f->p;
2338312a1df1SDavid du Colombier f->p = f->t;
2339312a1df1SDavid du Colombier f->t = t; /* restore */
2340312a1df1SDavid du Colombier } }
2341312a1df1SDavid du Colombier }
2342