QBE
ssa.c
См. документацию.
1 #include "all.h"
2 #include <stdarg.h>
3 
4 static void
5 adduse(Tmp *tmp, int ty, Blk *b, ...)
6 {
7  Use *u;
8  int n;
9  va_list ap;
10 
11  if (!tmp->use)
12  return;
13  va_start(ap, b);
14  n = tmp->nuse;
15  vgrow(&tmp->use, ++tmp->nuse);
16  u = &tmp->use[n];
17  u->type = ty;
18  u->bid = b->id;
19  switch (ty) {
20  case UPhi:
21  u->u.phi = va_arg(ap, Phi *);
22  break;
23  case UIns:
24  u->u.ins = va_arg(ap, Ins *);
25  break;
26  case UJmp:
27  break;
28  default:
29  die("unreachable");
30  }
31  va_end(ap);
32 }
33 
34 /* fill usage, width, phi, and class information
35  * must not change .visit fields
36  */
37 
45 void
46 filluse(Fn *fn)
47 {
48  Blk *b;
49  Phi *p;
50  Ins *i;
51  int m, t, tp, w;
52  uint a;
53  Tmp *tmp;
54 
55  /* todo, is this the correct file? */
56  tmp = fn->tmp;
57  for (t=Tmp0; t<fn->ntmp; t++) {
58  tmp[t].ndef = 0;
59  tmp[t].nuse = 0;
60  tmp[t].cls = 0;
61  tmp[t].phi = 0;
62  tmp[t].width = WFull;
63  if (tmp[t].use == 0)
64  tmp[t].use = vnew(0, sizeof(Use), Pfn);
65  }
66  for (b=fn->start; b; b=b->link) {
67  for (p=b->phi; p; p=p->link) {
68  assert(rtype(p->to) == RTmp);
69  tp = p->to.val;
70  tmp[tp].ndef++;
71  tmp[tp].cls = p->cls;
72  tp = phicls(tp, fn->tmp);
73  for (a=0; a<p->narg; a++)
74  if (rtype(p->arg[a]) == RTmp) {
75  t = p->arg[a].val;
76  adduse(&tmp[t], UPhi, b, p);
77  t = phicls(t, fn->tmp);
78  if (t != tp)
79  tmp[t].phi = tp;
80  }
81  }
82  for (i=b->ins; i-b->ins < b->nins; i++) {
83  if (!req(i->to, R)) {
84  assert(rtype(i->to) == RTmp);
85  w = WFull;
86  if (isload(i->op) && i->op != Oload)
87  w = Wsb + (i->op - Oloadsb);
88  if (isext(i->op))
89  w = Wsb + (i->op - Oextsb);
90  if (w == Wsw || w == Wuw)
91  if (i->cls == Kw)
92  w = WFull;
93  t = i->to.val;
94  tmp[t].width = w;
95  tmp[t].ndef++;
96  tmp[t].cls = i->cls;
97  }
98  for (m=0; m<2; m++)
99  if (rtype(i->arg[m]) == RTmp) {
100  t = i->arg[m].val;
101  adduse(&tmp[t], UIns, b, i);
102  }
103  }
104  if (rtype(b->jmp.arg) == RTmp)
105  adduse(&tmp[b->jmp.arg.val], UJmp, b);
106  }
107 }
108 
109 static Ref
110 refindex(int t, Fn *fn)
111 {
112  return newtmp(fn->tmp[t].name, fn->tmp[t].cls, fn);
113 }
114 
115 static void
116 phiins(Fn *fn)
117 {
118  BSet u[1], defs[1];
119  Blk *a, *b, **blist, **be, **bp;
120  Ins *i;
121  Phi *p;
122  Ref r;
123  int t, nt;
124  uint n;
125  short k;
126 
127  bsinit(u, fn->nblk);
128  bsinit(defs, fn->nblk);
129  blist = emalloc(fn->nblk * sizeof blist[0]);
130  be = &blist[fn->nblk];
131  nt = fn->ntmp;
132  for (t=Tmp0; t<nt; t++) {
133  fn->tmp[t].visit = 0;
134  if (fn->tmp[t].phi != 0)
135  continue;
136  bszero(u);
137  k = -1;
138  bp = be;
139  for (b=fn->start; b; b=b->link) {
140  b->visit = 0;
141  r = R;
142  for (i=b->ins; i-b->ins < b->nins; i++) {
143  if (!req(r, R)) {
144  if (req(i->arg[0], TMP(t)))
145  i->arg[0] = r;
146  if (req(i->arg[1], TMP(t)))
147  i->arg[1] = r;
148  }
149  if (req(i->to, TMP(t))) {
150  if (!bshas(b->out, t)) {
151  if (fn->tmp[t].ndef == 1)
152  r = TMP(t);
153  else
154  r = refindex(t, fn);
155  i->to = r;
156  } else {
157  if (!bshas(u, b->id)) {
158  bsset(u, b->id);
159  *--bp = b;
160  }
161  if (clsmerge(&k, i->cls))
162  die("invalid input");
163  }
164  }
165  }
166  if (!req(r, R) && req(b->jmp.arg, TMP(t)))
167  b->jmp.arg = r;
168  }
169  bscopy(defs, u);
170  while (bp != be) {
171  fn->tmp[t].visit = t;
172  b = *bp++;
173  bsclr(u, b->id);
174  for (n=0; n<b->nfron; n++) {
175  a = b->fron[n];
176  if (a->visit++ == 0)
177  if (bshas(a->in, t)) {
178  p = alloc(sizeof *p);
179  p->cls = k;
180  p->to = TMP(t);
181  p->link = a->phi;
182  a->phi = p;
183  if (!bshas(defs, a->id))
184  if (!bshas(u, a->id)) {
185  bsset(u, a->id);
186  *--bp = a;
187  }
188  }
189  }
190  }
191  }
192  free(blist);
193 }
194 
195 typedef struct Name Name;
196 struct Name {
198  Blk *b;
200 };
201 
202 static Name *namel;
203 
204 static Name *
205 nnew(Ref r, Blk *b, Name *up)
206 {
207  Name *n;
208 
209  if (namel) {
210  n = namel;
211  namel = n->up;
212  } else
213  /* could use alloc, here
214  * but namel should be reset
215  */
216  n = emalloc(sizeof *n);
217  n->r = r;
218  n->b = b;
219  n->up = up;
220  return n;
221 }
222 
223 static void
224 nfree(Name *n)
225 {
226  n->up = namel;
227  namel = n;
228 }
229 
230 static void
231 rendef(Ref *r, Blk *b, Name **stk, Fn *fn)
232 {
233  Ref r1;
234  int t;
235 
236  t = r->val;
237  if (req(*r, R) || !fn->tmp[t].visit)
238  return;
239  r1 = refindex(t, fn);
240  fn->tmp[r1.val].visit = t;
241  stk[t] = nnew(r1, b, stk[t]);
242  *r = r1;
243 }
244 
245 static Ref
246 getstk(int t, Blk *b, Name **stk)
247 {
248  Name *n, *n1;
249 
250  n = stk[t];
251  while (n && !dom(n->b, b)) {
252  n1 = n;
253  n = n->up;
254  nfree(n1);
255  }
256  stk[t] = n;
257  if (!n) {
258  /* uh, oh, warn */
259  return CON_Z;
260  } else
261  return n->r;
262 }
263 
264 static void
265 renblk(Blk *b, Name **stk, Fn *fn)
266 {
267  Phi *p;
268  Ins *i;
269  Blk *s, **ps, *succ[3];
270  int t, m;
271 
272  for (p=b->phi; p; p=p->link)
273  rendef(&p->to, b, stk, fn);
274  for (i=b->ins; i-b->ins < b->nins; i++) {
275  for (m=0; m<2; m++) {
276  t = i->arg[m].val;
277  if (rtype(i->arg[m]) == RTmp)
278  if (fn->tmp[t].visit)
279  i->arg[m] = getstk(t, b, stk);
280  }
281  rendef(&i->to, b, stk, fn);
282  }
283  t = b->jmp.arg.val;
284  if (rtype(b->jmp.arg) == RTmp)
285  if (fn->tmp[t].visit)
286  b->jmp.arg = getstk(t, b, stk);
287  succ[0] = b->s1;
288  succ[1] = b->s2 == b->s1 ? 0 : b->s2;
289  succ[2] = 0;
290  for (ps=succ; (s=*ps); ps++)
291  for (p=s->phi; p; p=p->link) {
292  t = p->to.val;
293  if ((t=fn->tmp[t].visit)) {
294  m = p->narg++;
295  if (m == NPred)
296  die("renblk, too many phi args");
297  p->arg[m] = getstk(t, b, stk);
298  p->blk[m] = b;
299  }
300  }
301  for (s=b->dom; s; s=s->dlink)
302  renblk(s, stk, fn);
303 }
304 
305 /* require rpo and ndef */
306 void
307 ssa(Fn *fn)
308 {
309  Name **stk, *n;
310  int d, nt;
311  Blk *b, *b1;
312 
313  nt = fn->ntmp;
314  stk = emalloc(nt * sizeof stk[0]);
315  d = debug['L'];
316  debug['L'] = 0;
317  filldom(fn);
318  if (debug['N']) {
319  fprintf(stderr, "\n> Dominators:\n");
320  for (b1=fn->start; b1; b1=b1->link) {
321  if (!b1->dom)
322  continue;
323  fprintf(stderr, "%10s:", b1->name);
324  for (b=b1->dom; b; b=b->dlink)
325  fprintf(stderr, " %s", b->name);
326  fprintf(stderr, "\n");
327  }
328  }
329  fillfron(fn);
330  filllive(fn);
331  phiins(fn);
332  renblk(fn->start, stk, fn);
333  while (nt--)
334  while ((n=stk[nt])) {
335  stk[nt] = n->up;
336  nfree(n);
337  }
338  debug['L'] = d;
339  free(stk);
340  if (debug['N']) {
341  fprintf(stderr, "\n> After SSA construction:\n");
342  printfn(fn, stderr);
343  }
344 }
345 
346 static int
347 phicheck(Phi *p, Blk *b, Ref t)
348 {
349  Blk *b1;
350  uint n;
351 
352  for (n=0; n<p->narg; n++)
353  if (req(p->arg[n], t)) {
354  b1 = p->blk[n];
355  if (b1 != b && !sdom(b, b1))
356  return 1;
357  }
358  return 0;
359 }
360 
361 /* require use and ssa */
362 void
364 {
365  Tmp *t;
366  Ins *i;
367  Phi *p;
368  Use *u;
369  Blk *b, *bu;
370  Ref r;
371 
372  for (t=&fn->tmp[Tmp0]; t-fn->tmp < fn->ntmp; t++) {
373  if (t->ndef > 1)
374  err("ssa temporary %%%s defined more than once",
375  t->name);
376  if (t->nuse > 0 && t->ndef == 0) {
377  bu = fn->rpo[t->use[0].bid];
378  goto Err;
379  }
380  }
381  for (b=fn->start; b; b=b->link) {
382  for (p=b->phi; p; p=p->link) {
383  r = p->to;
384  t = &fn->tmp[r.val];
385  for (u=t->use; u-t->use < t->nuse; u++) {
386  bu = fn->rpo[u->bid];
387  if (u->type == UPhi) {
388  if (phicheck(u->u.phi, b, r))
389  goto Err;
390  } else
391  if (bu != b && !sdom(b, bu))
392  goto Err;
393  }
394  }
395  for (i=b->ins; i-b->ins < b->nins; i++) {
396  if (rtype(i->to) != RTmp)
397  continue;
398  r = i->to;
399  t = &fn->tmp[r.val];
400  for (u=t->use; u-t->use < t->nuse; u++) {
401  bu = fn->rpo[u->bid];
402  if (u->type == UPhi) {
403  if (phicheck(u->u.phi, b, r))
404  goto Err;
405  } else {
406  if (bu == b) {
407  if (u->type == UIns)
408  if (u->u.ins <= i)
409  goto Err;
410  } else
411  if (!sdom(b, bu))
412  goto Err;
413  }
414  }
415  }
416  }
417  return;
418 Err:
419  if (t->visit)
420  die("%%%s violates ssa invariant", t->name);
421  else
422  err("ssa temporary %%%s is used undefined in @%s",
423  t->name, bu->name);
424 }
Definition: ssa.c:196
unsigned int uint
Definition: all.h:12
char name[NString]
Definition: all.h:279
void bsset(BSet *, uint)
Definition: util.c:467
void filllive(Fn *)
Definition: live.c:39
Blk * start
Указатель на блок функции, являющийся её входной точкой
Definition: all.h:385
int sdom(Blk *, Blk *)
Definition: cfg.c:187
void * emalloc(size_t)
Definition: util.c:66
uint narg
Definition: all.h:246
Структура, хранящая информацию об инструкциях.
Definition: all.h:235
Blk * dlink
Definition: all.h:270
enum Tmp::@10 width
Definition: all.h:251
int clsmerge(short *, short)
Definition: util.c:296
Definition: all.h:242
int visit
Definition: all.h:350
Definition: all.h:84
int bid
Definition: all.h:293
void * vnew(ulong, size_t, Pool)
Definition: util.c:111
Phi * link
Definition: all.h:248
Blk * s1
Definition: all.h:262
uint ndef
Количество блоков, в которых есть объявление переменной
Definition: all.h:329
int phi
Definition: all.h:339
Definition: all.h:66
void bsinit(BSet *, uint)
Definition: util.c:403
void bscopy(BSet *, BSet *)
Definition: util.c:491
Ref arg[NPred]
Definition: all.h:244
Definition: all.h:213
Структура, хранящая описание переменных (более подробное описание переменной ищите в Tmp)...
Definition: all.h:77
Содержит информацию о переменной
Definition: all.h:326
void err(char *,...) __attribute__((noreturn))
Definition: parse.c:134
Tmp * tmp
Массив используемых функцией переменных
Definition: all.h:386
Ref arg
Definition: all.h:260
Use * use
Содержит информацию об использовании переменной
Definition: all.h:328
union Use::@7 u
#define CON_Z
Definition: all.h:95
Ref to
Definition: all.h:243
BSet in[1]
Definition: all.h:276
int ntmp
Размер массива tmp.
Definition: all.h:389
Blk * s2
Definition: all.h:263
Непосредственно информация о базовом блоке.
Definition: all.h:254
void * alloc(size_t)
Definition: util.c:77
void fillfron(Fn *)
Definition: cfg.c:220
void printfn(Fn *, FILE *)
Definition: parse.c:1160
#define TMP(x)
Definition: all.h:93
Blk * link
Definition: all.h:264
void bszero(BSet *)
Definition: util.c:509
#define isext(o)
Definition: all.h:206
uint nins
Definition: all.h:257
char name[NString]
Имя переменной
Definition: all.h:327
Definition: all.h:460
short cls
Definition: all.h:333
Ins * ins
Definition: all.h:295
uint visit
Definition: all.h:267
Ref to
Definition: all.h:237
void vgrow(void *, ulong)
Definition: util.c:142
void bsclr(BSet *, uint)
Definition: util.c:474
Blk * b
Definition: ssa.c:198
uint nblk
Количество блоков в функции
Definition: all.h:392
void filldom(Fn *)
Definition: cfg.c:152
#define isload(o)
Definition: all.h:205
Ins * ins
Definition: all.h:256
Phi * phi
Definition: all.h:255
Blk ** rpo
Ссылка на массив блоков, пронумерованных в порядке Reverse-Post Order, заполняется функцией fillrpo...
Definition: all.h:395
Ref arg[2]
Definition: all.h:238
Номер (в массиве Fn->tmp) первой не регистровой переменной
Definition: all.h:63
void filluse(Fn *fn)
Заполняет информацию об использовании переменных в функции
Definition: ssa.c:46
Definition: all.h:248
#define die(...)
Definition: all.h:9
Blk * dom
Definition: all.h:270
uint val
Definition: all.h:80
enum Use::@6 type
uint id
Definition: all.h:266
BSet out[1]
Definition: all.h:276
void ssacheck(Fn *fn)
Definition: ssa.c:363
int phicls(int, Tmp *)
Definition: util.c:313
int cls
Definition: all.h:247
Ref newtmp(char *, int, Fn *)
Definition: util.c:326
#define R
Definition: all.h:92
Ref r
Definition: ssa.c:197
uint cls
Definition: all.h:239
uint nfron
Definition: all.h:272
Blk * blk[NPred]
Definition: all.h:245
struct Blk::@5 jmp
int dom(Blk *, Blk *)
Definition: cfg.c:198
Структура, хранящая в себе информацию о функции
Definition: all.h:384
uint nuse
Количество блоков, в которых переменная используется
Definition: all.h:329
void ssa(Fn *fn)
Definition: ssa.c:307
uint op
Definition: all.h:236
char debug['Z'+1]
Definition: all.h:35
Definition: all.h:242
Name * up
Definition: ssa.c:199
Blk ** fron
Definition: all.h:271
Структура, хранящая информацию об одном "использовании" переменной.
Definition: all.h:286
Phi * phi
Definition: all.h:296