]> Cypherpunks repositories - gostls13.git/commitdiff
trivial cut and paste: move 64-bit simulation into cgen64.c
authorRuss Cox <rsc@golang.org>
Wed, 3 Jun 2009 06:26:02 +0000 (23:26 -0700)
committerRuss Cox <rsc@golang.org>
Wed, 3 Jun 2009 06:26:02 +0000 (23:26 -0700)
R=ken
OCL=29812
CL=29812

src/cmd/8g/Makefile
src/cmd/8g/cgen.c
src/cmd/8g/cgen64.c [new file with mode: 0644]

index 78e0ee4ec46ca7983005cbf31e238b211eed6dbd..02ddfa6dd0cb83a36ccd444b088b323792aa7e2a 100644 (file)
@@ -21,6 +21,7 @@ OFILES=\
        ggen.$O\
        gsubr.$O\
        cgen.$O\
+       cgen64.$O\
 #      peep.$O\
 #      reg.$O\
 
index 75c15cd23a4d0105e144d4cdd0f7757a4f916b71..b524f99328e747893963afce124968f3ffdf6663 100644 (file)
@@ -984,509 +984,3 @@ sgen(Node *n, Node *res, int w)
        }
 }
 
-/*
- * attempt to generate 64-bit
- *     res = n
- * return 1 on success, 0 if op not handled.
- */
-void
-cgen64(Node *n, Node *res)
-{
-       Node t1, t2, ax, dx, cx, ex, fx, *l, *r;
-       Node lo1, lo2, lo3, hi1, hi2, hi3;
-       Prog *p1, *p2;
-       uint64 v;
-       uint32 lv, hv;
-
-       if(res->op != OINDREG && res->op != ONAME) {
-               dump("n", n);
-               dump("res", res);
-               fatal("cgen64 %O of %O", n->op, res->op);
-       }
-       switch(n->op) {
-       default:
-               fatal("cgen64 %O", n->op);
-
-       case OMINUS:
-               cgen(n->left, res);
-               split64(res, &lo1, &hi1);
-               gins(ANEGL, N, &lo1);
-               gins(AADCL, ncon(0), &hi1);
-               gins(ANEGL, N, &hi1);
-               splitclean();
-               return;
-
-       case OCOM:
-               cgen(n->left, res);
-               split64(res, &lo1, &hi1);
-               gins(ANOTL, N, &lo1);
-               gins(ANOTL, N, &hi1);
-               splitclean();
-               return;
-
-       case OADD:
-       case OSUB:
-       case OMUL:
-       case OLSH:
-       case ORSH:
-       case OAND:
-       case OOR:
-       case OXOR:
-               // binary operators.
-               // common setup below.
-               break;
-       }
-
-       l = n->left;
-       r = n->right;
-       if(!l->addable) {
-               tempalloc(&t1, l->type);
-               cgen(l, &t1);
-               l = &t1;
-       }
-       if(r != N && !r->addable) {
-               tempalloc(&t2, r->type);
-               cgen(r, &t2);
-               r = &t2;
-       }
-
-       nodreg(&ax, types[TINT32], D_AX);
-       nodreg(&cx, types[TINT32], D_CX);
-       nodreg(&dx, types[TINT32], D_DX);
-
-       // Setup for binary operation.
-       split64(l, &lo1, &hi1);
-       if(is64(r->type))
-               split64(r, &lo2, &hi2);
-
-       // Do op.  Leave result in DX:AX.
-       switch(n->op) {
-       case OADD:
-               // TODO: Constants
-               gins(AMOVL, &lo1, &ax);
-               gins(AMOVL, &hi1, &dx);
-               gins(AADDL, &lo2, &ax);
-               gins(AADCL, &hi2, &dx);
-               break;
-
-       case OSUB:
-               // TODO: Constants.
-               gins(AMOVL, &lo1, &ax);
-               gins(AMOVL, &hi1, &dx);
-               gins(ASUBL, &lo2, &ax);
-               gins(ASBBL, &hi2, &dx);
-               break;
-
-       case OMUL:
-               // let's call the next two EX and FX.
-               regalloc(&ex, types[TPTR32], N);
-               regalloc(&fx, types[TPTR32], N);
-
-               // load args into DX:AX and EX:CX.
-               gins(AMOVL, &lo1, &ax);
-               gins(AMOVL, &hi1, &dx);
-               gins(AMOVL, &lo2, &cx);
-               gins(AMOVL, &hi2, &ex);
-
-               // if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply.
-               gins(AMOVL, &dx, &fx);
-               gins(AORL, &ex, &fx);
-               p1 = gbranch(AJNE, T);
-               gins(AMULL, &cx, N);    // implicit &ax
-               p2 = gbranch(AJMP, T);
-               patch(p1, pc);
-
-               // full 64x64 -> 64, from 32x32 -> 64.
-               gins(AIMULL, &cx, &dx);
-               gins(AMOVL, &ax, &fx);
-               gins(AIMULL, &ex, &fx);
-               gins(AADDL, &dx, &fx);
-               gins(AMOVL, &cx, &dx);
-               gins(AMULL, &dx, N);    // implicit &ax
-               gins(AADDL, &fx, &dx);
-               patch(p2, pc);
-
-               regfree(&ex);
-               regfree(&fx);
-               break;
-
-       case OLSH:
-               if(r->op == OLITERAL) {
-                       v = mpgetfix(r->val.u.xval);
-                       if(v >= 64) {
-                               if(is64(r->type))
-                                       splitclean();
-                               splitclean();
-                               split64(res, &lo2, &hi2);
-                               gins(AMOVL, ncon(0), &lo2);
-                               gins(AMOVL, ncon(0), &hi2);
-                               splitclean();
-                               goto out;
-                       }
-                       if(v >= 32) {
-                               if(is64(r->type))
-                                       splitclean();
-                               split64(res, &lo2, &hi2);
-                               gmove(&lo1, &hi2);
-                               if(v > 32) {
-                                       gins(ASHLL, ncon(v - 32), &hi2);
-                               }
-                               gins(AMOVL, ncon(0), &lo2);
-                               splitclean();
-                               splitclean();
-                               goto out;
-                       }
-
-                       // general shift
-                       gins(AMOVL, &lo1, &ax);
-                       gins(AMOVL, &hi1, &dx);
-                       p1 = gins(ASHLL, ncon(v), &dx);
-                       p1->from.index = D_AX;  // double-width shift
-                       p1->from.scale = 0;
-                       gins(ASHLL, ncon(v), &ax);
-                       break;
-               }
-
-               // load value into DX:AX.
-               gins(AMOVL, &lo1, &ax);
-               gins(AMOVL, &hi1, &dx);
-
-               // load shift value into register.
-               // if high bits are set, zero value.
-               p1 = P;
-               if(is64(r->type)) {
-                       gins(ACMPL, &hi2, ncon(0));
-                       p1 = gbranch(AJNE, T);
-                       gins(AMOVL, &lo2, &cx);
-               } else
-                       gins(AMOVL, r, &cx);
-
-               // if shift count is >=64, zero value
-               gins(ACMPL, &cx, ncon(64));
-               p2 = gbranch(optoas(OLT, types[TUINT32]), T);
-               if(p1 != P)
-                       patch(p1, pc);
-               gins(AXORL, &dx, &dx);
-               gins(AXORL, &ax, &ax);
-               patch(p2, pc);
-
-               // if shift count is >= 32, zero low.
-               gins(ACMPL, &cx, ncon(32));
-               p1 = gbranch(optoas(OLT, types[TUINT32]), T);
-               gins(AMOVL, &ax, &dx);
-               gins(ASHLL, &cx, &dx);  // SHLL only uses bottom 5 bits of count
-               gins(AXORL, &ax, &ax);
-               p2 = gbranch(AJMP, T);
-               patch(p1, pc);
-
-               // general shift
-               p1 = gins(ASHLL, &cx, &dx);
-               p1->from.index = D_AX;  // double-width shift
-               p1->from.scale = 0;
-               gins(ASHLL, &cx, &ax);
-               patch(p2, pc);
-               break;
-
-       case ORSH:
-               if(r->op == OLITERAL) {
-                       v = mpgetfix(r->val.u.xval);
-                       if(v >= 64) {
-                               if(is64(r->type))
-                                       splitclean();
-                               splitclean();
-                               split64(res, &lo2, &hi2);
-                               if(hi1.type->etype == TINT32) {
-                                       gmove(&hi1, &lo2);
-                                       gins(ASARL, ncon(31), &lo2);
-                                       gmove(&hi1, &hi2);
-                                       gins(ASARL, ncon(31), &hi2);
-                               } else {
-                                       gins(AMOVL, ncon(0), &lo2);
-                                       gins(AMOVL, ncon(0), &hi2);
-                               }
-                               splitclean();
-                               goto out;
-                       }
-                       if(v >= 32) {
-                               if(is64(r->type))
-                                       splitclean();
-                               split64(res, &lo2, &hi2);
-                               gmove(&hi1, &lo2);
-                               if(v > 32)
-                                       gins(optoas(ORSH, hi1.type), ncon(v-32), &lo2);
-                               if(hi1.type->etype == TINT32) {
-                                       gmove(&hi1, &hi2);
-                                       gins(ASARL, ncon(31), &hi2);
-                               } else
-                                       gins(AMOVL, ncon(0), &hi2);
-                               splitclean();
-                               splitclean();
-                               goto out;
-                       }
-
-                       // general shift
-                       gins(AMOVL, &lo1, &ax);
-                       gins(AMOVL, &hi1, &dx);
-                       p1 = gins(ASHRL, ncon(v), &ax);
-                       p1->from.index = D_DX;  // double-width shift
-                       p1->from.scale = 0;
-                       gins(optoas(ORSH, hi1.type), ncon(v), &dx);
-                       break;
-               }
-
-               // load value into DX:AX.
-               gins(AMOVL, &lo1, &ax);
-               gins(AMOVL, &hi1, &dx);
-
-               // load shift value into register.
-               // if high bits are set, zero value.
-               p1 = P;
-               if(is64(r->type)) {
-                       gins(ACMPL, &hi2, ncon(0));
-                       p1 = gbranch(AJNE, T);
-                       gins(AMOVL, &lo2, &cx);
-               } else
-                       gins(AMOVL, r, &cx);
-
-               // if shift count is >=64, zero or sign-extend value
-               gins(ACMPL, &cx, ncon(64));
-               p2 = gbranch(optoas(OLT, types[TUINT32]), T);
-               if(p1 != P)
-                       patch(p1, pc);
-               if(hi1.type->etype == TINT32) {
-                       gins(ASARL, ncon(31), &dx);
-                       gins(AMOVL, &dx, &ax);
-               } else {
-                       gins(AXORL, &dx, &dx);
-                       gins(AXORL, &ax, &ax);
-               }
-               patch(p2, pc);
-
-               // if shift count is >= 32, sign-extend hi.
-               gins(ACMPL, &cx, ncon(32));
-               p1 = gbranch(optoas(OLT, types[TUINT32]), T);
-               gins(AMOVL, &dx, &ax);
-               if(hi1.type->etype == TINT32) {
-                       gins(ASARL, &cx, &ax);  // SARL only uses bottom 5 bits of count
-                       gins(ASARL, ncon(31), &dx);
-               } else {
-                       gins(ASHRL, &cx, &ax);
-                       gins(AXORL, &dx, &dx);
-               }
-               p2 = gbranch(AJMP, T);
-               patch(p1, pc);
-
-               // general shift
-               p1 = gins(ASHRL, &cx, &ax);
-               p1->from.index = D_DX;  // double-width shift
-               p1->from.scale = 0;
-               gins(optoas(ORSH, hi1.type), &cx, &dx);
-               patch(p2, pc);
-               break;
-
-       case OXOR:
-       case OAND:
-       case OOR:
-               // make constant the right side (it usually is anyway).
-               if(lo1.op == OLITERAL) {
-                       nswap(&lo1, &lo2);
-                       nswap(&hi1, &hi2);
-               }
-               if(lo2.op == OLITERAL) {
-                       // special cases for constants.
-                       lv = mpgetfix(lo2.val.u.xval);
-                       hv = mpgetfix(hi2.val.u.xval);
-                       splitclean();   // right side
-                       split64(res, &lo2, &hi2);
-                       switch(n->op) {
-                       case OXOR:
-                               gmove(&lo1, &lo2);
-                               gmove(&hi1, &hi2);
-                               switch(lv) {
-                               case 0:
-                                       break;
-                               case 0xffffffffu:
-                                       gins(ANOTL, N, &lo2);
-                                       break;
-                               default:
-                                       gins(AXORL, ncon(lv), &lo2);
-                                       break;
-                               }
-                               switch(hv) {
-                               case 0:
-                                       break;
-                               case 0xffffffffu:
-                                       gins(ANOTL, N, &hi2);
-                                       break;
-                               default:
-                                       gins(AXORL, ncon(hv), &hi2);
-                                       break;
-                               }
-                               break;
-
-                       case OAND:
-                               switch(lv) {
-                               case 0:
-                                       gins(AMOVL, ncon(0), &lo2);
-                                       break;
-                               default:
-                                       gmove(&lo1, &lo2);
-                                       if(lv != 0xffffffffu)
-                                               gins(AANDL, ncon(lv), &lo2);
-                                       break;
-                               }
-                               switch(hv) {
-                               case 0:
-                                       gins(AMOVL, ncon(0), &hi2);
-                                       break;
-                               default:
-                                       gmove(&hi1, &hi2);
-                                       if(hv != 0xffffffffu)
-                                               gins(AANDL, ncon(hv), &hi2);
-                                       break;
-                               }
-                               break;
-
-                       case OOR:
-                               switch(lv) {
-                               case 0:
-                                       gmove(&lo1, &lo2);
-                                       break;
-                               case 0xffffffffu:
-                                       gins(AMOVL, ncon(0xffffffffu), &lo2);
-                                       break;
-                               default:
-                                       gmove(&lo1, &lo2);
-                                       gins(AORL, ncon(lv), &lo2);
-                                       break;
-                               }
-                               switch(hv) {
-                               case 0:
-                                       gmove(&hi1, &hi2);
-                                       break;
-                               case 0xffffffffu:
-                                       gins(AMOVL, ncon(0xffffffffu), &hi2);
-                                       break;
-                               default:
-                                       gmove(&hi1, &hi2);
-                                       gins(AORL, ncon(hv), &hi2);
-                                       break;
-                               }
-                               break;
-                       }
-                       splitclean();
-                       splitclean();
-                       goto out;
-               }
-               gins(AMOVL, &lo1, &ax);
-               gins(AMOVL, &hi1, &dx);
-               gins(optoas(n->op, lo1.type), &lo2, &ax);
-               gins(optoas(n->op, lo1.type), &hi2, &dx);
-               break;
-       }
-       if(is64(r->type))
-               splitclean();
-       splitclean();
-
-       split64(res, &lo1, &hi1);
-       gins(AMOVL, &ax, &lo1);
-       gins(AMOVL, &dx, &hi1);
-       splitclean();
-
-out:
-       if(r == &t2)
-               tempfree(&t2);
-       if(l == &t1)
-               tempfree(&t1);
-}
-
-/*
- * generate comparison of nl, nr, both 64-bit.
- * nl is memory; nr is constant or memory.
- */
-void
-cmp64(Node *nl, Node *nr, int op, Prog *to)
-{
-       Node lo1, hi1, lo2, hi2, rr;
-       Prog *br;
-       Type *t;
-
-       split64(nl, &lo1, &hi1);
-       split64(nr, &lo2, &hi2);
-
-       // compare most significant word;
-       // if they differ, we're done.
-       t = hi1.type;
-       if(nl->op == OLITERAL || nr->op == OLITERAL)
-               gins(ACMPL, &hi1, &hi2);
-       else {
-               regalloc(&rr, types[TINT32], N);
-               gins(AMOVL, &hi1, &rr);
-               gins(ACMPL, &rr, &hi2);
-               regfree(&rr);
-       }
-       br = P;
-       switch(op) {
-       default:
-               fatal("cmp64 %O %T", op, t);
-       case OEQ:
-               // cmp hi
-               // jne L
-               // cmp lo
-               // jeq to
-               // L:
-               br = gbranch(AJNE, T);
-               break;
-       case ONE:
-               // cmp hi
-               // jne to
-               // cmp lo
-               // jne to
-               patch(gbranch(AJNE, T), to);
-               break;
-       case OGE:
-       case OGT:
-               // cmp hi
-               // jgt to
-               // jlt L
-               // cmp lo
-               // jge to (or jgt to)
-               // L:
-               patch(gbranch(optoas(OGT, t), T), to);
-               br = gbranch(optoas(OLT, t), T);
-               break;
-       case OLE:
-       case OLT:
-               // cmp hi
-               // jlt to
-               // jgt L
-               // cmp lo
-               // jle to (or jlt to)
-               // L:
-               patch(gbranch(optoas(OLT, t), T), to);
-               br = gbranch(optoas(OGT, t), T);
-               break;
-       }
-
-       // compare least significant word
-       t = lo1.type;
-       if(nl->op == OLITERAL || nr->op == OLITERAL)
-               gins(ACMPL, &lo1, &lo2);
-       else {
-               regalloc(&rr, types[TINT32], N);
-               gins(AMOVL, &lo1, &rr);
-               gins(ACMPL, &rr, &lo2);
-               regfree(&rr);
-       }
-
-       // jump again
-       patch(gbranch(optoas(op, t), T), to);
-
-       // point first branch down here if appropriate
-       if(br != P)
-               patch(br, pc);
-
-       splitclean();
-       splitclean();
-}
-
diff --git a/src/cmd/8g/cgen64.c b/src/cmd/8g/cgen64.c
new file mode 100644 (file)
index 0000000..e723410
--- /dev/null
@@ -0,0 +1,512 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "gg.h"
+
+/*
+ * attempt to generate 64-bit
+ *     res = n
+ * return 1 on success, 0 if op not handled.
+ */
+void
+cgen64(Node *n, Node *res)
+{
+       Node t1, t2, ax, dx, cx, ex, fx, *l, *r;
+       Node lo1, lo2, lo3, hi1, hi2, hi3;
+       Prog *p1, *p2;
+       uint64 v;
+       uint32 lv, hv;
+
+       if(res->op != OINDREG && res->op != ONAME) {
+               dump("n", n);
+               dump("res", res);
+               fatal("cgen64 %O of %O", n->op, res->op);
+       }
+       switch(n->op) {
+       default:
+               fatal("cgen64 %O", n->op);
+
+       case OMINUS:
+               cgen(n->left, res);
+               split64(res, &lo1, &hi1);
+               gins(ANEGL, N, &lo1);
+               gins(AADCL, ncon(0), &hi1);
+               gins(ANEGL, N, &hi1);
+               splitclean();
+               return;
+
+       case OCOM:
+               cgen(n->left, res);
+               split64(res, &lo1, &hi1);
+               gins(ANOTL, N, &lo1);
+               gins(ANOTL, N, &hi1);
+               splitclean();
+               return;
+
+       case OADD:
+       case OSUB:
+       case OMUL:
+       case OLSH:
+       case ORSH:
+       case OAND:
+       case OOR:
+       case OXOR:
+               // binary operators.
+               // common setup below.
+               break;
+       }
+
+       l = n->left;
+       r = n->right;
+       if(!l->addable) {
+               tempalloc(&t1, l->type);
+               cgen(l, &t1);
+               l = &t1;
+       }
+       if(r != N && !r->addable) {
+               tempalloc(&t2, r->type);
+               cgen(r, &t2);
+               r = &t2;
+       }
+
+       nodreg(&ax, types[TINT32], D_AX);
+       nodreg(&cx, types[TINT32], D_CX);
+       nodreg(&dx, types[TINT32], D_DX);
+
+       // Setup for binary operation.
+       split64(l, &lo1, &hi1);
+       if(is64(r->type))
+               split64(r, &lo2, &hi2);
+
+       // Do op.  Leave result in DX:AX.
+       switch(n->op) {
+       case OADD:
+               // TODO: Constants
+               gins(AMOVL, &lo1, &ax);
+               gins(AMOVL, &hi1, &dx);
+               gins(AADDL, &lo2, &ax);
+               gins(AADCL, &hi2, &dx);
+               break;
+
+       case OSUB:
+               // TODO: Constants.
+               gins(AMOVL, &lo1, &ax);
+               gins(AMOVL, &hi1, &dx);
+               gins(ASUBL, &lo2, &ax);
+               gins(ASBBL, &hi2, &dx);
+               break;
+
+       case OMUL:
+               // let's call the next two EX and FX.
+               regalloc(&ex, types[TPTR32], N);
+               regalloc(&fx, types[TPTR32], N);
+
+               // load args into DX:AX and EX:CX.
+               gins(AMOVL, &lo1, &ax);
+               gins(AMOVL, &hi1, &dx);
+               gins(AMOVL, &lo2, &cx);
+               gins(AMOVL, &hi2, &ex);
+
+               // if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply.
+               gins(AMOVL, &dx, &fx);
+               gins(AORL, &ex, &fx);
+               p1 = gbranch(AJNE, T);
+               gins(AMULL, &cx, N);    // implicit &ax
+               p2 = gbranch(AJMP, T);
+               patch(p1, pc);
+
+               // full 64x64 -> 64, from 32x32 -> 64.
+               gins(AIMULL, &cx, &dx);
+               gins(AMOVL, &ax, &fx);
+               gins(AIMULL, &ex, &fx);
+               gins(AADDL, &dx, &fx);
+               gins(AMOVL, &cx, &dx);
+               gins(AMULL, &dx, N);    // implicit &ax
+               gins(AADDL, &fx, &dx);
+               patch(p2, pc);
+
+               regfree(&ex);
+               regfree(&fx);
+               break;
+
+       case OLSH:
+               if(r->op == OLITERAL) {
+                       v = mpgetfix(r->val.u.xval);
+                       if(v >= 64) {
+                               if(is64(r->type))
+                                       splitclean();
+                               splitclean();
+                               split64(res, &lo2, &hi2);
+                               gins(AMOVL, ncon(0), &lo2);
+                               gins(AMOVL, ncon(0), &hi2);
+                               splitclean();
+                               goto out;
+                       }
+                       if(v >= 32) {
+                               if(is64(r->type))
+                                       splitclean();
+                               split64(res, &lo2, &hi2);
+                               gmove(&lo1, &hi2);
+                               if(v > 32) {
+                                       gins(ASHLL, ncon(v - 32), &hi2);
+                               }
+                               gins(AMOVL, ncon(0), &lo2);
+                               splitclean();
+                               splitclean();
+                               goto out;
+                       }
+
+                       // general shift
+                       gins(AMOVL, &lo1, &ax);
+                       gins(AMOVL, &hi1, &dx);
+                       p1 = gins(ASHLL, ncon(v), &dx);
+                       p1->from.index = D_AX;  // double-width shift
+                       p1->from.scale = 0;
+                       gins(ASHLL, ncon(v), &ax);
+                       break;
+               }
+
+               // load value into DX:AX.
+               gins(AMOVL, &lo1, &ax);
+               gins(AMOVL, &hi1, &dx);
+
+               // load shift value into register.
+               // if high bits are set, zero value.
+               p1 = P;
+               if(is64(r->type)) {
+                       gins(ACMPL, &hi2, ncon(0));
+                       p1 = gbranch(AJNE, T);
+                       gins(AMOVL, &lo2, &cx);
+               } else
+                       gins(AMOVL, r, &cx);
+
+               // if shift count is >=64, zero value
+               gins(ACMPL, &cx, ncon(64));
+               p2 = gbranch(optoas(OLT, types[TUINT32]), T);
+               if(p1 != P)
+                       patch(p1, pc);
+               gins(AXORL, &dx, &dx);
+               gins(AXORL, &ax, &ax);
+               patch(p2, pc);
+
+               // if shift count is >= 32, zero low.
+               gins(ACMPL, &cx, ncon(32));
+               p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+               gins(AMOVL, &ax, &dx);
+               gins(ASHLL, &cx, &dx);  // SHLL only uses bottom 5 bits of count
+               gins(AXORL, &ax, &ax);
+               p2 = gbranch(AJMP, T);
+               patch(p1, pc);
+
+               // general shift
+               p1 = gins(ASHLL, &cx, &dx);
+               p1->from.index = D_AX;  // double-width shift
+               p1->from.scale = 0;
+               gins(ASHLL, &cx, &ax);
+               patch(p2, pc);
+               break;
+
+       case ORSH:
+               if(r->op == OLITERAL) {
+                       v = mpgetfix(r->val.u.xval);
+                       if(v >= 64) {
+                               if(is64(r->type))
+                                       splitclean();
+                               splitclean();
+                               split64(res, &lo2, &hi2);
+                               if(hi1.type->etype == TINT32) {
+                                       gmove(&hi1, &lo2);
+                                       gins(ASARL, ncon(31), &lo2);
+                                       gmove(&hi1, &hi2);
+                                       gins(ASARL, ncon(31), &hi2);
+                               } else {
+                                       gins(AMOVL, ncon(0), &lo2);
+                                       gins(AMOVL, ncon(0), &hi2);
+                               }
+                               splitclean();
+                               goto out;
+                       }
+                       if(v >= 32) {
+                               if(is64(r->type))
+                                       splitclean();
+                               split64(res, &lo2, &hi2);
+                               gmove(&hi1, &lo2);
+                               if(v > 32)
+                                       gins(optoas(ORSH, hi1.type), ncon(v-32), &lo2);
+                               if(hi1.type->etype == TINT32) {
+                                       gmove(&hi1, &hi2);
+                                       gins(ASARL, ncon(31), &hi2);
+                               } else
+                                       gins(AMOVL, ncon(0), &hi2);
+                               splitclean();
+                               splitclean();
+                               goto out;
+                       }
+
+                       // general shift
+                       gins(AMOVL, &lo1, &ax);
+                       gins(AMOVL, &hi1, &dx);
+                       p1 = gins(ASHRL, ncon(v), &ax);
+                       p1->from.index = D_DX;  // double-width shift
+                       p1->from.scale = 0;
+                       gins(optoas(ORSH, hi1.type), ncon(v), &dx);
+                       break;
+               }
+
+               // load value into DX:AX.
+               gins(AMOVL, &lo1, &ax);
+               gins(AMOVL, &hi1, &dx);
+
+               // load shift value into register.
+               // if high bits are set, zero value.
+               p1 = P;
+               if(is64(r->type)) {
+                       gins(ACMPL, &hi2, ncon(0));
+                       p1 = gbranch(AJNE, T);
+                       gins(AMOVL, &lo2, &cx);
+               } else
+                       gins(AMOVL, r, &cx);
+
+               // if shift count is >=64, zero or sign-extend value
+               gins(ACMPL, &cx, ncon(64));
+               p2 = gbranch(optoas(OLT, types[TUINT32]), T);
+               if(p1 != P)
+                       patch(p1, pc);
+               if(hi1.type->etype == TINT32) {
+                       gins(ASARL, ncon(31), &dx);
+                       gins(AMOVL, &dx, &ax);
+               } else {
+                       gins(AXORL, &dx, &dx);
+                       gins(AXORL, &ax, &ax);
+               }
+               patch(p2, pc);
+
+               // if shift count is >= 32, sign-extend hi.
+               gins(ACMPL, &cx, ncon(32));
+               p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+               gins(AMOVL, &dx, &ax);
+               if(hi1.type->etype == TINT32) {
+                       gins(ASARL, &cx, &ax);  // SARL only uses bottom 5 bits of count
+                       gins(ASARL, ncon(31), &dx);
+               } else {
+                       gins(ASHRL, &cx, &ax);
+                       gins(AXORL, &dx, &dx);
+               }
+               p2 = gbranch(AJMP, T);
+               patch(p1, pc);
+
+               // general shift
+               p1 = gins(ASHRL, &cx, &ax);
+               p1->from.index = D_DX;  // double-width shift
+               p1->from.scale = 0;
+               gins(optoas(ORSH, hi1.type), &cx, &dx);
+               patch(p2, pc);
+               break;
+
+       case OXOR:
+       case OAND:
+       case OOR:
+               // make constant the right side (it usually is anyway).
+               if(lo1.op == OLITERAL) {
+                       nswap(&lo1, &lo2);
+                       nswap(&hi1, &hi2);
+               }
+               if(lo2.op == OLITERAL) {
+                       // special cases for constants.
+                       lv = mpgetfix(lo2.val.u.xval);
+                       hv = mpgetfix(hi2.val.u.xval);
+                       splitclean();   // right side
+                       split64(res, &lo2, &hi2);
+                       switch(n->op) {
+                       case OXOR:
+                               gmove(&lo1, &lo2);
+                               gmove(&hi1, &hi2);
+                               switch(lv) {
+                               case 0:
+                                       break;
+                               case 0xffffffffu:
+                                       gins(ANOTL, N, &lo2);
+                                       break;
+                               default:
+                                       gins(AXORL, ncon(lv), &lo2);
+                                       break;
+                               }
+                               switch(hv) {
+                               case 0:
+                                       break;
+                               case 0xffffffffu:
+                                       gins(ANOTL, N, &hi2);
+                                       break;
+                               default:
+                                       gins(AXORL, ncon(hv), &hi2);
+                                       break;
+                               }
+                               break;
+
+                       case OAND:
+                               switch(lv) {
+                               case 0:
+                                       gins(AMOVL, ncon(0), &lo2);
+                                       break;
+                               default:
+                                       gmove(&lo1, &lo2);
+                                       if(lv != 0xffffffffu)
+                                               gins(AANDL, ncon(lv), &lo2);
+                                       break;
+                               }
+                               switch(hv) {
+                               case 0:
+                                       gins(AMOVL, ncon(0), &hi2);
+                                       break;
+                               default:
+                                       gmove(&hi1, &hi2);
+                                       if(hv != 0xffffffffu)
+                                               gins(AANDL, ncon(hv), &hi2);
+                                       break;
+                               }
+                               break;
+
+                       case OOR:
+                               switch(lv) {
+                               case 0:
+                                       gmove(&lo1, &lo2);
+                                       break;
+                               case 0xffffffffu:
+                                       gins(AMOVL, ncon(0xffffffffu), &lo2);
+                                       break;
+                               default:
+                                       gmove(&lo1, &lo2);
+                                       gins(AORL, ncon(lv), &lo2);
+                                       break;
+                               }
+                               switch(hv) {
+                               case 0:
+                                       gmove(&hi1, &hi2);
+                                       break;
+                               case 0xffffffffu:
+                                       gins(AMOVL, ncon(0xffffffffu), &hi2);
+                                       break;
+                               default:
+                                       gmove(&hi1, &hi2);
+                                       gins(AORL, ncon(hv), &hi2);
+                                       break;
+                               }
+                               break;
+                       }
+                       splitclean();
+                       splitclean();
+                       goto out;
+               }
+               gins(AMOVL, &lo1, &ax);
+               gins(AMOVL, &hi1, &dx);
+               gins(optoas(n->op, lo1.type), &lo2, &ax);
+               gins(optoas(n->op, lo1.type), &hi2, &dx);
+               break;
+       }
+       if(is64(r->type))
+               splitclean();
+       splitclean();
+
+       split64(res, &lo1, &hi1);
+       gins(AMOVL, &ax, &lo1);
+       gins(AMOVL, &dx, &hi1);
+       splitclean();
+
+out:
+       if(r == &t2)
+               tempfree(&t2);
+       if(l == &t1)
+               tempfree(&t1);
+}
+
+/*
+ * generate comparison of nl, nr, both 64-bit.
+ * nl is memory; nr is constant or memory.
+ */
+void
+cmp64(Node *nl, Node *nr, int op, Prog *to)
+{
+       Node lo1, hi1, lo2, hi2, rr;
+       Prog *br;
+       Type *t;
+
+       split64(nl, &lo1, &hi1);
+       split64(nr, &lo2, &hi2);
+
+       // compare most significant word;
+       // if they differ, we're done.
+       t = hi1.type;
+       if(nl->op == OLITERAL || nr->op == OLITERAL)
+               gins(ACMPL, &hi1, &hi2);
+       else {
+               regalloc(&rr, types[TINT32], N);
+               gins(AMOVL, &hi1, &rr);
+               gins(ACMPL, &rr, &hi2);
+               regfree(&rr);
+       }
+       br = P;
+       switch(op) {
+       default:
+               fatal("cmp64 %O %T", op, t);
+       case OEQ:
+               // cmp hi
+               // jne L
+               // cmp lo
+               // jeq to
+               // L:
+               br = gbranch(AJNE, T);
+               break;
+       case ONE:
+               // cmp hi
+               // jne to
+               // cmp lo
+               // jne to
+               patch(gbranch(AJNE, T), to);
+               break;
+       case OGE:
+       case OGT:
+               // cmp hi
+               // jgt to
+               // jlt L
+               // cmp lo
+               // jge to (or jgt to)
+               // L:
+               patch(gbranch(optoas(OGT, t), T), to);
+               br = gbranch(optoas(OLT, t), T);
+               break;
+       case OLE:
+       case OLT:
+               // cmp hi
+               // jlt to
+               // jgt L
+               // cmp lo
+               // jle to (or jlt to)
+               // L:
+               patch(gbranch(optoas(OLT, t), T), to);
+               br = gbranch(optoas(OGT, t), T);
+               break;
+       }
+
+       // compare least significant word
+       t = lo1.type;
+       if(nl->op == OLITERAL || nr->op == OLITERAL)
+               gins(ACMPL, &lo1, &lo2);
+       else {
+               regalloc(&rr, types[TINT32], N);
+               gins(AMOVL, &lo1, &rr);
+               gins(ACMPL, &rr, &lo2);
+               regfree(&rr);
+       }
+
+       // jump again
+       patch(gbranch(optoas(op, t), T), to);
+
+       // point first branch down here if appropriate
+       if(br != P)
+               patch(br, pc);
+
+       splitclean();
+       splitclean();
+}
+