4 Bot
= -2, /* lattice bottom */
5 Top
= -1, /* lattice top */
8 typedef struct Edge Edge
;
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
)
101 if (rtype(i
->to
) != RTmp
)
103 if (optab
[i
->op
].canfold
) {
104 l
= latval(i
->arg
[0]);
105 if (!req(i
->arg
[1], R
))
106 r
= latval(i
->arg
[1]);
109 if (l
== Bot
|| r
== Bot
)
111 else if (l
== Top
|| r
== Top
)
114 v
= opfold(i
->op
, i
->cls
, &fn
->con
[l
], &fn
->con
[r
], fn
);
117 /* fprintf(stderr, "\nvisiting %s (%p)", optab[i->op].name, (void *)i); */
118 update(i
->to
.val
, v
, fn
);
122 visitjmp(Blk
*b
, int n
, Fn
*fn
)
126 switch (b
->jmp
.type
) {
128 l
= latval(b
->jmp
.arg
);
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];
151 if (isret(b
->jmp
.type
))
158 initedge(Edge
*e
, Blk
*s
)
173 if (rtype(*r
) == RTmp
)
174 if ((l
=val
[r
->val
]) != Bot
) {
175 assert(l
!= Top
&& "ssa invariant broken");
182 /* require rpo, use, pred */
194 val
= emalloc(fn
->ntmp
* sizeof val
[0]);
195 edge
= emalloc(fn
->nblk
* sizeof edge
[0]);
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
);
210 /* 1. find out constants and dead cfg edges */
216 if (e
->dest
== -1 || !e
->dead
)
221 for (p
=b
->phi
; p
; p
=p
->link
)
224 for (i
=b
->ins
; i
<&b
->ins
[b
->nins
]; i
++)
229 assert(b
->jmp
.type
!= Jjmp
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:");
259 for (t
=Tmp0
; t
<fn
->ntmp
; t
++) {
262 fprintf(stderr
, "\n%10s: ", fn
->tmp
[t
].name
);
264 fprintf(stderr
, "Top");
266 printref(CON(val
[t
]), fn
, stderr
);
268 fprintf(stderr
, "\n dead code: ");
271 /* 2. trim dead code, replace constants */
273 for (pb
=&fn
->start
; (b
=*pb
);) {
277 fprintf(stderr
, "%s ", b
->name
);
283 for (pp
=&b
->phi
; (p
=*pp
);)
284 if (val
[p
->to
.val
] != Bot
)
287 for (a
=0; a
<p
->narg
; a
++)
288 if (!deadedge(p
->blk
[a
]->id
, b
->id
))
292 for (i
=b
->ins
; i
<&b
->ins
[b
->nins
]; i
++)
294 *i
= (Ins
){.op
= Onop
};
299 if (b
->jmp
.type
== Jjnz
&& rtype(b
->jmp
.arg
) == RCon
) {
300 if (czero(&fn
->con
[b
->jmp
.arg
.val
], 0)) {
314 fprintf(stderr
, "(none)");
315 fprintf(stderr
, "\n\n> After constant folding:\n");
324 /* boring folding code */
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
) {
360 } else if (cl
->label
!= cr
->label
)
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
) {
367 if (Ocmpl
<= op
&& op
<= Ocmpl1
)
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
= w
? l
.s
/ r
.s
: (int32_t)l
.s
/ (int32_t)r
.s
; break;
375 case Orem
: x
= w
? l
.s
% r
.s
: (int32_t)l
.s
% (int32_t)r
.s
; break;
376 case Oudiv
: x
= w
? l
.u
/ r
.u
: (uint32_t)l
.u
/ (uint32_t)r
.u
; break;
377 case Ourem
: x
= w
? l
.u
% r
.u
: (uint32_t)l
.u
% (uint32_t)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
= (w
? l
.s
: (int32_t)l
.s
) >> (r
.u
& 63); break;
383 case Oshr
: x
= (w
? l
.u
: (uint32_t)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;
391 case Ostosi
: x
= w
? (int64_t)cl
->bits
.s
: (int32_t)cl
->bits
.s
; break;
392 case Odtosi
: x
= w
? (int64_t)cl
->bits
.d
: (int32_t)cl
->bits
.d
; break;
395 if (cl
->type
== CAddr
) {
401 if (Ocmpw
<= op
&& op
<= Ocmpl1
) {
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");
421 else if (Ocmps
<= op
&& op
<= Ocmps1
) {
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");
434 else if (Ocmpd
<= op
&& op
<= Ocmpd1
) {
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;
470 case Oswtof
: xd
= (int32_t)cl
->bits
.i
; break;
471 case Osltof
: xd
= (int64_t)cl
->bits
.i
; break;
472 case Oexts
: xd
= cl
->bits
.s
; 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;
485 case Oswtof
: xs
= (int32_t)cl
->bits
.i
; break;
486 case Osltof
: xs
= (int64_t)cl
->bits
.i
; break;
487 case Otruncd
: xs
= cl
->bits
.d
; break;
488 case Ocast
: xs
= ls
; break;
489 default: die("unreachable");
491 *res
= (Con
){CBits
, .bits
={.s
=xs
}, .flt
=1};
496 opfold(int op
, int cls
, Con
*cl
, Con
*cr
, Fn
*fn
)
501 if ((op
== Odiv
|| op
== Oudiv
502 || op
== Orem
|| op
== Ourem
) && czero(cr
, KWIDE(cls
)))
504 if (cls
== Kw
|| cls
== Kl
) {
505 if (foldint(&c
, op
, cls
== Kl
, cl
, cr
))
508 foldflt(&c
, op
, cls
== Kd
, cl
, cr
);
510 nc
= getcon(c
.bits
.i
, fn
).val
;
513 vgrow(&fn
->con
, ++fn
->ncon
);
515 assert(!(cls
== Ks
|| cls
== Kd
) || c
.flt
);