refine width of parsb/ub/sh/uh ops
[qbe.git] / ssa.c
blob126113de9b9827c9e8a8b59f4b55d91bcd3b79eb
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 (isparbh(i->op))
81 w = Wsb + (i->op - Oparsb);
82 if (isload(i->op) && i->op != Oload)
83 w = Wsb + (i->op - Oloadsb);
84 if (isext(i->op))
85 w = Wsb + (i->op - Oextsb);
86 if (w == Wsw || w == Wuw)
87 if (i->cls == Kw)
88 w = WFull;
89 t = i->to.val;
90 tmp[t].width = w;
91 tmp[t].bid = b->id;
92 tmp[t].ndef++;
93 tmp[t].cls = i->cls;
95 for (m=0; m<2; m++)
96 if (rtype(i->arg[m]) == RTmp) {
97 t = i->arg[m].val;
98 adduse(&tmp[t], UIns, b, i);
101 if (rtype(b->jmp.arg) == RTmp)
102 adduse(&tmp[b->jmp.arg.val], UJmp, b);
106 static Ref
107 refindex(int t, Fn *fn)
109 return newtmp(fn->tmp[t].name, fn->tmp[t].cls, fn);
112 static void
113 phiins(Fn *fn)
115 BSet u[1], defs[1];
116 Blk *a, *b, **blist, **be, **bp;
117 Ins *i;
118 Phi *p;
119 Use *use;
120 Ref r;
121 int t, nt, ok;
122 uint n, defb;
123 short k;
125 bsinit(u, fn->nblk);
126 bsinit(defs, fn->nblk);
127 blist = emalloc(fn->nblk * sizeof blist[0]);
128 be = &blist[fn->nblk];
129 nt = fn->ntmp;
130 for (t=Tmp0; t<nt; t++) {
131 fn->tmp[t].visit = 0;
132 if (fn->tmp[t].phi != 0)
133 continue;
134 if (fn->tmp[t].ndef == 1) {
135 ok = 1;
136 defb = fn->tmp[t].bid;
137 use = fn->tmp[t].use;
138 for (n=fn->tmp[t].nuse; n--; use++)
139 ok &= use->bid == defb;
140 if (ok || defb == fn->start->id)
141 continue;
143 bszero(u);
144 k = -1;
145 bp = be;
146 for (b=fn->start; b; b=b->link) {
147 b->visit = 0;
148 r = R;
149 for (i=b->ins; i<&b->ins[b->nins]; i++) {
150 if (!req(r, R)) {
151 if (req(i->arg[0], TMP(t)))
152 i->arg[0] = r;
153 if (req(i->arg[1], TMP(t)))
154 i->arg[1] = r;
156 if (req(i->to, TMP(t))) {
157 if (!bshas(b->out, t)) {
158 r = refindex(t, fn);
159 i->to = r;
160 } else {
161 if (!bshas(u, b->id)) {
162 bsset(u, b->id);
163 *--bp = b;
165 if (clsmerge(&k, i->cls))
166 die("invalid input");
170 if (!req(r, R) && req(b->jmp.arg, TMP(t)))
171 b->jmp.arg = r;
173 bscopy(defs, u);
174 while (bp != be) {
175 fn->tmp[t].visit = t;
176 b = *bp++;
177 bsclr(u, b->id);
178 for (n=0; n<b->nfron; n++) {
179 a = b->fron[n];
180 if (a->visit++ == 0)
181 if (bshas(a->in, t)) {
182 p = alloc(sizeof *p);
183 p->cls = k;
184 p->to = TMP(t);
185 p->link = a->phi;
186 p->arg = vnew(0, sizeof p->arg[0], Pfn);
187 p->blk = vnew(0, sizeof p->blk[0], Pfn);
188 a->phi = p;
189 if (!bshas(defs, a->id))
190 if (!bshas(u, a->id)) {
191 bsset(u, a->id);
192 *--bp = a;
198 free(blist);
201 typedef struct Name Name;
202 struct Name {
203 Ref r;
204 Blk *b;
205 Name *up;
208 static Name *namel;
210 static Name *
211 nnew(Ref r, Blk *b, Name *up)
213 Name *n;
215 if (namel) {
216 n = namel;
217 namel = n->up;
218 } else
219 /* could use alloc, here
220 * but namel should be reset
222 n = emalloc(sizeof *n);
223 n->r = r;
224 n->b = b;
225 n->up = up;
226 return n;
229 static void
230 nfree(Name *n)
232 n->up = namel;
233 namel = n;
236 static void
237 rendef(Ref *r, Blk *b, Name **stk, Fn *fn)
239 Ref r1;
240 int t;
242 t = r->val;
243 if (req(*r, R) || !fn->tmp[t].visit)
244 return;
245 r1 = refindex(t, fn);
246 fn->tmp[r1.val].visit = t;
247 stk[t] = nnew(r1, b, stk[t]);
248 *r = r1;
251 static Ref
252 getstk(int t, Blk *b, Name **stk)
254 Name *n, *n1;
256 n = stk[t];
257 while (n && !dom(n->b, b)) {
258 n1 = n;
259 n = n->up;
260 nfree(n1);
262 stk[t] = n;
263 if (!n) {
264 /* uh, oh, warn */
265 return CON_Z;
266 } else
267 return n->r;
270 static void
271 renblk(Blk *b, Name **stk, Fn *fn)
273 Phi *p;
274 Ins *i;
275 Blk *s, **ps, *succ[3];
276 int t, m;
278 for (p=b->phi; p; p=p->link)
279 rendef(&p->to, b, stk, fn);
280 for (i=b->ins; i<&b->ins[b->nins]; i++) {
281 for (m=0; m<2; m++) {
282 t = i->arg[m].val;
283 if (rtype(i->arg[m]) == RTmp)
284 if (fn->tmp[t].visit)
285 i->arg[m] = getstk(t, b, stk);
287 rendef(&i->to, b, stk, fn);
289 t = b->jmp.arg.val;
290 if (rtype(b->jmp.arg) == RTmp)
291 if (fn->tmp[t].visit)
292 b->jmp.arg = getstk(t, b, stk);
293 succ[0] = b->s1;
294 succ[1] = b->s2 == b->s1 ? 0 : b->s2;
295 succ[2] = 0;
296 for (ps=succ; (s=*ps); ps++)
297 for (p=s->phi; p; p=p->link) {
298 t = p->to.val;
299 if ((t=fn->tmp[t].visit)) {
300 m = p->narg++;
301 vgrow(&p->arg, p->narg);
302 vgrow(&p->blk, p->narg);
303 p->arg[m] = getstk(t, b, stk);
304 p->blk[m] = b;
307 for (s=b->dom; s; s=s->dlink)
308 renblk(s, stk, fn);
311 /* require rpo and use */
312 void
313 ssa(Fn *fn)
315 Name **stk, *n;
316 int d, nt;
317 Blk *b, *b1;
319 nt = fn->ntmp;
320 stk = emalloc(nt * sizeof stk[0]);
321 d = debug['L'];
322 debug['L'] = 0;
323 filldom(fn);
324 if (debug['N']) {
325 fprintf(stderr, "\n> Dominators:\n");
326 for (b1=fn->start; b1; b1=b1->link) {
327 if (!b1->dom)
328 continue;
329 fprintf(stderr, "%10s:", b1->name);
330 for (b=b1->dom; b; b=b->dlink)
331 fprintf(stderr, " %s", b->name);
332 fprintf(stderr, "\n");
335 fillfron(fn);
336 filllive(fn);
337 phiins(fn);
338 renblk(fn->start, stk, fn);
339 while (nt--)
340 while ((n=stk[nt])) {
341 stk[nt] = n->up;
342 nfree(n);
344 debug['L'] = d;
345 free(stk);
346 if (debug['N']) {
347 fprintf(stderr, "\n> After SSA construction:\n");
348 printfn(fn, stderr);
352 static int
353 phicheck(Phi *p, Blk *b, Ref t)
355 Blk *b1;
356 uint n;
358 for (n=0; n<p->narg; n++)
359 if (req(p->arg[n], t)) {
360 b1 = p->blk[n];
361 if (b1 != b && !sdom(b, b1))
362 return 1;
364 return 0;
367 /* require use and ssa */
368 void
369 ssacheck(Fn *fn)
371 Tmp *t;
372 Ins *i;
373 Phi *p;
374 Use *u;
375 Blk *b, *bu;
376 Ref r;
378 for (t=&fn->tmp[Tmp0]; t-fn->tmp < fn->ntmp; t++) {
379 if (t->ndef > 1)
380 err("ssa temporary %%%s defined more than once",
381 t->name);
382 if (t->nuse > 0 && t->ndef == 0) {
383 bu = fn->rpo[t->use[0].bid];
384 goto Err;
387 for (b=fn->start; b; b=b->link) {
388 for (p=b->phi; p; p=p->link) {
389 r = p->to;
390 t = &fn->tmp[r.val];
391 for (u=t->use; u<&t->use[t->nuse]; u++) {
392 bu = fn->rpo[u->bid];
393 if (u->type == UPhi) {
394 if (phicheck(u->u.phi, b, r))
395 goto Err;
396 } else
397 if (bu != b && !sdom(b, bu))
398 goto Err;
401 for (i=b->ins; i<&b->ins[b->nins]; i++) {
402 if (rtype(i->to) != RTmp)
403 continue;
404 r = i->to;
405 t = &fn->tmp[r.val];
406 for (u=t->use; u<&t->use[t->nuse]; u++) {
407 bu = fn->rpo[u->bid];
408 if (u->type == UPhi) {
409 if (phicheck(u->u.phi, b, r))
410 goto Err;
411 } else {
412 if (bu == b) {
413 if (u->type == UIns)
414 if (u->u.ins <= i)
415 goto Err;
416 } else
417 if (!sdom(b, bu))
418 goto Err;
423 return;
424 Err:
425 if (t->visit)
426 die("%%%s violates ssa invariant", t->name);
427 else
428 err("ssa temporary %%%s is used undefined in @%s",
429 t->name, bu->name);