History

new UNDEF Ref

Crashing loads of uninitialized memory proved to be a problem when implementing unions using qbe. This patch introduces a new UNDEF Ref to represent data that is known to be uninitialized. Optimization passes can make use of it to eliminate some code. In the last compilation stages, UNDEF is treated as the constant 0xdeaddead.

Quentin Carbonneaux committed 3 years ago

Commit 5e972691 parent c5cd6528 files · +46 −28Browse files

Unified · Split

8 files
  1. all.h +3 −2
  2. amd64/isel.c +1 −1
  3. copy.c +8 −4
  4. fold.c +7 −5
  5. mem.c +15 −10
  6. parse.c +7 −2
  7. ssa.c +1 −1
  8. util.c +4 −3
all.h+3−2
@@ -90,10 +90,11 @@ enum { · 89 unmodified lines
9090 RMem,
9191 };
9292
93−#define R (Ref){0, 0}
93+#define R (Ref){RTmp, 0}
94+#define UNDEF (Ref){RCon, 0} /* represents uninitialized data */
95+#define CON_Z (Ref){RCon, 1}
9496 #define TMP(x) (Ref){RTmp, x}
9597 #define CON(x) (Ref){RCon, x}
96−#define CON_Z CON(0) /* reserved zero constant */
9798 #define SLOT(x) (Ref){RSlot, (x)&0x1fffffff}
9899 #define TYPE(x) (Ref){RType, x}
99100 #define CALL(x) (Ref){RCall, x}
amd64/isel.c+1−1
@@ -482,7 +482,7 @@ seljmp(Blk *b, Fn *fn) · 481 unmodified lines
482482 }
483483 fi = flagi(b->ins, &b->ins[b->nins]);
484484 if (!fi || !req(fi->to, r)) {
485− selcmp((Ref[2]){r, CON_Z}, Kw, 0, fn); /* todo, long jnz */
485+ selcmp((Ref[2]){r, CON_Z}, Kw, 0, fn);
486486 b->jmp.type = Jjf + Cine;
487487 }
488488 else if (iscmp(fi->op, &k, &c)
copy.c+8−4
@@ -125,7 +125,7 @@ subst(Ref *pr, Ref *cpy) · 124 unmodified lines
125125 *pr = copyof(*pr, cpy);
126126 }
127127
128−/* requires use and rpo, breaks use */
128+/* requires use and dom, breaks use */
129129 void
130130 copy(Fn *fn)
131131 {
@@ -155,12 +155,16 @@ copy(Fn *fn) · 23 unmodified lines
155155 for (a=0; a<p->narg; a++)
156156 if (p->blk[a]->id < n) {
157157 r1 = copyof(p->arg[a], cpy);
158− if (req(r, R) || req(r1, r))
158+ if (req(r, R) || req(r, UNDEF))
159+ r = r1;
160+ if (req(r1, r) || req(r1, UNDEF))
159161 eq++;
160− r = r1;
161162 }
162163 assert(!req(r, R));
163− if (eq == p->narg)
164+ if (rtype(r) == RTmp
165+ && !dom(fn->rpo[fn->tmp[r.val].bid], b))
166+ cpy[p->to.val] = p->to;
167+ else if (eq == p->narg)
164168 cpy[p->to.val] = r;
165169 else {
166170 cpy[p->to.val] = p->to;
fold.c+7−5
@@ -1,8 +1,8 @@
11 #include "all.h"
22
33 enum {
4− Bot = -2, /* lattice bottom */
5− Top = -1, /* lattice top */
4+ Bot = -1, /* lattice bottom */
5+ Top = 0, /* lattice top (matches UNDEF) */
66 };
77
88 typedef struct Edge Edge;
@@ -126,7 +126,6 @@ visitjmp(Blk *b, int n, Fn *fn) · 117 unmodified lines
126126 switch (b->jmp.type) {
127127 case Jjnz:
128128 l = latval(b->jmp.arg);
129− assert(l != Top && "ssa invariant broken");
130129 if (l == Bot) {
131130 edge[n][1].work = flowrk;
132131 edge[n][0].work = &edge[n][1];
@@ -174,7 +173,6 @@ renref(Ref *r) · 41 unmodified lines
174173
175174 if (rtype(*r) == RTmp)
176175 if ((l=val[r->val]) != Bot) {
177− assert(l != Top && "ssa invariant broken");
178176 *r = CON(l);
179177 return 1;
180178 }
@@ -294,9 +292,13 @@ fold(Fn *fn) · 113 unmodified lines
294292 for (i=b->ins; i<&b->ins[b->nins]; i++)
295293 if (renref(&i->to))
296294 *i = (Ins){.op = Onop};
297− else
295+ else {
298296 for (n=0; n<2; n++)
299297 renref(&i->arg[n]);
298+ if (isstore(i->op))
299+ if (req(i->arg[0], UNDEF))
300+ *i = (Ins){.op = Onop};
301+ }
300302 renref(&b->jmp.arg);
301303 if (b->jmp.type == Jjnz && rtype(b->jmp.arg) == RCon) {
302304 if (iscon(&fn->con[b->jmp.arg.val], 0, 0)) {
mem.c+15−10
@@ -201,7 +201,7 @@ coalesce(Fn *fn) · 200 unmodified lines
201201 Ref *arg;
202202 bits x;
203203 int64_t off0, off1;
204− int n, m, sz, nsl, nbl, ip, *stk;
204+ int n, m, ip, sz, nsl, nbl, *stk;
205205 uint total, freed, fused;
206206
207207 /* minimize the stack usage
@@ -317,26 +317,31 @@ coalesce(Fn *fn) · 109 unmodified lines
317317 while (n--) {
318318 t = &fn->tmp[stk[n]];
319319 assert(t->ndef == 1 && t->def);
320− *t->def = (Ins){.op = Onop};
320+ i = t->def;
321+ if (isload(i->op)) {
322+ i->op = Ocopy;
323+ i->arg[0] = UNDEF;
324+ continue;
325+ }
326+ *i = (Ins){.op = Onop};
321327 for (u=t->use; u<&t->use[t->nuse]; u++) {
322328 if (u->type == UJmp) {
323329 b = fn->rpo[u->bid];
324− b->jmp.arg = CON_Z;
330+ assert(isret(b->jmp.type));
331+ b->jmp.type = Jret0;
332+ b->jmp.arg = R;
325333 continue;
326334 }
327335 assert(u->type == UIns);
328336 i = u->u.ins;
329− /* make loads crash */
330− if (isload(i->op))
331− i->arg[0] = CON_Z;
332− else if (i->op == Oargc)
333− i->arg[1] = CON_Z;
334− else if (!req(i->to, R)) {
337+ if (!req(i->to, R)) {
335338 assert(rtype(i->to) == RTmp);
336339 vgrow(&stk, ++n);
337340 stk[n-1] = i->to.val;
341+ } else if (isarg(i->op)) {
342+ assert(i->op == Oargc);
343+ i->arg[1] = CON_Z; /* crash */
338344 } else {
339− assert(!isarg(i->op));
340345 if (i->op == Oblit0)
341346 *(i+1) = (Ins){.op = Onop};
342347 *i = (Ins){.op = Onop};
parse.c+7−2
@@ -867,7 +867,7 @@ parsefn(Lnk *lnk) · 866 unmodified lines
867867 curi = insb;
868868 curf = alloc(sizeof *curf);
869869 curf->ntmp = 0;
870− curf->ncon = 1; /* first constant must be 0 */
870+ curf->ncon = 2;
871871 curf->tmp = vnew(curf->ntmp, sizeof curf->tmp[0], PFn);
872872 curf->con = vnew(curf->ncon, sizeof curf->con[0], PFn);
873873 for (i=0; i<Tmp0; ++i)
@@ -876,6 +876,8 @@ parsefn(Lnk *lnk) · 2 unmodified lines
876876 else
877877 newtmp(0, Kl, curf);
878878 curf->con[0].type = CBits;
879+ curf->con[0].bits.i = 0xdeaddead; /* UNDEF */
880+ curf->con[1].type = CBits;
879881 curf->lnk = *lnk;
880882 blink = &curf->start;
881883 curf->retty = Kx;
@@ -1230,7 +1232,10 @@ printref(Ref r, Fn *fn, FILE *f) · 348 unmodified lines
12301232 fprintf(f, "%%%s", fn->tmp[r.val].name);
12311233 break;
12321234 case RCon:
1233− printcon(&fn->con[r.val], f);
1235+ if (req(r, UNDEF))
1236+ fprintf(f, "UNDEF");
1237+ else
1238+ printcon(&fn->con[r.val], f);
12341239 break;
12351240 case RSlot:
12361241 fprintf(f, "S%d", rsval(r));
ssa.c+1−1
@@ -264,7 +264,7 @@ getstk(int t, Blk *b, Name **stk) · 263 unmodified lines
264264 stk[t] = n;
265265 if (!n) {
266266 /* uh, oh, warn */
267− return CON_Z;
267+ return UNDEF;
268268 } else
269269 return n->r;
270270 }
util.c+4−3
@@ -361,7 +361,7 @@ newcon(Con *c0, Fn *fn) · 360 unmodified lines
361361 Con *c1;
362362 int i;
363363
364− for (i=0; i<fn->ncon; i++) {
364+ for (i=1; i<fn->ncon; i++) {
365365 c1 = &fn->con[i];
366366 if (c0->type == c1->type
367367 && symeq(c0->sym, c1->sym)
@@ -378,8 +378,9 @@ getcon(int64_t val, Fn *fn) · 10 unmodified lines
378378 {
379379 int c;
380380
381− for (c=0; c<fn->ncon; c++)
382− if (fn->con[c].type == CBits && fn->con[c].bits.i == val)
381+ for (c=1; c<fn->ncon; c++)
382+ if (fn->con[c].type == CBits
383+ && fn->con[c].bits.i == val)
383384 return CON(c);
384385 vgrow(&fn->con, ++fn->ncon);
385386 fn->con[c] = (Con){.type = CBits, .bits.i = val};

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t