Fix 1 C UB
[qbe.git] / ssa.c
blob356135b616ece6830eb8499d3a95a4ac67438232
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].def = 0;
51 tmp[t].bid = -1u;
52 tmp[t].ndef = 0;
53 tmp[t].nuse = 0;
54 tmp[t].cls = 0;
55 tmp[t].phi = 0;
56 tmp[t].width = WFull;
57 if (tmp[t].use == 0)
58 tmp[t].use = vnew(0, sizeof(Use), PFn);
60 for (b=fn->start; b; b=b->link) {
61 for (p=b->phi; p; p=p->link) {
62 assert(rtype(p->to) == RTmp);
63 tp = p->to.val;
64 tmp[tp].bid = b->id;
65 tmp[tp].ndef++;
66 tmp[tp].cls = p->cls;
67 tp = phicls(tp, fn->tmp);
68 for (a=0; a<p->narg; a++)
69 if (rtype(p->arg[a]) == RTmp) {
70 t = p->arg[a].val;
71 adduse(&tmp[t], UPhi, b, p);
72 t = phicls(t, fn->tmp);
73 if (t != tp)
74 tmp[t].phi = tp;
77 for (i=b->ins; i<&b->ins[b->nins]; i++) {
78 if (!req(i->to, R)) {
79 assert(rtype(i->to) == RTmp);
80 w = WFull;
81 if (isparbh(i->op))
82 w = Wsb + (i->op - Oparsb);
83 if (isload(i->op) && i->op != Oload)
84 w = Wsb + (i->op - Oloadsb);
85 if (isext(i->op))
86 w = Wsb + (i->op - Oextsb);
87 if (w == Wsw || w == Wuw)
88 if (i->cls == Kw)
89 w = WFull;
90 t = i->to.val;
91 tmp[t].width = w;
92 tmp[t].def = i;
93 tmp[t].bid = b->id;
94 tmp[t].ndef++;
95 tmp[t].cls = i->cls;
97 for (m=0; m<2; m++)
98 if (rtype(i->arg[m]) == RTmp) {
99 t = i->arg[m].val;
100 adduse(&tmp[t], UIns, b, i);
103 if (rtype(b->jmp.arg) == RTmp)
104 adduse(&tmp[b->jmp.arg.val], UJmp, b);
108 static Ref
109 refindex(int t, Fn *fn)
111 return newtmp(fn->tmp[t].name, fn->tmp[t].cls, fn);
114 static void
115 phiins(Fn *fn)
117 BSet u[1], defs[1];
118 Blk *a, *b, **blist, **be, **bp;
119 Ins *i;
120 Phi *p;
121 Use *use;
122 Ref r;
123 int t, nt, ok;
124 uint n, defb;
125 short k;
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 if (fn->tmp[t].ndef == 1) {
137 ok = 1;
138 defb = fn->tmp[t].bid;
139 use = fn->tmp[t].use;
140 for (n=fn->tmp[t].nuse; n--; use++)
141 ok &= use->bid == defb;
142 if (ok || defb == fn->start->id)
143 continue;
145 bszero(u);
146 k = -1;
147 bp = be;
148 for (b=fn->start; b; b=b->link) {
149 b->visit = 0;
150 r = R;
151 for (i=b->ins; i<&b->ins[b->nins]; i++) {
152 if (!req(r, R)) {
153 if (req(i->arg[0], TMP(t)))
154 i->arg[0] = r;
155 if (req(i->arg[1], TMP(t)))
156 i->arg[1] = r;
158 if (req(i->to, TMP(t))) {
159 if (!bshas(b->out, t)) {
160 r = refindex(t, fn);
161 i->to = r;
162 } else {
163 if (!bshas(u, b->id)) {
164 bsset(u, b->id);
165 *--bp = b;
167 if (clsmerge(&k, i->cls))
168 die("invalid input");
172 if (!req(r, R) && req(b->jmp.arg, TMP(t)))
173 b->jmp.arg = r;
175 bscopy(defs, u);
176 while (bp != be) {
177 fn->tmp[t].visit = t;
178 b = *bp++;
179 bsclr(u, b->id);
180 for (n=0; n<b->nfron; n++) {
181 a = b->fron[n];
182 if (a->visit++ == 0)
183 if (bshas(a->in, t)) {
184 p = alloc(sizeof *p);
185 p->cls = k;
186 p->to = TMP(t);
187 p->link = a->phi;
188 p->arg = vnew(0, sizeof p->arg[0], PFn);
189 p->blk = vnew(0, sizeof p->blk[0], PFn);
190 a->phi = p;
191 if (!bshas(defs, a->id))
192 if (!bshas(u, a->id)) {
193 bsset(u, a->id);
194 *--bp = a;
200 free(blist);
203 typedef struct Name Name;
204 struct Name {
205 Ref r;
206 Blk *b;
207 Name *up;
210 static Name *namel;
212 static Name *
213 nnew(Ref r, Blk *b, Name *up)
215 Name *n;
217 if (namel) {
218 n = namel;
219 namel = n->up;
220 } else
221 /* could use alloc, here
222 * but namel should be reset
224 n = emalloc(sizeof *n);
225 n->r = r;
226 n->b = b;
227 n->up = up;
228 return n;
231 static void
232 nfree(Name *n)
234 n->up = namel;
235 namel = n;
238 static void
239 rendef(Ref *r, Blk *b, Name **stk, Fn *fn)
241 Ref r1;
242 int t;
244 t = r->val;
245 if (req(*r, R) || !fn->tmp[t].visit)
246 return;
247 r1 = refindex(t, fn);
248 fn->tmp[r1.val].visit = t;
249 stk[t] = nnew(r1, b, stk[t]);
250 *r = r1;
253 static Ref
254 getstk(int t, Blk *b, Name **stk)
256 Name *n, *n1;
258 n = stk[t];
259 while (n && !dom(n->b, b)) {
260 n1 = n;
261 n = n->up;
262 nfree(n1);
264 stk[t] = n;
265 if (!n) {
266 /* uh, oh, warn */
267 return UNDEF;
268 } else
269 return n->r;
272 static void
273 renblk(Blk *b, Name **stk, Fn *fn)
275 Phi *p;
276 Ins *i;
277 Blk *s, **ps, *succ[3];
278 int t, m;
280 for (p=b->phi; p; p=p->link)
281 rendef(&p->to, b, stk, fn);
282 for (i=b->ins; i<&b->ins[b->nins]; i++) {
283 for (m=0; m<2; m++) {
284 t = i->arg[m].val;
285 if (rtype(i->arg[m]) == RTmp)
286 if (fn->tmp[t].visit)
287 i->arg[m] = getstk(t, b, stk);
289 rendef(&i->to, b, stk, fn);
291 t = b->jmp.arg.val;
292 if (rtype(b->jmp.arg) == RTmp)
293 if (fn->tmp[t].visit)
294 b->jmp.arg = getstk(t, b, stk);
295 succ[0] = b->s1;
296 succ[1] = b->s2 == b->s1 ? 0 : b->s2;
297 succ[2] = 0;
298 for (ps=succ; (s=*ps); ps++)
299 for (p=s->phi; p; p=p->link) {
300 t = p->to.val;
301 if ((t=fn->tmp[t].visit)) {
302 m = p->narg++;
303 vgrow(&p->arg, p->narg);
304 vgrow(&p->blk, p->narg);
305 p->arg[m] = getstk(t, b, stk);
306 p->blk[m] = b;
309 for (s=b->dom; s; s=s->dlink)
310 renblk(s, stk, fn);
313 /* require rpo and use */
314 void
315 ssa(Fn *fn)
317 Name **stk, *n;
318 int d, nt;
319 Blk *b, *b1;
321 nt = fn->ntmp;
322 stk = emalloc(nt * sizeof stk[0]);
323 d = debug['L'];
324 debug['L'] = 0;
325 filldom(fn);
326 if (debug['N']) {
327 fprintf(stderr, "\n> Dominators:\n");
328 for (b1=fn->start; b1; b1=b1->link) {
329 if (!b1->dom)
330 continue;
331 fprintf(stderr, "%10s:", b1->name);
332 for (b=b1->dom; b; b=b->dlink)
333 fprintf(stderr, " %s", b->name);
334 fprintf(stderr, "\n");
337 fillfron(fn);
338 filllive(fn);
339 phiins(fn);
340 renblk(fn->start, stk, fn);
341 while (nt--)
342 while ((n=stk[nt])) {
343 stk[nt] = n->up;
344 nfree(n);
346 debug['L'] = d;
347 free(stk);
348 if (debug['N']) {
349 fprintf(stderr, "\n> After SSA construction:\n");
350 printfn(fn, stderr);
354 static int
355 phicheck(Phi *p, Blk *b, Ref t)
357 Blk *b1;
358 uint n;
360 for (n=0; n<p->narg; n++)
361 if (req(p->arg[n], t)) {
362 b1 = p->blk[n];
363 if (b1 != b && !sdom(b, b1))
364 return 1;
366 return 0;
369 /* require use and ssa */
370 void
371 ssacheck(Fn *fn)
373 Tmp *t;
374 Ins *i;
375 Phi *p;
376 Use *u;
377 Blk *b, *bu;
378 Ref r;
380 for (t=&fn->tmp[Tmp0]; t-fn->tmp < fn->ntmp; t++) {
381 if (t->ndef > 1)
382 err("ssa temporary %%%s defined more than once",
383 t->name);
384 if (t->nuse > 0 && t->ndef == 0) {
385 bu = fn->rpo[t->use[0].bid];
386 goto Err;
389 for (b=fn->start; b; b=b->link) {
390 for (p=b->phi; p; p=p->link) {
391 r = p->to;
392 t = &fn->tmp[r.val];
393 for (u=t->use; u<&t->use[t->nuse]; u++) {
394 bu = fn->rpo[u->bid];
395 if (u->type == UPhi) {
396 if (phicheck(u->u.phi, b, r))
397 goto Err;
398 } else
399 if (bu != b && !sdom(b, bu))
400 goto Err;
403 for (i=b->ins; i<&b->ins[b->nins]; i++) {
404 if (rtype(i->to) != RTmp)
405 continue;
406 r = i->to;
407 t = &fn->tmp[r.val];
408 for (u=t->use; u<&t->use[t->nuse]; u++) {
409 bu = fn->rpo[u->bid];
410 if (u->type == UPhi) {
411 if (phicheck(u->u.phi, b, r))
412 goto Err;
413 } else {
414 if (bu == b) {
415 if (u->type == UIns)
416 if (u->u.ins <= i)
417 goto Err;
418 } else
419 if (!sdom(b, bu))
420 goto Err;
425 return;
426 Err:
427 if (t->visit)
428 die("%%%s violates ssa invariant", t->name);
429 else
430 err("ssa temporary %%%s is used undefined in @%s",
431 t->name, bu->name);