new large test to evaluate performance
[qbe.git] / ssa.c
blobc09843862c3c0d572a0c31f59b2950690f4a2806
1 #include "all.h"
2 #include <stdarg.h>
4 static void
5 adduse(Tmp *tmp, int ty, Blk *b, ...)
7 Use *u;
8 int n;
9 va_list ap;
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");
31 va_end(ap);
34 /* fill usage, width, phi, and class information
35 * must not change .visit fields
37 void
38 filluse(Fn *fn)
40 Blk *b;
41 Phi *p;
42 Ins *i;
43 int m, t, tp, w;
44 uint a;
45 Tmp *tmp;
47 /* todo, is this the correct file? */
48 tmp = fn->tmp;
49 for (t=Tmp0; t<fn->ntmp; t++) {
50 tmp[t].bid = -1u;
51 tmp[t].ndef = 0;
52 tmp[t].nuse = 0;
53 tmp[t].cls = 0;
54 tmp[t].phi = 0;
55 tmp[t].width = WFull;
56 if (tmp[t].use == 0)
57 tmp[t].use = vnew(0, sizeof(Use), Pfn);
59 for (b=fn->start; b; b=b->link) {
60 for (p=b->phi; p; p=p->link) {
61 assert(rtype(p->to) == RTmp);
62 tp = p->to.val;
63 tmp[tp].bid = b->id;
64 tmp[tp].ndef++;
65 tmp[tp].cls = p->cls;
66 tp = phicls(tp, fn->tmp);
67 for (a=0; a<p->narg; a++)
68 if (rtype(p->arg[a]) == RTmp) {
69 t = p->arg[a].val;
70 adduse(&tmp[t], UPhi, b, p);
71 t = phicls(t, fn->tmp);
72 if (t != tp)
73 tmp[t].phi = tp;
76 for (i=b->ins; i<&b->ins[b->nins]; i++) {
77 if (!req(i->to, R)) {
78 assert(rtype(i->to) == RTmp);
79 w = WFull;
80 if (isload(i->op) && i->op != Oload)
81 w = Wsb + (i->op - Oloadsb);
82 if (isext(i->op))
83 w = Wsb + (i->op - Oextsb);
84 if (w == Wsw || w == Wuw)
85 if (i->cls == Kw)
86 w = WFull;
87 t = i->to.val;
88 tmp[t].width = w;
89 tmp[t].bid = b->id;
90 tmp[t].ndef++;
91 tmp[t].cls = i->cls;
93 for (m=0; m<2; m++)
94 if (rtype(i->arg[m]) == RTmp) {
95 t = i->arg[m].val;
96 adduse(&tmp[t], UIns, b, i);
99 if (rtype(b->jmp.arg) == RTmp)
100 adduse(&tmp[b->jmp.arg.val], UJmp, b);
104 static Ref
105 refindex(int t, Fn *fn)
107 return newtmp(fn->tmp[t].name, fn->tmp[t].cls, fn);
110 static void
111 phiins(Fn *fn)
113 BSet u[1], defs[1];
114 Blk *a, *b, **blist, **be, **bp;
115 Ins *i;
116 Phi *p;
117 Use *use;
118 Ref r;
119 int t, nt, ok;
120 uint n, defb;
121 short k;
123 bsinit(u, fn->nblk);
124 bsinit(defs, fn->nblk);
125 blist = emalloc(fn->nblk * sizeof blist[0]);
126 be = &blist[fn->nblk];
127 nt = fn->ntmp;
128 for (t=Tmp0; t<nt; t++) {
129 fn->tmp[t].visit = 0;
130 if (fn->tmp[t].phi != 0)
131 continue;
132 if (fn->tmp[t].ndef == 1) {
133 ok = 1;
134 defb = fn->tmp[t].bid;
135 use = fn->tmp[t].use;
136 for (n=fn->tmp[t].nuse; n--; use++)
137 ok &= use->bid == defb;
138 if (ok || defb == fn->start->id)
139 continue;
141 bszero(u);
142 k = -1;
143 bp = be;
144 for (b=fn->start; b; b=b->link) {
145 b->visit = 0;
146 r = R;
147 for (i=b->ins; i<&b->ins[b->nins]; i++) {
148 if (!req(r, R)) {
149 if (req(i->arg[0], TMP(t)))
150 i->arg[0] = r;
151 if (req(i->arg[1], TMP(t)))
152 i->arg[1] = r;
154 if (req(i->to, TMP(t))) {
155 if (!bshas(b->out, t)) {
156 r = refindex(t, fn);
157 i->to = r;
158 } else {
159 if (!bshas(u, b->id)) {
160 bsset(u, b->id);
161 *--bp = b;
163 if (clsmerge(&k, i->cls))
164 die("invalid input");
168 if (!req(r, R) && req(b->jmp.arg, TMP(t)))
169 b->jmp.arg = r;
171 bscopy(defs, u);
172 while (bp != be) {
173 fn->tmp[t].visit = t;
174 b = *bp++;
175 bsclr(u, b->id);
176 for (n=0; n<b->nfron; n++) {
177 a = b->fron[n];
178 if (a->visit++ == 0)
179 if (bshas(a->in, t)) {
180 p = alloc(sizeof *p);
181 p->cls = k;
182 p->to = TMP(t);
183 p->link = a->phi;
184 a->phi = p;
185 if (!bshas(defs, a->id))
186 if (!bshas(u, a->id)) {
187 bsset(u, a->id);
188 *--bp = a;
194 free(blist);
197 typedef struct Name Name;
198 struct Name {
199 Ref r;
200 Blk *b;
201 Name *up;
204 static Name *namel;
206 static Name *
207 nnew(Ref r, Blk *b, Name *up)
209 Name *n;
211 if (namel) {
212 n = namel;
213 namel = n->up;
214 } else
215 /* could use alloc, here
216 * but namel should be reset
218 n = emalloc(sizeof *n);
219 n->r = r;
220 n->b = b;
221 n->up = up;
222 return n;
225 static void
226 nfree(Name *n)
228 n->up = namel;
229 namel = n;
232 static void
233 rendef(Ref *r, Blk *b, Name **stk, Fn *fn)
235 Ref r1;
236 int t;
238 t = r->val;
239 if (req(*r, R) || !fn->tmp[t].visit)
240 return;
241 r1 = refindex(t, fn);
242 fn->tmp[r1.val].visit = t;
243 stk[t] = nnew(r1, b, stk[t]);
244 *r = r1;
247 static Ref
248 getstk(int t, Blk *b, Name **stk)
250 Name *n, *n1;
252 n = stk[t];
253 while (n && !dom(n->b, b)) {
254 n1 = n;
255 n = n->up;
256 nfree(n1);
258 stk[t] = n;
259 if (!n) {
260 /* uh, oh, warn */
261 return CON_Z;
262 } else
263 return n->r;
266 static void
267 renblk(Blk *b, Name **stk, Fn *fn)
269 Phi *p;
270 Ins *i;
271 Blk *s, **ps, *succ[3];
272 int t, m;
274 for (p=b->phi; p; p=p->link)
275 rendef(&p->to, b, stk, fn);
276 for (i=b->ins; i<&b->ins[b->nins]; i++) {
277 for (m=0; m<2; m++) {
278 t = i->arg[m].val;
279 if (rtype(i->arg[m]) == RTmp)
280 if (fn->tmp[t].visit)
281 i->arg[m] = getstk(t, b, stk);
283 rendef(&i->to, b, stk, fn);
285 t = b->jmp.arg.val;
286 if (rtype(b->jmp.arg) == RTmp)
287 if (fn->tmp[t].visit)
288 b->jmp.arg = getstk(t, b, stk);
289 succ[0] = b->s1;
290 succ[1] = b->s2 == b->s1 ? 0 : b->s2;
291 succ[2] = 0;
292 for (ps=succ; (s=*ps); ps++)
293 for (p=s->phi; p; p=p->link) {
294 t = p->to.val;
295 if ((t=fn->tmp[t].visit)) {
296 m = p->narg++;
297 if (m == NPred)
298 die("renblk, too many phi args");
299 p->arg[m] = getstk(t, b, stk);
300 p->blk[m] = b;
303 for (s=b->dom; s; s=s->dlink)
304 renblk(s, stk, fn);
307 /* require rpo and use */
308 void
309 ssa(Fn *fn)
311 Name **stk, *n;
312 int d, nt;
313 Blk *b, *b1;
315 nt = fn->ntmp;
316 stk = emalloc(nt * sizeof stk[0]);
317 d = debug['L'];
318 debug['L'] = 0;
319 filldom(fn);
320 if (debug['N']) {
321 fprintf(stderr, "\n> Dominators:\n");
322 for (b1=fn->start; b1; b1=b1->link) {
323 if (!b1->dom)
324 continue;
325 fprintf(stderr, "%10s:", b1->name);
326 for (b=b1->dom; b; b=b->dlink)
327 fprintf(stderr, " %s", b->name);
328 fprintf(stderr, "\n");
331 fillfron(fn);
332 filllive(fn);
333 phiins(fn);
334 renblk(fn->start, stk, fn);
335 while (nt--)
336 while ((n=stk[nt])) {
337 stk[nt] = n->up;
338 nfree(n);
340 debug['L'] = d;
341 free(stk);
342 if (debug['N']) {
343 fprintf(stderr, "\n> After SSA construction:\n");
344 printfn(fn, stderr);
348 static int
349 phicheck(Phi *p, Blk *b, Ref t)
351 Blk *b1;
352 uint n;
354 for (n=0; n<p->narg; n++)
355 if (req(p->arg[n], t)) {
356 b1 = p->blk[n];
357 if (b1 != b && !sdom(b, b1))
358 return 1;
360 return 0;
363 /* require use and ssa */
364 void
365 ssacheck(Fn *fn)
367 Tmp *t;
368 Ins *i;
369 Phi *p;
370 Use *u;
371 Blk *b, *bu;
372 Ref r;
374 for (t=&fn->tmp[Tmp0]; t-fn->tmp < fn->ntmp; t++) {
375 if (t->ndef > 1)
376 err("ssa temporary %%%s defined more than once",
377 t->name);
378 if (t->nuse > 0 && t->ndef == 0) {
379 bu = fn->rpo[t->use[0].bid];
380 goto Err;
383 for (b=fn->start; b; b=b->link) {
384 for (p=b->phi; p; p=p->link) {
385 r = p->to;
386 t = &fn->tmp[r.val];
387 for (u=t->use; u<&t->use[t->nuse]; u++) {
388 bu = fn->rpo[u->bid];
389 if (u->type == UPhi) {
390 if (phicheck(u->u.phi, b, r))
391 goto Err;
392 } else
393 if (bu != b && !sdom(b, bu))
394 goto Err;
397 for (i=b->ins; i<&b->ins[b->nins]; i++) {
398 if (rtype(i->to) != RTmp)
399 continue;
400 r = i->to;
401 t = &fn->tmp[r.val];
402 for (u=t->use; u<&t->use[t->nuse]; u++) {
403 bu = fn->rpo[u->bid];
404 if (u->type == UPhi) {
405 if (phicheck(u->u.phi, b, r))
406 goto Err;
407 } else {
408 if (bu == b) {
409 if (u->type == UIns)
410 if (u->u.ins <= i)
411 goto Err;
412 } else
413 if (!sdom(b, bu))
414 goto Err;
419 return;
420 Err:
421 if (t->visit)
422 die("%%%s violates ssa invariant", t->name);
423 else
424 err("ssa temporary %%%s is used undefined in @%s",
425 t->name, bu->name);