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
90 RMem,90 RMem,
91};91};
92 92
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}
94#define TMP(x) (Ref){RTmp, x}96#define TMP(x) (Ref){RTmp, x}
95#define CON(x) (Ref){RCon, x}97#define CON(x) (Ref){RCon, x}
96#define CON_Z CON(0) /* reserved zero constant */
97#define SLOT(x) (Ref){RSlot, (x)&0x1fffffff}98#define SLOT(x) (Ref){RSlot, (x)&0x1fffffff}
98#define TYPE(x) (Ref){RType, x}99#define TYPE(x) (Ref){RType, x}
99#define CALL(x) (Ref){RCall, x}100#define CALL(x) (Ref){RCall, x}
amd64/isel.c+1−1
@@ -482,7 +482,7 @@ seljmp(Blk *b, Fn *fn) · 481 unmodified lines
482 }482 }
483 fi = flagi(b->ins, &b->ins[b->nins]);483 fi = flagi(b->ins, &b->ins[b->nins]);
484 if (!fi || !req(fi->to, r)) {484 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);
486 b->jmp.type = Jjf + Cine;486 b->jmp.type = Jjf + Cine;
487 }487 }
488 else if (iscmp(fi->op, &k, &c)488 else if (iscmp(fi->op, &k, &c)
copy.c+8−4
@@ -125,7 +125,7 @@ subst(Ref *pr, Ref *cpy) · 124 unmodified lines
125 *pr = copyof(*pr, cpy);125 *pr = copyof(*pr, cpy);
126}126}
127 127
128/* requires use and rpo, breaks use */128/* requires use and dom, breaks use */
129void129void
130copy(Fn *fn)130copy(Fn *fn)
131{131{
@@ -155,12 +155,16 @@ copy(Fn *fn) · 23 unmodified lines
155 for (a=0; a<p->narg; a++)155 for (a=0; a<p->narg; a++)
156 if (p->blk[a]->id < n) {156 if (p->blk[a]->id < n) {
157 r1 = copyof(p->arg[a], cpy);157 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))
159 eq++;161 eq++;
160 r = r1;
161 }162 }
162 assert(!req(r, R));163 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)
164 cpy[p->to.val] = r;168 cpy[p->to.val] = r;
165 else {169 else {
166 cpy[p->to.val] = p->to;170 cpy[p->to.val] = p->to;
fold.c+7−5
@@ -1,8 +1,8 @@
1#include "all.h"1#include "all.h"
2 2
3enum {3enum {
4 Bot = -2, /* lattice bottom */4 Bot = -1, /* lattice bottom */
5 Top = -1, /* lattice top */5 Top = 0, /* lattice top (matches UNDEF) */
6};6};
7 7
8typedef struct Edge Edge;8typedef struct Edge Edge;
@@ -126,7 +126,6 @@ visitjmp(Blk *b, int n, Fn *fn) · 117 unmodified lines
126 switch (b->jmp.type) {126 switch (b->jmp.type) {
127 case Jjnz:127 case Jjnz:
128 l = latval(b->jmp.arg);128 l = latval(b->jmp.arg);
129 assert(l != Top && "ssa invariant broken");
130 if (l == Bot) {129 if (l == Bot) {
131 edge[n][1].work = flowrk;130 edge[n][1].work = flowrk;
132 edge[n][0].work = &edge[n][1];131 edge[n][0].work = &edge[n][1];
@@ -174,7 +173,6 @@ renref(Ref *r) · 41 unmodified lines
174 173
175 if (rtype(*r) == RTmp)174 if (rtype(*r) == RTmp)
176 if ((l=val[r->val]) != Bot) {175 if ((l=val[r->val]) != Bot) {
177 assert(l != Top && "ssa invariant broken");
178 *r = CON(l);176 *r = CON(l);
179 return 1;177 return 1;
180 }178 }
@@ -294,9 +292,13 @@ fold(Fn *fn) · 113 unmodified lines
294 for (i=b->ins; i<&b->ins[b->nins]; i++)292 for (i=b->ins; i<&b->ins[b->nins]; i++)
295 if (renref(&i->to))293 if (renref(&i->to))
296 *i = (Ins){.op = Onop};294 *i = (Ins){.op = Onop};
297 else295 else {
298 for (n=0; n<2; n++)296 for (n=0; n<2; n++)
299 renref(&i->arg[n]);297 renref(&i->arg[n]);
298 if (isstore(i->op))
299 if (req(i->arg[0], UNDEF))
300 *i = (Ins){.op = Onop};
301 }
300 renref(&b->jmp.arg);302 renref(&b->jmp.arg);
301 if (b->jmp.type == Jjnz && rtype(b->jmp.arg) == RCon) {303 if (b->jmp.type == Jjnz && rtype(b->jmp.arg) == RCon) {
302 if (iscon(&fn->con[b->jmp.arg.val], 0, 0)) {304 if (iscon(&fn->con[b->jmp.arg.val], 0, 0)) {
mem.c+15−10
@@ -201,7 +201,7 @@ coalesce(Fn *fn) · 200 unmodified lines
201 Ref *arg;201 Ref *arg;
202 bits x;202 bits x;
203 int64_t off0, off1;203 int64_t off0, off1;
204 int n, m, sz, nsl, nbl, ip, *stk;204 int n, m, ip, sz, nsl, nbl, *stk;
205 uint total, freed, fused;205 uint total, freed, fused;
206 206
207 /* minimize the stack usage207 /* minimize the stack usage
@@ -317,26 +317,31 @@ coalesce(Fn *fn) · 109 unmodified lines
317 while (n--) {317 while (n--) {
318 t = &fn->tmp[stk[n]];318 t = &fn->tmp[stk[n]];
319 assert(t->ndef == 1 && t->def);319 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};
321 for (u=t->use; u<&t->use[t->nuse]; u++) {327 for (u=t->use; u<&t->use[t->nuse]; u++) {
322 if (u->type == UJmp) {328 if (u->type == UJmp) {
323 b = fn->rpo[u->bid];329 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;
325 continue;333 continue;
326 }334 }
327 assert(u->type == UIns);335 assert(u->type == UIns);
328 i = u->u.ins;336 i = u->u.ins;
329 /* make loads crash */337 if (!req(i->to, R)) {
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)) {
335 assert(rtype(i->to) == RTmp);338 assert(rtype(i->to) == RTmp);
336 vgrow(&stk, ++n);339 vgrow(&stk, ++n);
337 stk[n-1] = i->to.val;340 stk[n-1] = i->to.val;
341 } else if (isarg(i->op)) {
342 assert(i->op == Oargc);
343 i->arg[1] = CON_Z; /* crash */
338 } else {344 } else {
339 assert(!isarg(i->op));
340 if (i->op == Oblit0)345 if (i->op == Oblit0)
341 *(i+1) = (Ins){.op = Onop};346 *(i+1) = (Ins){.op = Onop};
342 *i = (Ins){.op = Onop};347 *i = (Ins){.op = Onop};
parse.c+7−2
@@ -867,7 +867,7 @@ parsefn(Lnk *lnk) · 866 unmodified lines
867 curi = insb;867 curi = insb;
868 curf = alloc(sizeof *curf);868 curf = alloc(sizeof *curf);
869 curf->ntmp = 0;869 curf->ntmp = 0;
870 curf->ncon = 1; /* first constant must be 0 */870 curf->ncon = 2;
871 curf->tmp = vnew(curf->ntmp, sizeof curf->tmp[0], PFn);871 curf->tmp = vnew(curf->ntmp, sizeof curf->tmp[0], PFn);
872 curf->con = vnew(curf->ncon, sizeof curf->con[0], PFn);872 curf->con = vnew(curf->ncon, sizeof curf->con[0], PFn);
873 for (i=0; i<Tmp0; ++i)873 for (i=0; i<Tmp0; ++i)
@@ -876,6 +876,8 @@ parsefn(Lnk *lnk) · 2 unmodified lines
876 else876 else
877 newtmp(0, Kl, curf);877 newtmp(0, Kl, curf);
878 curf->con[0].type = CBits;878 curf->con[0].type = CBits;
879 curf->con[0].bits.i = 0xdeaddead; /* UNDEF */
880 curf->con[1].type = CBits;
879 curf->lnk = *lnk;881 curf->lnk = *lnk;
880 blink = &curf->start;882 blink = &curf->start;
881 curf->retty = Kx;883 curf->retty = Kx;
@@ -1230,7 +1232,10 @@ printref(Ref r, Fn *fn, FILE *f) · 348 unmodified lines
1230 fprintf(f, "%%%s", fn->tmp[r.val].name);1232 fprintf(f, "%%%s", fn->tmp[r.val].name);
1231 break;1233 break;
1232 case RCon:1234 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);
1234 break;1239 break;
1235 case RSlot:1240 case RSlot:
1236 fprintf(f, "S%d", rsval(r));1241 fprintf(f, "S%d", rsval(r));
ssa.c+1−1
@@ -264,7 +264,7 @@ getstk(int t, Blk *b, Name **stk) · 263 unmodified lines
264 stk[t] = n;264 stk[t] = n;
265 if (!n) {265 if (!n) {
266 /* uh, oh, warn */266 /* uh, oh, warn */
267 return CON_Z;267 return UNDEF;
268 } else268 } else
269 return n->r;269 return n->r;
270}270}
util.c+4−3
@@ -361,7 +361,7 @@ newcon(Con *c0, Fn *fn) · 360 unmodified lines
361 Con *c1;361 Con *c1;
362 int i;362 int i;
363 363
364 for (i=0; i<fn->ncon; i++) {364 for (i=1; i<fn->ncon; i++) {
365 c1 = &fn->con[i];365 c1 = &fn->con[i];
366 if (c0->type == c1->type366 if (c0->type == c1->type
367 && symeq(c0->sym, c1->sym)367 && symeq(c0->sym, c1->sym)
@@ -378,8 +378,9 @@ getcon(int64_t val, Fn *fn) · 10 unmodified lines
378{378{
379 int c;379 int c;
380 380
381 for (c=0; c<fn->ncon; c++)381 for (c=1; c<fn->ncon; c++)
382 if (fn->con[c].type == CBits && fn->con[c].bits.i == val)382 if (fn->con[c].type == CBits
383 && fn->con[c].bits.i == val)
383 return CON(c);384 return CON(c);
384 vgrow(&fn->con, ++fn->ncon);385 vgrow(&fn->con, ++fn->ncon);
385 fn->con[c] = (Con){.type = CBits, .bits.i = val};386 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