[PATCH] Use ceqw/l/s/d for logical not (!) operator instead of jnz+phi
Export this patch
This leads to neater code - single instruction, no more
blocks, and facilitates further QBE optimisations.
[Note: applies on top of Quentin's "logflow" patch]
Fixes previous patch which always generates ceqw.
Testing:
cproc bootstrap; cproc->qbe->cproc->qbe double bootstrap
coremark and a few others
Specific tests:
rolandpj@rolandpj-VivoBook-ASUSLaptop-X515DAP-M515DA:~/src/cproc$ cat ../rpj-qbe-test/tlnot.c
int inoti(int v)
{
return !v;
}
int inotl(long v)
{
return !v;
}
int inotp(void *p)
{
return !p;
}
int inotf(float f)
{
return !f;
}
int inotd(double d)
{
return !d;
}
long lnotp(void *p)
{
return !p;
}
rolandpj@rolandpj-VivoBook-ASUSLaptop-X515DAP-M515DA:~/src/cproc$ cproc-qbe ../rpj-qbe-test/tlnot.c
export
function w $inoti(w %.1) {
@start.1
%.2 =l alloc4 4
storew %.1, %.2
@body.2
%.3 =w loadw %.2
%.4 =w ceqw %.3, 0
ret %.4
}
export
function w $inotl(l %.1) {
@start.3
%.2 =l alloc8 8
storel %.1, %.2
@body.4
%.3 =l loadl %.2
%.4 =w ceql %.3, 0
ret %.4
}
export
function w $inotp(l %.1) {
@start.5
%.2 =l alloc8 8
storel %.1, %.2
@body.6
%.3 =l loadl %.2
%.4 =w ceql %.3, 0
ret %.4
}
export
function w $inotf(s %.1) {
@start.7
%.2 =l alloc4 4
stores %.1, %.2
@body.8
%.3 =s loads %.2
%.4 =w ceqs %.3, s_0
ret %.4
}
export
function w $inotd(d %.1) {
@start.9
%.2 =l alloc8 8
stored %.1, %.2
@body.10
%.3 =d loadd %.2
%.4 =w ceqd %.3, d_0
ret %.4
}
export
function l $lnotp(l %.1) {
@start.11
%.2 =l alloc8 8
storel %.1, %.2
@body.12
%.3 =l loadl %.2
%.4 =w ceql %.3, 0
%.5 =l extsw %.4
ret %.5
}
---
qbe.c | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/qbe.c b/qbe.c
index 7951409..9ed9e2a 100644
--- a/qbe.c
+++ b/qbe.c
@@ -702,12 +702,6 @@ funcbranch(struct func *f, struct expr *e, struct block *bt, struct block *bf)
/* Maybe we we could do something for EXPRCOND as well. */
switch (e->kind) {
- case EXPRUNARY:
- if (e->op == TLNOT) {
- funcbranch(f, e->base, bf, bt);
- return;
- }
- break;
case EXPRBINARY:
if (e->op == TLOR || e->op == TLAND) {
if (e->op == TLOR) {
@@ -833,7 +827,16 @@ funcexpr(struct func *f, struct expr *e)
case EXPRUNARY:
switch (e->op) {
case TLNOT:
- return funclogical(f, e);
+ r = funcexpr(f, e->base);
+ switch (qbetype(e->base->type).base) {
+ case 'w': op = ICEQW; v = mkintconst(0); break;
+ case 'l': op = ICEQL; v = mkintconst(0); break;
+ case 's': op = ICEQS; v = mkfltconst(VALUE_FLTCONST, 0); break;
+ case 'd': op = ICEQD; v = mkfltconst(VALUE_DBLCONST, 0); break;
+ default: fatal("internal error; unexpected unary not arg type");
+ }
+ assert(qbetype(e->type).base == 'w');
+ return funcinst(f, op, 'w', r, v);
case TBAND:
lval = funclval(f, e->base);
return lval.addr;
--
2.34.1