]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/cmd/7c/cgen.c
git/branch: somewhere in the syncing, the fix for junk files was lost
[plan9front.git] / sys / src / cmd / 7c / cgen.c
index f2733a8aa2802bd2d783ae5d8167ade580561636..3cb84a65ca8bea2593635cf7dddf838f0a761af7 100644 (file)
@@ -2,11 +2,17 @@
 
 void
 cgen(Node *n, Node *nn)
+{
+       cgenrel(n, nn, 0);
+}
+
+void
+cgenrel(Node *n, Node *nn, int inrel)
 {
        Node *l, *r;
        Prog *p1;
        Node nod, nod1, nod2, nod3, nod4;
-       int o;
+       int o, t;
        long v, curs;
 
        if(debug['g']) {
@@ -44,6 +50,9 @@ cgen(Node *n, Node *nn)
        if(r != Z && r->complex >= FNX)
        switch(o) {
        default:
+               if(cond(o) && typesu[l->type->etype])
+                       break;
+
                regret(&nod, r);
                cgen(r, &nod);
 
@@ -70,22 +79,41 @@ cgen(Node *n, Node *nn)
                diag(n, "unknown op in cgen: %O", o);
                break;
 
+       case ONEG:
+       case OCOM:
+               if(nn == Z) {
+                       nullwarn(l, Z);
+                       break;
+               }
+               regalloc(&nod, l, nn);
+               cgen(l, &nod);
+               gopcode(o, &nod, Z, &nod);
+               gmove(&nod, nn);
+               regfree(&nod);
+               break;
+
        case OAS:
                if(l->op == OBIT)
                        goto bitas;
                if(l->addable >= INDEXED && l->complex < FNX) {
-                       if(nn != Z || r->addable < INDEXED) {
-                               regalloc(&nod, r, nn);
+                       if(nn != Z || r->addable < INDEXED) {   /* || hardconst(r) */
+                               if(r->complex >= FNX && nn == Z)
+                                       regret(&nod, r);
+                               else
+                                       regalloc(&nod, r, nn);
                                cgen(r, &nod);
                                gmove(&nod, l);
+                               if(nn != Z)
+                                       gmove(&nod, nn);
                                regfree(&nod);
                        } else
                                gmove(r, l);
                        break;
                }
                if(l->complex >= r->complex) {
+                       /* TO DO: see 6c for OINDEX && immconst(r) */
                        reglcgen(&nod1, l, Z);
-                       if(r->addable >= INDEXED) {
+                       if(r->addable >= INDEXED) {     /* && !hardconst(r) */
                                gmove(r, &nod1);
                                if(nn != Z)
                                        gmove(r, nn);
@@ -100,6 +128,8 @@ cgen(Node *n, Node *nn)
                        reglcgen(&nod1, l, Z);
                }
                gmove(&nod, &nod1);
+               if(nn != Z)
+                       gmove(&nod, nn);
                regfree(&nod);
                regfree(&nod1);
                break;
@@ -129,20 +159,49 @@ cgen(Node *n, Node *nn)
                regfree(&nod);
                break;
 
-       case OADD:
+       case ODIV:
+       case OMOD:
+               if(nn != Z)
+               if((t = vlog(r)) >= 0) {
+                       /* signed div/mod by constant power of 2 */
+                       cgen(l, nn);
+                       gopcode(OGE, nodconst(0), nn, Z);
+                       p1 = p;
+                       if(o == ODIV) {
+                               gopcode(OADD, nodconst((1<<t)-1), Z, nn);
+                               patch(p1, pc);
+                               gopcode(OASHR, nodconst(t), Z, nn);
+                       } else {
+                               gopcode(ONEG, nn, Z, nn);
+                               gopcode(OAND, nodconst((1<<t)-1), Z, nn);
+                               gopcode(ONEG, nn, Z, nn);
+                               gbranch(OGOTO);
+                               patch(p1, pc);
+                               p1 = p;
+                               gopcode(OAND, nodconst((1<<t)-1), Z, nn);
+                               patch(p1, pc);
+                       }
+                       break;
+               }
+               goto muldiv;
+
+       case OXOR:
+#ifdef NOTYET
+               if(nn != Z)
+               if(r->op == OCONST && r->vconst == -1){
+                       cgen(l, nn);
+                       gopcode(OCOM, nn, Z, nn);
+                       break;
+               }
+#endif
+
        case OSUB:
+       case OADD:
        case OAND:
        case OOR:
-       case OXOR:
        case OLSHR:
        case OASHL:
        case OASHR:
-       case OLDIV:
-       case OLMOD:
-       case ODIV:
-       case OMOD:
-       case OMUL:
-       case OLMUL:
                /*
                 * immediate operands
                 */
@@ -158,14 +217,19 @@ cgen(Node *n, Node *nn)
                        break;
                }
 
+       case OLMUL:
+       case OLDIV:
+       case OLMOD:
+       case OMUL:
+       muldiv:
                if(nn == Z) {
                        nullwarn(l, r);
                        break;
                }
-/*             if(o == OMUL || o == OLMUL) {
+               if(o == OMUL || o == OLMUL) {
                        if(mulcon(n, nn))
                                break;
-               } */
+               }
                if(l->complex >= r->complex) {
                        regalloc(&nod, l, nn);
                        cgen(l, &nod);
@@ -192,12 +256,6 @@ cgen(Node *n, Node *nn)
        case OASSUB:
        case OASXOR:
        case OASOR:
-       case OASLDIV:
-       case OASLMOD:
-       case OASDIV:
-       case OASMOD:
-       case OASLMUL:
-       case OASMUL:
                if(l->op == OBIT)
                        goto asbitop;
                if(r->op == OCONST)
@@ -211,13 +269,22 @@ cgen(Node *n, Node *nn)
                        gopcode(OAS, &nod2, Z, &nod);
                        gopcode(o, r, Z, &nod);
                        gopcode(OAS, &nod, Z, &nod2);
-       
+                       if(nn != Z)
+                               gmove(&nod, nn);
                        regfree(&nod);
                        if(l->addable < INDEXED)
                                regfree(&nod2);
                        break;
                }
 
+       case OASLMUL:
+       case OASLDIV:
+       case OASLMOD:
+       case OASMUL:
+       case OASDIV:
+       case OASMOD:
+               if(l->op == OBIT)
+                       goto asbitop;
                if(l->complex >= r->complex) {
                        if(l->addable < INDEXED)
                                reglcgen(&nod2, l, Z);
@@ -233,19 +300,21 @@ cgen(Node *n, Node *nn)
                        else
                                nod2 = *l;
                }
-
-               regalloc(&nod, n, nn);
-               gmove(&nod2, &nod);
+               if(nod1.type->etype == nod2.type->etype || !typefd[nod1.type->etype])
+                       regalloc(&nod, &nod2, nn);
+               else
+                       regalloc(&nod, &nod1, Z);
+               gopcode(OAS, &nod2, Z, &nod);
                if(nod1.type->etype != nod.type->etype){
                        regalloc(&nod3, &nod, Z);
                        gmove(&nod1, &nod3);
                        regfree(&nod1);
                        nod1 = nod3;
                }
-               gopcode(o, &nod1, Z, &nod);
+               gopcode(o, &nod1, &nod, &nod);
                gmove(&nod, &nod2);
                if(nn != Z)
-                       gopcode(OAS, &nod, Z, nn);
+                       gmove(&nod, nn);
                regfree(&nod);
                regfree(&nod1);
                if(l->addable < INDEXED)
@@ -254,12 +323,11 @@ cgen(Node *n, Node *nn)
 
        asbitop:
                regalloc(&nod4, n, nn);
+               regalloc(&nod3, r, Z);
                if(l->complex >= r->complex) {
                        bitload(l, &nod, &nod1, &nod2, &nod4);
-                       regalloc(&nod3, r, Z);
                        cgen(r, &nod3);
                } else {
-                       regalloc(&nod3, r, Z);
                        cgen(r, &nod3);
                        bitload(l, &nod, &nod1, &nod2, &nod4);
                }
@@ -280,6 +348,7 @@ cgen(Node *n, Node *nn)
                break;
 
        case OFUNC:
+               l = uncomma(l);
                if(l->complex >= FNX) {
                        if(l->op != OIND)
                                diag(n, "bad function call");
@@ -299,7 +368,7 @@ cgen(Node *n, Node *nn)
 
                        return;
                }
-               if(REGARG != NREG)
+               if(REGARG >= 0)
                        o = reg[REGARG];
                gargs(r, &nod, &nod1);
                if(l->addable < INDEXED) {
@@ -308,7 +377,7 @@ cgen(Node *n, Node *nn)
                        regfree(&nod);
                } else
                        gopcode(OFUNC, Z, Z, l);
-               if(REGARG != NREG)
+               if(REGARG >= 0)
                        if(o != reg[REGARG])
                                reg[REGARG]--;
                if(nn != Z) {
@@ -327,7 +396,7 @@ cgen(Node *n, Node *nn)
                r = l;
                while(r->op == OADD)
                        r = r->right;
-               if(sconst(r)) {
+               if(usableoffset(n, nod.xoffset, r)){
                        v = r->vconst;
                        r->vconst = 0;
                        cgen(l, &nod);
@@ -379,22 +448,39 @@ cgen(Node *n, Node *nn)
 
        case OCAST:
                if(nn == Z) {
-                       nullwarn(l, Z);
+                       cgen(l, Z);
                        break;
                }
                /*
                 * convert from types l->n->nn
                 */
-               if(nocast(l->type, n->type)) {
-                       if(nocast(n->type, nn->type)) {
-                               cgen(l, nn);
+               if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
+                       /* both null, gen l->nn */
+                       cgen(l, nn);
+                       break;
+               }
+               if(ewidth[n->type->etype] < ewidth[l->type->etype]){
+                       if(l->type->etype == TIND && typechlp[n->type->etype])
+                               warn(n, "conversion of pointer to shorter integer");
+               }else if(0){
+                       if(nocast(n->type, nn->type) || castup(n->type, nn->type)){
+                               if(typefd[l->type->etype] != typefd[nn->type->etype])
+                                       regalloc(&nod, l, nn);
+                               else
+                                       regalloc(&nod, nn, nn);
+                               cgen(l, &nod);
+                               gmove(&nod, nn);
+                               regfree(&nod);
                                break;
                        }
                }
                regalloc(&nod, l, nn);
                cgen(l, &nod);
                regalloc(&nod1, n, &nod);
-               gopcode(OAS, &nod, Z, &nod1);
+               if(inrel)
+                       gmover(&nod, &nod1);
+               else
+                       gopcode(OAS, &nod, Z, &nod1);
                gopcode(OAS, &nod1, Z, nn);
                regfree(&nod1);
                regfree(&nod);
@@ -445,6 +531,8 @@ cgen(Node *n, Node *nn)
 
                regalloc(&nod, l, nn);
                gopcode(OAS, &nod2, Z, &nod);
+               if(nn != Z)
+                       gmove(&nod, nn);
                regalloc(&nod1, l, Z);
                if(typefd[l->type->etype]) {
                        regalloc(&nod3, l, Z);
@@ -497,9 +585,11 @@ cgen(Node *n, Node *nn)
                } else
                        gopcode(OADD, nodconst(v), Z, &nod);
                gopcode(OAS, &nod, Z, &nod2);
-               if(nn && l->op == ONAME)        /* in x=++i, emit USED(i) */
-                       gins(ANOP, l, Z);
-
+               if(nn != Z){
+                       gmove(&nod, nn);
+                       if(l->op == ONAME)      /* in x=++i, emit USED(i) */
+                               gins(ANOP, l, Z);
+               }
                regfree(&nod);
                if(l->addable < INDEXED)
                        regfree(&nod2);
@@ -533,7 +623,7 @@ reglcgen(Node *t, Node *n, Node *nn)
                r = n->left;
                while(r->op == OADD)
                        r = r->right;
-               if(sconst(r)) {
+               if(usableoffset(n, t->xoffset, r)) {
                        v = r->vconst;
                        r->vconst = 0;
                        lcgen(n, t);
@@ -542,6 +632,21 @@ reglcgen(Node *t, Node *n, Node *nn)
                        regind(t, n);
                        return;
                }
+       } else if(n->op == OINDREG) {
+               if(usableoffset(n, t->xoffset+n->xoffset, nil)) {
+                       Type *tt = n->type;
+                       n->type = types[TIND];
+                       n->op = OREGISTER;
+                       v = n->xoffset;
+                       n->xoffset = 0;
+                       cgen(n, t);
+                       t->xoffset += v;
+                       n->xoffset = v;
+                       n->op = OINDREG;
+                       n->type = tt;
+                       regind(t, n);
+                       return;
+               }
        }
        lcgen(n, t);
        regind(t, n);
@@ -631,12 +736,11 @@ boolgen(Node *n, int true, Node *nn)
                cgen(n, &nod);
                o = ONE;
                if(true)
-                       o = comrel[relindex(o)];
+                       o = OEQ;
                if(typefd[n->type->etype]) {
-                       nodreg(&nod1, n, NREG+FREGZERO);
-                       gopcode(o, &nod, Z, &nod1);
+                       gopcode(true ? o | BTRUE : o, nodfconst(0), &nod, Z);
                } else
-                       gopcode(o, &nod, Z, nodconst(0));
+                       gopcode(o, nodconst(0), &nod, Z);
                regfree(&nod);
                goto com;
 
@@ -720,7 +824,7 @@ boolgen(Node *n, int true, Node *nn)
                        o = comrel[relindex(o)];
                if(l->complex >= FNX && r->complex >= FNX) {
                        regret(&nod, r);
-                       cgen(r, &nod);
+                       cgenrel(r, &nod, 1);
                        regsalloc(&nod1, r);
                        gopcode(OAS, &nod, Z, &nod1);
                        regfree(&nod);
@@ -729,25 +833,33 @@ boolgen(Node *n, int true, Node *nn)
                        boolgen(&nod, true, nn);
                        break;
                }
-               if(bconst(r)) {
+               if(sconst(l)) {
+                       regalloc(&nod, r, nn);
+                       cgenrel(r, &nod, 1);
+                       o = invrel[relindex(o)];
+                       gopcode(true ? o | BTRUE : o, l, &nod, Z);
+                       regfree(&nod);
+                       goto com;
+               }
+               if(sconst(r)) {
                        regalloc(&nod, l, nn);
-                       cgen(l, &nod);
-                       gopcode(o, &nod, Z, r);
+                       cgenrel(l, &nod, 1);
+                       gopcode(true ? o | BTRUE : o, r, &nod, Z);
                        regfree(&nod);
                        goto com;
                }
                if(l->complex >= r->complex) {
                        regalloc(&nod1, l, nn);
-                       cgen(l, &nod1);
+                       cgenrel(l, &nod1, 1);
                        regalloc(&nod, r, Z);
-                       cgen(r, &nod);
+                       cgenrel(r, &nod, 1);
                } else {
                        regalloc(&nod, r, nn);
-                       cgen(r, &nod);
+                       cgenrel(r, &nod, 1);
                        regalloc(&nod1, l, Z);
-                       cgen(l, &nod1);
+                       cgenrel(l, &nod1, 1);
                }
-               gopcode(o, &nod1, Z, &nod);
+               gopcode(true ? o | BTRUE : o, &nod, &nod1, Z);
                regfree(&nod);
                regfree(&nod1);
 
@@ -794,6 +906,33 @@ sugen(Node *n, Node *nn, long w)
        default:
                goto copy;
 
+       case OCONST:
+               if(n->type && typev[n->type->etype]) {
+                       if(nn == Z) {
+                               nullwarn(n->left, Z);
+                               break;
+                       }
+
+                       t = nn->type;
+                       nn->type = types[TLONG];
+                       reglcgen(&nod1, nn, Z);
+                       nn->type = t;
+
+                       if(align(0, types[TCHAR], Aarg1))       /* isbigendian */
+                               gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+                       else
+                               gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+                       nod1.xoffset += SZ_LONG;
+                       if(align(0, types[TCHAR], Aarg1))       /* isbigendian */
+                               gopcode(OAS, nod32const(n->vconst), Z, &nod1);
+                       else
+                               gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
+
+                       regfree(&nod1);
+                       break;
+               }
+               goto copy;
+
        case ODOT:
                l = n->left;
                sugen(l, nodrat, l->type->width);
@@ -813,9 +952,9 @@ sugen(Node *n, Node *nn, long w)
 
        case OSTRUCT:
                /*
-                * rewrite so lhs has no fn call
+                * rewrite so lhs has no side effects
                 */
-               if(nn != Z && nn->complex >= FNX) {
+               if(nn != Z && side(nn)) {
                        nod1 = *n;
                        nod1.type = typ(TIND, n->type);
                        regret(&nod2, &nod1);
@@ -880,7 +1019,6 @@ sugen(Node *n, Node *nn, long w)
                        xcom(&nod0);
                        nod0.addable = 0;
 
-                       /* prtree(&nod0, "hand craft"); /* */
                        cgen(&nod0, Z);
                }
                break;
@@ -940,7 +1078,7 @@ copy:
                nn->type = types[TLONG];
                regialloc(&nod1, nn, Z);
                lcgen(nn, &nod1);
-               regsalloc(&nod2, nn);
+               regsalloc(&nod2, &nod1);
                nn->type = t;
 
                gopcode(OAS, &nod1, Z, &nod2);
@@ -959,6 +1097,7 @@ copy:
                return;
        }
 
+       /* TO DO: use AMOV/VLONG when possible */
        if(n->complex > nn->complex) {
                t = n->type;
                n->type = types[TLONG];
@@ -1009,13 +1148,19 @@ copy:
        pc1 = pc;
        layout(&nod1, &nod2, c, 0, Z);
 
-       gopcode(OSUB, nodconst(1), Z, &nod3);
+       gopcode(OSUB, nodconst(1L), Z, &nod3);
        nod1.op = OREGISTER;
+       t = nod1.type;
+       nod1.type = types[TIND];
        gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod1);
+       nod1.type = t;
        nod2.op = OREGISTER;
+       t = nod2.type;
+       nod2.type = types[TIND];
        gopcode(OADD, nodconst(c*SZ_LONG), Z, &nod2);
+       nod2.type = t;
        
-       gopcode(OGT, &nod3, Z, nodconst(0));
+       gopcode(OGT, nodconst(0), &nod3, Z);
        patch(p, pc1);
 
        regfree(&nod3);
@@ -1065,3 +1210,63 @@ layout(Node *f, Node *t, int c, int cv, Node *cn)
        regfree(&t1);
        regfree(&t2);
 }
+
+/*
+ * if a constant and vlong, doesn't fit as 32-bit signed immediate
+ */
+int
+hardconst(Node *n)
+{
+       return n->op == OCONST && !sconst(n);
+}
+
+/*
+ * casting up to t2 covers an intermediate cast to t1
+ */
+int
+castup(Type *t1, Type *t2)
+{
+       int ft;
+
+       if(!nilcast(t1, t2))
+               return 0;
+       /* known to be small to large */
+       ft = t1->etype;
+       switch(t2->etype){
+       case TINT:
+       case TLONG:
+               return ft == TLONG || ft == TINT || ft == TSHORT || ft == TCHAR;
+       case TUINT:
+       case TULONG:
+               return ft == TULONG || ft == TUINT || ft == TUSHORT || ft == TUCHAR;
+       case TVLONG:
+               return ft == TLONG || ft == TINT || ft == TSHORT;
+       case TUVLONG:
+               return ft == TULONG || ft == TUINT || ft == TUSHORT;
+       }
+       return 0;
+}
+
+int
+cond(int op)
+{
+       switch(op) {
+       case OANDAND:
+       case OOROR:
+       case ONOT:
+               return 1;
+
+       case OEQ:
+       case ONE:
+       case OLE:
+       case OLT:
+       case OGE:
+       case OGT:
+       case OHI:
+       case OHS:
+       case OLO:
+       case OLS:
+               return 1;
+       }
+       return 0;
+}