17 static Edge *flowrk, (*edge)[2];
27 return c->
bits.
i == 0;
29 return (uint32_t)c->
bits.
i == 0;
46 latmerge(
int v,
int m)
48 return m ==
Top ? v : (v ==
Top || v == m) ? m :
Bot;
52 update(
int t,
int m,
Fn *fn)
57 m = latmerge(val[t], m);
60 for (u=0; u<tmp->
nuse; u++) {
61 vgrow(&usewrk, ++nuse);
62 usewrk[nuse-1] = &tmp->
use[u];
69 deadedge(
int s,
int d)
74 if (e[0].dest == d && !e[0].dead)
76 if (e[1].dest == d && !e[1].dead)
82 visitphi(
Phi *p,
int n,
Fn *fn)
88 for (a=0; a<p->
narg; a++)
89 if (!deadedge(p->
blk[a]->
id, n))
90 v = latmerge(v, latval(p->
arg[a]));
91 update(p->
to.
val, v, fn);
94 static int opfold(
int,
int,
Con *,
Con *,
Fn *);
97 visitins(
Ins *i,
Fn *fn)
104 l = latval(i->
arg[0]);
105 if (!req(i->
arg[1],
R))
106 r = latval(i->
arg[1]);
111 else if (l ==
Top || r ==
Top)
114 v = opfold(i->
op, i->
cls, &fn->
con[l], &fn->
con[r], fn);
118 update(i->
to.
val, v, fn);
122 visitjmp(
Blk *b,
int n,
Fn *fn)
129 assert(l !=
Top &&
"ssa invariant broken");
131 edge[n][1].
work = flowrk;
132 edge[n][0].
work = &edge[n][1];
133 flowrk = &edge[n][0];
135 else if (czero(&fn->
con[l], 0)) {
136 assert(edge[n][0].dead);
137 edge[n][1].
work = flowrk;
138 flowrk = &edge[n][1];
141 assert(edge[n][1].dead);
142 edge[n][0].
work = flowrk;
143 flowrk = &edge[n][0];
147 edge[n][0].
work = flowrk;
148 flowrk = &edge[n][0];
173 if (rtype(*r) ==
RTmp)
174 if ((l=val[r->
val]) !=
Bot) {
175 assert(l !=
Top &&
"ssa invariant broken");
196 usewrk =
vnew(0,
sizeof usewrk[0],
Pheap);
198 for (t=0; t<fn->
ntmp; t++)
200 for (n=0; n<fn->
nblk; n++) {
203 initedge(&edge[n][0], b->
s1);
204 initedge(&edge[n][1], b->
s2);
206 initedge(&start, fn->
start);
231 || flowrk == &edge[n][0]);
241 visitphi(u->
u.
phi, u->
bid, fn);
244 visitins(u->
u.
ins, fn);
258 fprintf(stderr,
"\n> SCCP findings:");
262 fprintf(stderr,
"\n%10s: ", fn->
tmp[t].
name);
264 fprintf(stderr,
"Top");
268 fprintf(stderr,
"\n dead code: ");
273 for (pb=&fn->
start; (b=*pb);) {
277 fprintf(stderr,
"%s ", b->
name);
283 for (pp=&b->
phi; (p=*pp);)
287 for (a=0; a<p->
narg; a++)
288 if (!deadedge(p->
blk[a]->
id, b->
id))
314 fprintf(stderr,
"(none)");
315 fprintf(stderr,
"\n\n> After constant folding:\n");
327 foldint(
Con *res,
int op,
int w,
Con *cl,
Con *cr)
344 if (cl->
type == CAddr) {
345 if (cr->
type == CAddr)
346 err(
"undefined addition (addr + addr)");
350 else if (cr->
type == CAddr) {
355 else if (op ==
Osub) {
356 if (cl->
type == CAddr) {
357 if (cr->
type != CAddr) {
361 err(
"undefined substraction (addr1 - addr2)");
363 else if (cr->
type == CAddr)
364 err(
"undefined substraction (num - addr)");
366 else if (cl->
type == CAddr || cr->
type == CAddr) {
369 err(
"invalid address operand for '%s'",
optab[op].name);
372 case Oadd: x = l.u + r.u;
break;
373 case Osub: x = l.u - r.u;
break;
374 case Odiv: x = l.s / r.s;
break;
375 case Orem: x = l.s % r.s;
break;
376 case Oudiv: x = l.u / r.u;
break;
377 case Ourem: x = l.u % r.u;
break;
378 case Omul: x = l.u * r.u;
break;
379 case Oand: x = l.u & r.u;
break;
380 case Oor: x = l.u | r.u;
break;
381 case Oxor: x = l.u ^ r.u;
break;
382 case Osar: x = l.s >> (r.u & 63);
break;
383 case Oshr: x = l.u >> (r.u & 63);
break;
384 case Oshl: x = l.u << (r.u & 63);
break;
385 case Oextsb: x = (int8_t)l.u;
break;
386 case Oextub: x = (uint8_t)l.u;
break;
387 case Oextsh: x = (int16_t)l.u;
break;
388 case Oextuh: x = (uint16_t)l.u;
break;
389 case Oextsw: x = (int32_t)l.u;
break;
390 case Oextuw: x = (uint32_t)l.u;
break;
395 if (cl->
type == CAddr) {
407 switch (op -
Ocmpw) {
408 case Ciule: x = l.u <= r.u;
break;
409 case Ciult: x = l.u < r.u;
break;
410 case Cisle: x = l.s <= r.s;
break;
411 case Cislt: x = l.s < r.s;
break;
412 case Cisgt: x = l.s > r.s;
break;
413 case Cisge: x = l.s >= r.s;
break;
414 case Ciugt: x = l.u > r.u;
break;
415 case Ciuge: x = l.u >= r.u;
break;
416 case Cieq: x = l.u == r.u;
break;
417 case Cine: x = l.u != r.u;
break;
418 default:
die(
"unreachable");
422 switch (op -
Ocmps) {
423 case Cfle: x = l.fs <= r.fs;
break;
424 case Cflt: x = l.fs < r.fs;
break;
425 case Cfgt: x = l.fs > r.fs;
break;
426 case Cfge: x = l.fs >= r.fs;
break;
427 case Cfne: x = l.fs != r.fs;
break;
428 case Cfeq: x = l.fs == r.fs;
break;
429 case Cfo: x = l.fs < r.fs || l.fs >= r.fs;
break;
430 case Cfuo: x = !(l.fs < r.fs || l.fs >= r.fs);
break;
431 default:
die(
"unreachable");
435 switch (op -
Ocmpd) {
436 case Cfle: x = l.fd <= r.fd;
break;
437 case Cflt: x = l.fd < r.fd;
break;
438 case Cfgt: x = l.fd > r.fd;
break;
439 case Cfge: x = l.fd >= r.fd;
break;
440 case Cfne: x = l.fd != r.fd;
break;
441 case Cfeq: x = l.fd == r.fd;
break;
442 case Cfo: x = l.fd < r.fd || l.fd >= r.fd;
break;
443 case Cfuo: x = !(l.fd < r.fd || l.fd >= r.fd);
break;
444 default:
die(
"unreachable");
450 *res = (
Con){.
type=
typ, .label=lab, .bits={.i=x}};
455 foldflt(
Con *res,
int op,
int w,
Con *cl,
Con *cr)
460 if (cl->
type != CBits || cr->
type != CBits)
461 err(
"invalid address operand for '%s'",
optab[op].name);
466 case Oadd: xd = ld + rd;
break;
467 case Osub: xd = ld - rd;
break;
468 case Odiv: xd = ld / rd;
break;
469 case Omul: xd = ld * rd;
break;
473 case Ocast: xd = ld;
break;
474 default:
die(
"unreachable");
476 *res = (
Con){CBits, .
bits={.
d=xd}, .flt=2};
481 case Oadd: xs = ls + rs;
break;
482 case Osub: xs = ls - rs;
break;
483 case Odiv: xs = ls / rs;
break;
484 case Omul: xs = ls * rs;
break;
488 case Ocast: xs = ls;
break;
489 default:
die(
"unreachable");
491 *res = (
Con){CBits, .
bits={.
s=xs}, .flt=1};
503 err(
"null divisor in '%s'",
optab[op].name);
505 if (foldint(&c, op,
cls ==
Kl, cl, cr))
508 foldflt(&c, op,
cls ==
Kd, cl, cr);
Blk * start
Указатель на блок функции, являющийся её входной точкой
int ncon
Размер массива con.
Структура, хранящая информацию об инструкциях.
void * vnew(ulong, size_t, Pool)
Op optab[NOp]
Массив всех операций.
void edgedel(Blk *, Blk **)
Con * con
Массив используемых функцией констант
Структура, хранящая описание переменных (более подробное описание переменной ищите в Tmp)...
Содержит информацию о переменной
void err(char *,...) __attribute__((noreturn))
Tmp * tmp
Массив используемых функцией переменных
Use * use
Содержит информацию об использовании переменной
int ntmp
Размер массива tmp.
Непосредственно информация о базовом блоке.
void printfn(Fn *, FILE *)
Ref getcon(int64_t, Fn *)
char name[NString]
Имя переменной
void vgrow(void *, ulong)
uint nblk
Количество блоков в функции
Blk ** rpo
Ссылка на массив блоков, пронумерованных в порядке Reverse-Post Order, заполняется функцией fillrpo...
Номер (в массиве Fn->tmp) первой не регистровой переменной
void printref(Ref, Fn *, FILE *)
Структура, хранящая в себе информацию о функции
uint nuse
Количество блоков, в которых переменная используется
Структура, хранящая информацию об одном "использовании" переменной.