]> Cypherpunks repositories - gostls13.git/commitdiff
clean up gmove:
authorRuss Cox <rsc@golang.org>
Thu, 28 May 2009 06:55:14 +0000 (23:55 -0700)
committerRuss Cox <rsc@golang.org>
Thu, 28 May 2009 06:55:14 +0000 (23:55 -0700)
* conversions all in one place.
* no separate load, store phases;
  direct memory addressing when possible
  (this is the x86 after all!).
  avoids extra registers, extra MOVQs.
* fixes int32 -> uint64 bug
  (was zero-extending)

R=ken
OCL=29482
CL=29484

src/cmd/6g/cgen.c
src/cmd/6g/ggen.c
src/cmd/6g/gsubr.c
src/cmd/gc/const.c
src/cmd/gc/dcl.c
src/cmd/gc/go.h
src/cmd/gc/subr.c

index 1027f9076fb488113ce696e4fab1360f887221ea..5ac8b0f9cc9f52fce5f93029b6b2a09f14c44033 100644 (file)
@@ -201,8 +201,14 @@ cgen(Node *n, Node *res)
                        break;
                }
                regalloc(&n1, nl->type, res);
+               regalloc(&n2, n->type, &n1);
                cgen(nl, &n1);
-               gmove(&n1, res);
+               // if we do the conversion n1 -> n2 here
+               // reusing the register, then gmove won't
+               // have to allocate its own register.
+               gmove(&n1, &n2);
+               gmove(&n2, res);
+               regfree(&n2);
                regfree(&n1);
                break;
 
index 6da512da1d0b819979fb414cdf6e80b312b0fcf6..06b0f8003f1be6eb7b9761adbb5b4f812839c4f0 100644 (file)
@@ -491,8 +491,10 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
                        t = types[TUINT32];
        }
        a = optoas(op, t);
+       ax->type = t;
+       dx->type = t;
 
-       regalloc(&n3, nr->type, N);
+       regalloc(&n3, t, N);
        if(nl->ullman >= nr->ullman) {
                cgen(nl, ax);
                if(!issigned[t->etype]) {
index 0d9034f2ce226bf9a31f8085e70132087a42ed45..d8bd0767f08044696f1539c2ba65028dff55827c 100644 (file)
@@ -411,575 +411,397 @@ gconreg(int as, vlong c, int reg)
 #define        CASE(a,b)       (((a)<<16)|((b)<<0))
 
 /*
- * generate move:
- *     t = f
+ * Is this node a memory operand?
  */
-void
-gmove(Node *f, Node *t)
+int
+ismem(Node *n)
 {
-       int ft, tt, t64, a;
-       Node nod, nod1, nod2, nod3, nodc;
-       Prog *p1, *p2;
-
-       ft = simtype[f->type->etype];
-       tt = simtype[t->type->etype];
-
-       t64 = 0;
-       if(tt == TINT64 || tt == TUINT64 || tt == TPTR64)
-               t64 = 1;
-
-       if(debug['M'])
-               print("gop: %O %O[%E],%O[%E]\n", OAS,
-                       f->op, ft, t->op, tt);
-       if(isfloat[ft] && f->op == OCONST) {
-               /* TO DO: pick up special constants, possibly preloaded */
-               if(mpgetflt(f->val.u.fval) == 0.0) {
-                       regalloc(&nod, t->type, t);
-                       gins(AXORPD, &nod, &nod);
-                       gmove(&nod, t);
-                       regfree(&nod);
-                       return;
-               }
+       switch(n->op) {
+       case OINDREG:
+       case ONAME:
+       case OPARAM:
+               return 1;
        }
+       return 0;
+}
+
 /*
- * load
+ * set up nodes representing 2^63
  */
-       if(f->op == ONAME || f->op == OINDREG ||
-          f->op == OIND || f->op == OINDEX)
-       switch(ft) {
-       case TINT8:
-               a = AMOVBLSX;
-               if(t64)
-                       a = AMOVBQSX;
-               goto ld;
-       case TBOOL:
-       case TUINT8:
-               a = AMOVBLZX;
-               if(t64)
-                       a = AMOVBQZX;
-               goto ld;
-       case TINT16:
-               a = AMOVWLSX;
-               if(t64)
-                       a = AMOVWQSX;
-               goto ld;
-       case TUINT16:
-               a = AMOVWLZX;
-               if(t64)
-                       a = AMOVWQZX;
-               goto ld;
-       case TINT32:
-               if(isfloat[tt]) {
-                       regalloc(&nod, t->type, t);
-                       if(tt == TFLOAT64)
-                               a = ACVTSL2SD;
-                       else
-                               a = ACVTSL2SS;
-                       gins(a, f, &nod);
-                       gmove(&nod, t);
-                       regfree(&nod);
-                       return;
-               }
-               a = AMOVL;
-               if(t64)
-                       a = AMOVLQSX;
-               goto ld;
-       case TUINT32:
-       case TPTR32:
-               a = AMOVL;
-               if(t64)
-                       a = AMOVLQZX;
-               goto ld;
-       case TINT64:
-               if(isfloat[tt]) {
-                       regalloc(&nod, t->type, t);
-                       if(tt == TFLOAT64)
-                               a = ACVTSQ2SD;
-                       else
-                               a = ACVTSQ2SS;
-                       gins(a, f, &nod);
-                       gmove(&nod, t);
-                       regfree(&nod);
-                       return;
-               }
-       case TUINT64:
-       case TPTR64:
-               a = AMOVQ;
+Node bigi;
+Node bigf;
 
-       ld:
-               regalloc(&nod, f->type, t);
-               nod.type = t64? types[TINT64]: types[TINT32];
-               gins(a, f, &nod);
-               gmove(&nod, t);
-               regfree(&nod);
-               return;
+void
+bignodes(void)
+{
+       static int did;
 
-       case TFLOAT32:
-               a = AMOVSS;
-               goto fld;
-       case TFLOAT64:
-               a = AMOVSD;
-       fld:
-               regalloc(&nod, f->type, t);
-               if(tt != TFLOAT64 && tt != TFLOAT32){   /* TO DO: why is this here */
-                       dump("odd tree", f);
-                       nod.type = t64? types[TINT64]: types[TINT32];
-               }
-               gins(a, f, &nod);
-               gmove(&nod, t);
-               regfree(&nod);
+       if(did)
                return;
-       }
+       did = 1;
 
-/*
- * store
- */
-       if(t->op == ONAME || t->op == OINDREG ||
-          t->op == OIND || t->op == OINDEX)
-       switch(tt) {
-       case TBOOL:
-       case TINT8:
-       case TUINT8:
-               a = AMOVB;
-               goto st;
-       case TINT16:
-       case TUINT16:
-               a = AMOVW;
-               goto st;
-       case TINT32:
-       case TUINT32:
-               a = AMOVL;
-               goto st;
-       case TINT64:
-       case TUINT64:
-               a = AMOVQ;
-               goto st;
+       nodconst(&bigi, types[TUINT64], 1);
+       mpshiftfix(bigi.val.u.xval, 63);
 
-       case TPTR32:
-       case TPTR64:
-               /*
-                * store to pointer.
-                */
-               if(tt == TPTR32)
-                       a = AMOVL;
-               else
-                       a = AMOVQ;
-               switch(t->op) {
-               default:
-                       dump("gmove to", t);
-                       fatal("gmove t %O", t->op);
+       bigf = bigi;
+       bigf.type = types[TFLOAT64];
+       bigf.val.ctype = CTFLT;
+       bigf.val.u.fval = mal(sizeof *bigf.val.u.fval);
+       mpmovefixflt(bigf.val.u.fval, bigi.val.u.xval);
+}
 
-               case OINDREG:
-                       if(t->val.u.reg != D_SP)
-                               goto refcount;
-                       break;
+/*
+ * generate move:
+ *     t = f
+ * hard part is conversions.
+ */
+void
+gmove(Node *f, Node *t)
+{
+       int a, ft, tt;
+       Type *cvt;
+       Node r1, r2, r3, r4, zero, one, con;
+       Prog *p1, *p2;
 
-               case ONAME:
-                       switch(t->class) {
-                       default:
-                               dump("gmove", t);
-                               fatal("gmove t %O class %d reg %R", t->op, t->class, t->val.u.reg);
-                       case PEXTERN:
-                               goto refcount;
-                               break;
-                       case PAUTO:
-                       case PPARAM:
-                       case PPARAMOUT:
-                               break;
+       if(debug['M'])
+               print("gmove %N -> %N\n", f, t);
+
+       ft = simsimtype(f->type);
+       tt = simsimtype(t->type);
+       cvt = t->type;
+
+       // cannot have two memory operands
+       if(ismem(f) && ismem(t))
+               goto hard;
+
+       // convert constant to desired type
+       if(f->op == OLITERAL) {
+               convconst(&con, t->type, &f->val);
+               f = &con;
+               ft = tt;        // so big switch will choose a simple mov
+
+               // some constants can't move directly to memory.
+               if(ismem(t)) {
+                       // float constants come from memory.
+                       if(isfloat[tt])
+                               goto hard;
+                       // 64-bit immediates are really 32-bit sign-extended
+                       // unless moving into a register.
+                       if(isint[tt]) {
+                               if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0)
+                                       goto hard;
+                               if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0)
+                                       goto hard;
                        }
-                       break;
-               }
-               goto st;
-
-       st:
-               // 64-bit immediates only allowed for move into registers.
-               // this is not a move into a register.
-               if(f->op == OCONST || (f->op == OLITERAL && !t64)) {
-                       gins(a, f, t);
-                       return;
                }
-       fst:
-               regalloc(&nod, t->type, f);
-               gmove(f, &nod);
-               gins(a, &nod, t);
-               regfree(&nod);
-               return;
-
-       refcount:
-               if(!debug['r'])
-                       goto st;
-               // for now, mark ref count updates with AXCHGQ.
-               // using a temporary on the left, so no semantic
-               // changes.  code is likely slower, but still correct.
-               if(t64)
-                       a = AXCHGQ;
-               else
-                       a = AXCHGL;
-               regalloc(&nod, t->type, f);
-               gmove(f, &nod);
-               gins(a, &nod, t);
-               regfree(&nod);
-               return;
-
-       case TFLOAT32:
-               a = AMOVSS;
-               goto fst;
-       case TFLOAT64:
-               a = AMOVSD;
-               goto fst;
        }
 
-/*
- * convert
- */
+       // value -> value copy, only one memory operand.
+       // figure out the instruction to use.
+       // break out of switch for one-instruction gins.
+       // goto rdst for "destination must be register".
+       // goto hard for "convert to cvt type first".
+       // otherwise handle and return.
+
        switch(CASE(ft, tt)) {
        default:
-/*
- * integer to integer
- ********
- *             a = AGOK;       break;
-
- *     case CASE(TBOOL, TBOOL):
- *     case CASE(TINT8, TBOOL):
- *     case CASE(TUINT8, TBOOL):
- *     case CASE(TINT16, TBOOL):
- *     case CASE(TUINT16, TBOOL):
- *     case CASE(TINT32, TBOOL):
- *     case CASE(TUINT32, TBOOL):
- *     case CASE(TPTR64, TBOOL):
-
- *     case CASE(TBOOL, TINT8):
- *     case CASE(TINT8, TINT8):
- *     case CASE(TUINT8, TINT8):
- *     case CASE(TINT16, TINT8):
- *     case CASE(TUINT16, TINT8):
- *     case CASE(TINT32, TINT8):
- *     case CASE(TUINT32, TINT8):
- *     case CASE(TPTR64, TINT8):
-
- *     case CASE(TBOOL, TUINT8):
- *     case CASE(TINT8, TUINT8):
- *     case CASE(TUINT8, TUINT8):
- *     case CASE(TINT16, TUINT8):
- *     case CASE(TUINT16, TUINT8):
- *     case CASE(TINT32, TUINT8):
- *     case CASE(TUINT32, TUINT8):
- *     case CASE(TPTR64, TUINT8):
-
- *     case CASE(TINT16, TINT16):
- *     case CASE(TUINT16, TINT16):
- *     case CASE(TINT32, TINT16):
- *     case CASE(TUINT32, TINT16):
- *     case CASE(TPTR64, TINT16):
-
- *     case CASE(TINT16, TUINT16):
- *     case CASE(TUINT16, TUINT16):
- *     case CASE(TINT32, TUINT16):
- *     case CASE(TUINT32, TUINT16):
- *     case CASE(TPTR64, TUINT16):
-
- *     case CASE(TINT64, TUINT):
- *     case CASE(TINT64, TUINT32):
- *     case CASE(TUINT64, TUINT32):
- *****/
-               a = AMOVL;
-               break;
-
+               fatal("gmove %T -> %T", f, t);
+
+       /*
+        * integer copy and truncate
+        */
+       case CASE(TINT8, TINT8):        // same size
+       case CASE(TINT8, TUINT8):
+       case CASE(TUINT8, TINT8):
+       case CASE(TUINT8, TUINT8):
+       case CASE(TINT16, TINT8):       // truncate
+       case CASE(TUINT16, TINT8):
+       case CASE(TINT32, TINT8):
+       case CASE(TUINT32, TINT8):
        case CASE(TINT64, TINT8):
-       case CASE(TINT64, TINT16):
-       case CASE(TINT64, TINT32):
        case CASE(TUINT64, TINT8):
-       case CASE(TUINT64, TINT16):
-       case CASE(TUINT64, TINT32):
-               a = AMOVLQSX;           // this looks bad
+       case CASE(TINT16, TUINT8):
+       case CASE(TUINT16, TUINT8):
+       case CASE(TINT32, TUINT8):
+       case CASE(TUINT32, TUINT8):
+       case CASE(TINT64, TUINT8):
+       case CASE(TUINT64, TUINT8):
+               a = AMOVB;
                break;
 
-       case CASE(TINT32, TINT64):
-       case CASE(TINT32, TPTR64):
-               a = AMOVLQSX;
+       case CASE(TINT16, TINT16):      // same size
+       case CASE(TINT16, TUINT16):
+       case CASE(TUINT16, TINT16):
+       case CASE(TUINT16, TUINT16):
+       case CASE(TINT32, TINT16):      // truncate
+       case CASE(TUINT32, TINT16):
+       case CASE(TINT64, TINT16):
+       case CASE(TUINT64, TINT16):
+       case CASE(TINT32, TUINT16):
+       case CASE(TUINT32, TUINT16):
+       case CASE(TINT64, TUINT16):
+       case CASE(TUINT64, TUINT16):
+               a = AMOVW;
                break;
 
-       case CASE(TUINT32, TINT64):
-       case CASE(TUINT32, TUINT64):
-       case CASE(TUINT32, TPTR64):
-       case CASE(TPTR32, TINT64):
-       case CASE(TPTR32, TUINT64):
-       case CASE(TPTR32, TPTR64):
-               a = AMOVLQZX;
+       case CASE(TINT32, TINT32):      // same size
+       case CASE(TINT32, TUINT32):
+       case CASE(TUINT32, TINT32):
+       case CASE(TUINT32, TUINT32):
+       case CASE(TINT64, TINT32):      // truncate
+       case CASE(TUINT64, TINT32):
+       case CASE(TINT64, TUINT32):
+       case CASE(TUINT64, TUINT32):
+               a = AMOVL;
                break;
 
-       case CASE(TPTR64, TINT64):
-       case CASE(TINT64, TINT64):
-       case CASE(TUINT64, TINT64):
+       case CASE(TINT64, TINT64):      // same size
        case CASE(TINT64, TUINT64):
+       case CASE(TUINT64, TINT64):
        case CASE(TUINT64, TUINT64):
-       case CASE(TPTR64, TUINT64):
-       case CASE(TINT64, TPTR64):
-       case CASE(TUINT64, TPTR64):
-       case CASE(TPTR64, TPTR64):
                a = AMOVQ;
                break;
 
-       case CASE(TINT16, TINT32):
-       case CASE(TINT16, TUINT32):
-               a = AMOVWLSX;
-//             if(f->op == OCONST) {
-//                     f->val.vval &= 0xffff;
-//                     if(f->val.vval & 0x8000)
-//                             f->val.vval |= 0xffff0000;
-//                     a = AMOVL;
-//             }
-               break;
-
-       case CASE(TINT16, TINT64):
-       case CASE(TINT16, TUINT64):
-       case CASE(TINT16, TPTR64):
-               a = AMOVWQSX;
-//             if(f->op == OCONST) {
-//                     f->val.vval &= 0xffff;
-//                     if(f->val.vval & 0x8000){
-//                             f->val.vval |= 0xffff0000;
-//                             f->val.vval |= (vlong)~0 << 32;
-//                     }
-//                     a = AMOVL;
-//             }
-               break;
-
-       case CASE(TUINT16, TINT32):
-       case CASE(TUINT16, TUINT32):
-               a = AMOVWLZX;
-//             if(f->op == OCONST) {
-//                     f->val.vval &= 0xffff;
-//                     a = AMOVL;
-//             }
-               break;
-
-       case CASE(TUINT16, TINT64):
-       case CASE(TUINT16, TUINT64):
-       case CASE(TUINT16, TPTR64):
-               a = AMOVWQZX;
-//             if(f->op == OCONST) {
-//                     f->val.vval &= 0xffff;
-//                     a = AMOVL;      /* MOVL also zero-extends to 64 bits */
-//             }
-               break;
-
-       case CASE(TINT8, TINT16):
+       /*
+        * integer up-conversions
+        */
+       case CASE(TINT8, TINT16):       // sign extend int8
        case CASE(TINT8, TUINT16):
+               a = AMOVBWSX;
+               goto rdst;
        case CASE(TINT8, TINT32):
        case CASE(TINT8, TUINT32):
                a = AMOVBLSX;
-//             if(f->op == OCONST) {
-//                     f->val.vval &= 0xff;
-//                     if(f->val.vval & 0x80)
-//                             f->val.vval |= 0xffffff00;
-//                     a = AMOVL;
-//             }
-               break;
-
+               goto rdst;
        case CASE(TINT8, TINT64):
        case CASE(TINT8, TUINT64):
-       case CASE(TINT8, TPTR64):
                a = AMOVBQSX;
-//             if(f->op == OCONST) {
-//                     f->val.vval &= 0xff;
-//                     if(f->val.vval & 0x80){
-//                             f->val.vval |= 0xffffff00;
-//                             f->val.vval |= (vlong)~0 << 32;
-//                     }
-//                     a = AMOVQ;
-//             }
-               break;
+               goto rdst;
 
-       case CASE(TBOOL, TINT16):
-       case CASE(TBOOL, TUINT16):
-       case CASE(TBOOL, TINT32):
-       case CASE(TBOOL, TUINT32):
-       case CASE(TUINT8, TINT16):
+       case CASE(TUINT8, TINT16):      // zero extend uint8
        case CASE(TUINT8, TUINT16):
+               a = AMOVBWZX;
+               goto rdst;
        case CASE(TUINT8, TINT32):
        case CASE(TUINT8, TUINT32):
                a = AMOVBLZX;
-//             if(f->op == OCONST) {
-//                     f->val.vval &= 0xff;
-//                     a = AMOVL;
-//             }
-               break;
-
-       case CASE(TBOOL, TINT64):
-       case CASE(TBOOL, TUINT64):
-       case CASE(TBOOL, TPTR64):
+               goto rdst;
        case CASE(TUINT8, TINT64):
        case CASE(TUINT8, TUINT64):
-       case CASE(TUINT8, TPTR64):
                a = AMOVBQZX;
-//             if(f->op == OCONST) {
-//                     f->val.vval &= 0xff;
-//                     a = AMOVL;      /* zero-extends to 64-bits */
-//             }
-               break;
+               goto rdst;
 
-/*
- * float to fix
- */
-       case CASE(TFLOAT32, TINT8):
-       case CASE(TFLOAT32, TINT16):
+       case CASE(TINT16, TINT32):      // sign extend int16
+       case CASE(TINT16, TUINT32):
+               a = AMOVWLSX;
+               goto rdst;
+       case CASE(TINT16, TINT64):
+       case CASE(TINT16, TUINT64):
+               a = AMOVWQSX;
+               goto rdst;
+
+       case CASE(TUINT16, TINT32):     // zero extend uint16
+       case CASE(TUINT16, TUINT32):
+               a = AMOVWLZX;
+               goto rdst;
+       case CASE(TUINT16, TINT64):
+       case CASE(TUINT16, TUINT64):
+               a = AMOVWQZX;
+               goto rdst;
+
+       case CASE(TINT32, TINT64):      // sign extend int32
+       case CASE(TINT32, TUINT64):
+               a = AMOVLQSX;
+               goto rdst;
+
+       case CASE(TUINT32, TINT64):     // zero extend uint32
+       case CASE(TUINT32, TUINT64):
+               // AMOVL into a register zeros the top of the register,
+               // so this is not always necessary, but if we rely on AMOVL
+               // the optimizer is almost certain to screw with us.
+               a = AMOVLQZX;
+               goto rdst;
+
+       /*
+       * float to integer
+       */
        case CASE(TFLOAT32, TINT32):
-               regalloc(&nod, t->type, N);
-               gins(ACVTTSS2SL, f, &nod);
-               gmove(&nod, t);
-               regfree(&nod);
-               return;
+               a = ACVTTSS2SL;
+               goto rdst;
+
+       case CASE(TFLOAT64, TINT32):
+               a = ACVTTSD2SL;
+               goto rdst;
 
-       case CASE(TFLOAT32, TBOOL):
-       case CASE(TFLOAT32, TUINT8):
-       case CASE(TFLOAT32, TUINT16):
-       case CASE(TFLOAT32, TUINT32):
        case CASE(TFLOAT32, TINT64):
-       case CASE(TFLOAT32, TUINT64):
-       case CASE(TFLOAT32, TPTR64):
-               regalloc(&nod, t->type, N);
-               gins(ACVTTSS2SQ, f, &nod);
-               gmove(&nod, t);
-               regfree(&nod);
-               return;
+               a = ACVTTSS2SQ;
+               goto rdst;
 
-       case CASE(TFLOAT64, TINT8):
-       case CASE(TFLOAT64, TINT16):
-       case CASE(TFLOAT64, TINT32):
-               regalloc(&nod, t->type, N);
-               gins(ACVTTSD2SL, f, &nod);
-               gmove(&nod, t);
-               regfree(&nod);
-               return;
+       case CASE(TFLOAT64, TINT64):
+               a = ACVTTSD2SQ;
+               goto rdst;
 
-       case CASE(TFLOAT64, TBOOL):
-       case CASE(TFLOAT64, TUINT8):
+       case CASE(TFLOAT32, TINT16):
+       case CASE(TFLOAT32, TINT8):
+       case CASE(TFLOAT32, TUINT16):
+       case CASE(TFLOAT32, TUINT8):
+       case CASE(TFLOAT64, TINT16):
+       case CASE(TFLOAT64, TINT8):
        case CASE(TFLOAT64, TUINT16):
+       case CASE(TFLOAT64, TUINT8):
+               // convert via int32.
+               cvt = types[TINT32];
+               goto hard;
+
+       case CASE(TFLOAT32, TUINT32):
        case CASE(TFLOAT64, TUINT32):
-       case CASE(TFLOAT64, TINT64):
-       case CASE(TFLOAT64, TUINT64):
-       case CASE(TFLOAT64, TPTR64):
-               regalloc(&nod, t->type, N);
-               gins(ACVTTSD2SQ, f, &nod);
-               gmove(&nod, t);
-               regfree(&nod);
-               return;
+               // convert via int64.
+               cvt = types[TINT64];
+               goto hard;
 
-/*
- * uvlong to float
- */
-       case CASE(TUINT64, TFLOAT64):
-       case CASE(TUINT64, TFLOAT32):
-               a = ACVTSQ2SS;
-               if(tt == TFLOAT64)
-                       a = ACVTSQ2SD;
-               regalloc(&nod, f->type, f);
-               gmove(f, &nod);
-               regalloc(&nod1, t->type, t);
-               nodconst(&nodc, types[TUINT64], 0);
-               gins(ACMPQ, &nod, &nodc);
-               p1 = gbranch(AJLT, T);
-               gins(a, &nod, &nod1);
+       case CASE(TFLOAT32, TUINT64):
+       case CASE(TFLOAT64, TUINT64):
+               // algorithm is:
+               //      if small enough, use native float64 -> int64 conversion.
+               //      otherwise, subtract 2^63, convert, and add it back.
+               a = ACVTSS2SQ;
+               if(ft == TFLOAT64)
+                       a = ACVTSD2SQ;
+               bignodes();
+               regalloc(&r1, types[ft], N);
+               regalloc(&r2, types[tt], t);
+               regalloc(&r3, types[ft], N);
+               regalloc(&r4, types[tt], N);
+               gins(optoas(OAS, f->type), f, &r1);
+               gins(optoas(OCMP, f->type), &bigf, &r1);
+               p1 = gbranch(optoas(OLE, f->type), T);
+               gins(a, &r1, &r2);
                p2 = gbranch(AJMP, T);
                patch(p1, pc);
-               regalloc(&nod2, f->type, N);
-               regalloc(&nod3, f->type, N);
-               gmove(&nod, &nod2);
-               nodconst(&nodc, types[TUINT64], 1);
-               gins(ASHRQ, &nodc, &nod2);
-               gmove(&nod, &nod3);
-               gins(AANDL, &nodc, &nod3);
-               gins(AORQ, &nod3, &nod2);
-               gins(a, &nod2, &nod1);
-               gins(tt == TFLOAT64? AADDSD: AADDSS, &nod1, &nod1);
-               regfree(&nod2);
-               regfree(&nod3);
+               gins(optoas(OAS, f->type), &bigf, &r3);
+               gins(optoas(OSUB, f->type), &r3, &r1);
+               gins(a, &r1, &r2);
+               gins(AMOVQ, &bigi, &r4);
+               gins(AXORQ, &r4, &r2);
                patch(p2, pc);
-               regfree(&nod);
-               regfree(&nod1);
+               gmove(&r2, t);
+               regfree(&r4);
+               regfree(&r3);
+               regfree(&r2);
+               regfree(&r1);
                return;
 
-       case CASE(TUINT32, TFLOAT64):
-       case CASE(TUINT32, TFLOAT32):
-               a = ACVTSQ2SS;
-               if(tt == TFLOAT64)
-                       a = ACVTSQ2SD;
-               regalloc(&nod, f->type, f);
-               gins(AMOVLQZX, f, &nod);
-               regalloc(&nod1, t->type, t);
-               gins(a, &nod, &nod1);
-               gmove(&nod1, t);
-               regfree(&nod);
-               regfree(&nod1);
-               return;
+       /*
+        * integer to float
+        */
+       case CASE(TINT32, TFLOAT32):
+               a = ACVTSL2SS;
+               goto rdst;
+
+
+       case CASE(TINT32, TFLOAT64):
+               a = ACVTSL2SD;
+               goto rdst;
 
-/*
- * fix to float
- */
        case CASE(TINT64, TFLOAT32):
-       case CASE(TPTR64, TFLOAT32):
-               regalloc(&nod, t->type, t);
-               gins(ACVTSQ2SS, f, &nod);
-               gmove(&nod, t);
-               regfree(&nod);
-               return;
+               a = ACVTSQ2SS;
+               goto rdst;
 
        case CASE(TINT64, TFLOAT64):
-       case CASE(TPTR64, TFLOAT64):
-               regalloc(&nod, t->type, t);
-               gins(ACVTSQ2SD, f, &nod);
-               gmove(&nod, t);
-               regfree(&nod);
-               return;
+               a = ACVTSQ2SD;
+               goto rdst;
 
-       case CASE(TBOOL, TFLOAT32):
-       case CASE(TINT8, TFLOAT32):
-       case CASE(TUINT8, TFLOAT32):
        case CASE(TINT16, TFLOAT32):
-       case CASE(TUINT16, TFLOAT32):
-       case CASE(TINT32, TFLOAT32):
-               regalloc(&nod, t->type, t);
-               gins(ACVTSL2SS, f, &nod);
-               gmove(&nod, t);
-               regfree(&nod);
-               return;
-
-       case CASE(TBOOL, TFLOAT64):
-       case CASE(TINT8, TFLOAT64):
-       case CASE(TUINT8, TFLOAT64):
        case CASE(TINT16, TFLOAT64):
+       case CASE(TINT8, TFLOAT32):
+       case CASE(TINT8, TFLOAT64):
+       case CASE(TUINT16, TFLOAT32):
        case CASE(TUINT16, TFLOAT64):
-       case CASE(TINT32, TFLOAT64):
-               regalloc(&nod, t->type, t);
-               gins(ACVTSL2SD, f, &nod);
-               gmove(&nod, t);
-               regfree(&nod);
+       case CASE(TUINT8, TFLOAT32):
+       case CASE(TUINT8, TFLOAT64):
+               // convert via int32
+               cvt = types[TINT32];
+               goto hard;
+
+       case CASE(TUINT32, TFLOAT32):
+       case CASE(TUINT32, TFLOAT64):
+               // convert via int64.
+               cvt = types[TINT64];
+               goto hard;
+
+       case CASE(TUINT64, TFLOAT32):
+       case CASE(TUINT64, TFLOAT64):
+               // algorithm is:
+               //      if small enough, use native int64 -> uint64 conversion.
+               //      otherwise, halve (rounding to odd?), convert, and double.
+               a = ACVTSQ2SS;
+               if(tt == TFLOAT64)
+                       a = ACVTSQ2SD;
+               nodconst(&zero, types[TUINT64], 0);
+               nodconst(&one, types[TUINT64], 1);
+               regalloc(&r1, f->type, f);
+               regalloc(&r2, t->type, t);
+               regalloc(&r3, f->type, N);
+               regalloc(&r4, f->type, N);
+               gmove(f, &r1);
+               gins(ACMPQ, &r1, &zero);
+               p1 = gbranch(AJLT, T);
+               gins(a, &r1, &r2);
+               p2 = gbranch(AJMP, T);
+               patch(p1, pc);
+               gmove(&r1, &r3);
+               gins(ASHRQ, &one, &r3);
+               gmove(&r1, &r4);
+               gins(AANDL, &one, &r4);
+               gins(AORQ, &r4, &r3);
+               gins(a, &r3, &r2);
+               gins(optoas(OADD, t->type), &r2, &r2);
+               patch(p2, pc);
+               gmove(&r2, t);
+               regfree(&r4);
+               regfree(&r3);
+               regfree(&r2);
+               regfree(&r1);
                return;
 
-/*
- * float to float
- */
+       /*
       * float to float
       */
        case CASE(TFLOAT32, TFLOAT32):
                a = AMOVSS;
                break;
-       case CASE(TFLOAT64, TFLOAT32):
-               a = ACVTSD2SS;
-               break;
-       case CASE(TFLOAT32, TFLOAT64):
-               a = ACVTSS2SD;
-               break;
+
        case CASE(TFLOAT64, TFLOAT64):
                a = AMOVSD;
                break;
+
+       case CASE(TFLOAT32, TFLOAT64):
+               a = ACVTSS2SD;
+               goto rdst;
+
+       case CASE(TFLOAT64, TFLOAT32):
+               a = ACVTSD2SS;
+               goto rdst;
        }
-       if(a == AMOVQ ||
-          a == AMOVSD ||
-          a == AMOVSS ||
-          (a == AMOVL && f->type->width == t->type->width))    /* TO DO: check AMOVL */
-               if(samaddr(f, t))
-                       return;
+
        gins(a, f, t);
+       return;
+
+rdst:
+       // requires register destination
+       regalloc(&r1, t->type, t);
+       gins(a, f, &r1);
+       gmove(&r1, t);
+       regfree(&r1);
+       return;
+
+hard:
+       // requires register intermediate
+       regalloc(&r1, cvt, t);
+       gmove(f, &r1);
+       gmove(&r1, t);
+       regfree(&r1);
+       return;
 }
 
 int
@@ -1026,6 +848,17 @@ gins(int as, Node *f, Node *t)
 //             regfree(&nod);
 //     }
 
+       switch(as) {
+       case AMOVB:
+       case AMOVW:
+       case AMOVL:
+       case AMOVQ:
+       case AMOVSS:
+       case AMOVSD:
+               if(f != N && t != N && samaddr(f, t))
+                       return nil;
+       }
+
        p = prog(as);
        if(f != N)
                naddr(f, &p->from);
index 33acec6fc41cb29cb59382408be3b7add716c331..72cf684adfd847fa9c0dd90dec27b9e509ac30b1 100644 (file)
@@ -801,3 +801,95 @@ nonnegconst(Node *n)
        }
        return -1;
 }
+
+/*
+ * convert x to type et and back to int64
+ * for sign extension and truncation.
+ */
+int64
+iconv(int64 x, int et)
+{
+       switch(et) {
+       case TINT8:
+               x = (int8)x;
+               break;
+       case TUINT8:
+               x = (uint8)x;
+               break;
+       case TINT16:
+               x = (int16)x;
+               break;
+       case TUINT16:
+               x = (uint64)x;
+               break;
+       case TINT32:
+               x = (int32)x;
+               break;
+       case TUINT32:
+               x = (uint32)x;
+               break;
+       case TINT64:
+       case TUINT64:
+               break;
+       }
+       return x;
+}
+
+/*
+ * convert constant val to type t; leave in con.
+ * for back end.
+ */
+void
+convconst(Node *con, Type *t, Val *val)
+{
+       int64 i;
+       int tt;
+
+       tt = simsimtype(t);
+
+       // copy the constant for conversion
+       nodconst(con, types[TINT8], 0);
+       con->type = t;
+       con->val = *val;
+
+       if(isint[tt]) {
+               con->val.ctype = CTINT;
+               con->val.u.xval = mal(sizeof *con->val.u.xval);
+               switch(val->ctype) {
+               default:
+                       fatal("convconst ctype=%d %lT", val->ctype, t->type);
+               case CTINT:
+                       i = mpgetfix(val->u.xval);
+                       break;
+               case CTBOOL:
+                       i = val->u.bval;
+                       break;
+               case CTNIL:
+                       i = 0;
+                       break;
+               }
+               i = iconv(i, tt);
+               mpmovecfix(con->val.u.xval, i);
+               return;
+       }
+
+       if(isfloat[tt]) {
+               if(con->val.ctype == CTINT) {
+                       con->val.ctype = CTFLT;
+                       con->val.u.fval = mal(sizeof *con->val.u.fval);
+                       mpmovefixflt(con->val.u.fval, val->u.xval);
+               }
+               if(con->val.ctype != CTFLT)
+                       fatal("convconst ctype=%d %T", con->val.ctype, t);
+               if(!isfloat[tt]) {
+                       // easy to handle, but can it happen?
+                       fatal("convconst CTINT %T", t);
+               }
+               if(tt == TFLOAT32)
+                       con->val.u.fval = truncfltlit(con->val.u.fval, t);
+               return;
+       }
+
+       fatal("convconst %lT constant", t);
+
+}
index e4d1a04555a980c8aaaa86755a0b5ed810b3f746..6068651b85ee3cdff69a360e56e1bb191d0ee0c6 100644 (file)
@@ -1061,7 +1061,7 @@ addconst(Node *n, Node *e, int ctxt)
        d = dcl();
        d->dsym = s;
        d->dnode = e;
-       d->op = OCONST;
+       d->op = OLITERAL;
        d->back = r->back;
        r->back->forw = d;
        r->back = d;
index eb253d778d2a6afae5301e2a4c4b114c10c17a0f..5abdfcce07179dbbd3e26958e32647db850cfb24 100644 (file)
@@ -298,7 +298,7 @@ enum
 {
        OXXX,
 
-       OTYPE, OCONST, OVAR, OIMPORT,
+       OTYPE, OVAR, OIMPORT,
 
        ONAME, ONONAME, ODCL,
        ODOT, ODOTPTR, ODOTMETH, ODOTINTER,
@@ -315,7 +315,7 @@ enum
        OEQ, ONE, OLT, OLE, OGE, OGT,
        OADD, OSUB, OOR, OXOR,
        OMUL, ODIV, OMOD, OLSH, ORSH, OAND, OANDNOT,
-       OINC, ODEC,     // placeholders - not used
+       OINC, ODEC,
        OFUNC,
        OLABEL,
        OBREAK,
@@ -795,6 +795,8 @@ Node*       adddot(Node*);
 void   expandmeth(Sym*, Type*);
 void   genwrapper(Type*, Type*, Sym*);
 
+int    simsimtype(Type*);
+
 /*
  *     dcl.c
  */
@@ -949,6 +951,8 @@ int smallintconst(Node*);
 long   nonnegconst(Node*);
 int    consttype(Node*);
 int    isconst(Node*, int);
+Mpflt* truncfltlit(Mpflt*, Type*);
+void   convconst(Node*, Type*, Val*);
 
 /*
  *     align.c
index de32c8e6d44eeac6ebb3c4dc1b6d6e5c8a3de13c..dcaa11a004398686be2c2e9201a4970eeebf4484 100644 (file)
@@ -671,7 +671,6 @@ opnames[] =
        [OCOMPOS]       = "COMPOS",
        [OCOMPSLICE]    = "COMPSLICE",
        [OCOM]          = "COM",
-       [OCONST]        = "CONST",
        [OCONTINUE]     = "CONTINUE",
        [OCONV]         = "CONV",
        [ODCLARG]       = "DCLARG",
@@ -3015,3 +3014,29 @@ runifacechecks(void)
        }
        lineno = lno;
 }
+
+/*
+ * even simpler simtype; get rid of ptr, bool.
+ * assuming that the front end has rejected
+ * all the invalid conversions (like ptr -> bool)
+ */
+int
+simsimtype(Type *t)
+{
+       int et;
+
+       et = simtype[t->etype];
+       switch(et) {
+       case TPTR32:
+               et = TUINT32;
+               break;
+       case TPTR64:
+               et = TUINT64;
+               break;
+       case TBOOL:
+               et = TUINT8;
+               break;
+       }
+       return et;
+}
+