summaryrefslogtreecommitdiff
path: root/src/cmd/8c/cgen64.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/8c/cgen64.c')
-rw-r--r--src/cmd/8c/cgen64.c2741
1 files changed, 2741 insertions, 0 deletions
diff --git a/src/cmd/8c/cgen64.c b/src/cmd/8c/cgen64.c
new file mode 100644
index 000000000..75f87f91e
--- /dev/null
+++ b/src/cmd/8c/cgen64.c
@@ -0,0 +1,2741 @@
+// Inferno utils/8c/cgen64.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen64.c
+//
+// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
+// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
+// Portions Copyright © 1997-1999 Vita Nuova Limited
+// Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
+// Portions Copyright © 2004,2006 Bruce Ellis
+// Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
+// Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
+// Portions Copyright © 2009 The Go Authors. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+#include "gc.h"
+
+void
+zeroregm(Node *n)
+{
+ gins(AMOVL, nodconst(0), n);
+}
+
+/* do we need to load the address of a vlong? */
+int
+vaddr(Node *n, int a)
+{
+ switch(n->op) {
+ case ONAME:
+ if(a)
+ return 1;
+ return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC);
+
+ case OCONST:
+ case OREGISTER:
+ case OINDREG:
+ return 1;
+ }
+ return 0;
+}
+
+long
+hi64v(Node *n)
+{
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ return (long)(n->vconst) & ~0L;
+ else
+ return (long)((uvlong)n->vconst>>32) & ~0L;
+}
+
+long
+lo64v(Node *n)
+{
+ if(align(0, types[TCHAR], Aarg1)) /* isbigendian */
+ return (long)((uvlong)n->vconst>>32) & ~0L;
+ else
+ return (long)(n->vconst) & ~0L;
+}
+
+Node *
+hi64(Node *n)
+{
+ return nodconst(hi64v(n));
+}
+
+Node *
+lo64(Node *n)
+{
+ return nodconst(lo64v(n));
+}
+
+static Node *
+anonreg(void)
+{
+ Node *n;
+
+ n = new(OREGISTER, Z, Z);
+ n->reg = D_NONE;
+ n->type = types[TLONG];
+ return n;
+}
+
+static Node *
+regpair(Node *n, Node *t)
+{
+ Node *r;
+
+ if(n != Z && n->op == OREGPAIR)
+ return n;
+ r = new(OREGPAIR, anonreg(), anonreg());
+ if(n != Z)
+ r->type = n->type;
+ else
+ r->type = t->type;
+ return r;
+}
+
+static void
+evacaxdx(Node *r)
+{
+ Node nod1, nod2;
+
+ if(r->reg == D_AX || r->reg == D_DX) {
+ reg[D_AX]++;
+ reg[D_DX]++;
+ /*
+ * this is just an optim that should
+ * check for spill
+ */
+ r->type = types[TULONG];
+ regalloc(&nod1, r, Z);
+ nodreg(&nod2, Z, r->reg);
+ gins(AMOVL, &nod2, &nod1);
+ regfree(r);
+ r->reg = nod1.reg;
+ reg[D_AX]--;
+ reg[D_DX]--;
+ }
+}
+
+/* lazy instantiation of register pair */
+static int
+instpair(Node *n, Node *l)
+{
+ int r;
+
+ r = 0;
+ if(n->left->reg == D_NONE) {
+ if(l != Z) {
+ n->left->reg = l->reg;
+ r = 1;
+ }
+ else
+ regalloc(n->left, n->left, Z);
+ }
+ if(n->right->reg == D_NONE)
+ regalloc(n->right, n->right, Z);
+ return r;
+}
+
+static void
+zapreg(Node *n)
+{
+ if(n->reg != D_NONE) {
+ regfree(n);
+ n->reg = D_NONE;
+ }
+}
+
+static void
+freepair(Node *n)
+{
+ regfree(n->left);
+ regfree(n->right);
+}
+
+/* n is not OREGPAIR, nn is */
+void
+loadpair(Node *n, Node *nn)
+{
+ Node nod;
+
+ instpair(nn, Z);
+ if(n->op == OCONST) {
+ gins(AMOVL, lo64(n), nn->left);
+ n->xoffset += SZ_LONG;
+ gins(AMOVL, hi64(n), nn->right);
+ n->xoffset -= SZ_LONG;
+ return;
+ }
+ if(!vaddr(n, 0)) {
+ /* steal the right register for the laddr */
+ nod = regnode;
+ nod.reg = nn->right->reg;
+ lcgen(n, &nod);
+ n = &nod;
+ regind(n, n);
+ n->xoffset = 0;
+ }
+ gins(AMOVL, n, nn->left);
+ n->xoffset += SZ_LONG;
+ gins(AMOVL, n, nn->right);
+ n->xoffset -= SZ_LONG;
+}
+
+/* n is OREGPAIR, nn is not */
+static void
+storepair(Node *n, Node *nn, int f)
+{
+ Node nod;
+
+ if(!vaddr(nn, 0)) {
+ reglcgen(&nod, nn, Z);
+ nn = &nod;
+ }
+ gins(AMOVL, n->left, nn);
+ nn->xoffset += SZ_LONG;
+ gins(AMOVL, n->right, nn);
+ nn->xoffset -= SZ_LONG;
+ if(nn == &nod)
+ regfree(&nod);
+ if(f)
+ freepair(n);
+}
+
+/* generate a cast t from n to tt */
+static void
+cast(Node *n, Type *t, Node *nn)
+{
+ Node *r;
+
+ r = new(OCAST, n, Z);
+ r->type = t;
+ sugen(r, nn, 8);
+}
+
+static void
+swapregs(Node *a, Node *b)
+{
+ int t;
+
+ t = a->reg;
+ a->reg = b->reg;
+ b->reg = t;
+}
+
+static void
+swappairs(Node *a, Node *b)
+{
+ swapregs(a->left, b->left);
+ swapregs(a->right, b->right);
+}
+
+static int
+saveme(Node *n)
+{
+ int r;
+
+ r = n->reg;
+ return r >= D_AX && r <= D_DI;
+}
+
+static void
+saveit(Node *n, Node *t, Node *r)
+{
+ Node nod;
+
+ if(saveme(n)) {
+ t->reg = n->reg;
+ gins(AMOVL, t, r);
+ r->xoffset += SZ_LONG;
+ if(n->reg == D_AX) {
+ regalloc(&nod, n, Z);
+ regfree(n);
+ n->reg = nod.reg;
+ }
+ }
+}
+
+static void
+restoreit(Node *n, Node *t, Node *r)
+{
+ if(saveme(n)) {
+ t->reg = n->reg;
+ gins(AMOVL, r, t);
+ r->xoffset += SZ_LONG;
+ }
+}
+
+enum
+{
+/* 4 only, see WW */
+ WNONE = 0,
+ WCONST,
+ WADDR,
+ WHARD,
+};
+
+static int
+whatof(Node *n, int a)
+{
+ if(n->op == OCONST)
+ return WCONST;
+ return !vaddr(n, a) ? WHARD : WADDR;
+}
+
+/* can upgrade an extern to addr for AND */
+static int
+reduxv(Node *n)
+{
+ return lo64v(n) == 0 || hi64v(n) == 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;
+}
+
+/*
+ * for a func operand call it and then return
+ * the safe node
+ */
+static Node *
+vfunc(Node *n, Node *nn)
+{
+ Node *t;
+
+ if(n->op != OFUNC)
+ return n;
+ t = new(0, Z, Z);
+ if(nn == Z || nn == nodret)
+ nn = n;
+ regsalloc(t, nn);
+ sugen(n, t, 8);
+ return t;
+}
+
+static int
+forcereg(Node *d, int r, int o, Node *t)
+{
+ int a;
+
+ if(d->reg != D_NONE)
+ diag(Z, "force alloc");
+ d->reg = r;
+ a = 0;
+ if(reg[r]) {
+ reg[o]++;
+ regalloc(t, d, Z);
+ a = 1;
+ gins(AMOVL, d, t);
+ reg[o]--;
+ }
+ reg[r]++;
+ return a;
+}
+
+/* try to steal a reg */
+static int
+getreg(Node **np, Node *t, int r)
+{
+ Node *n, *p;
+
+ n = *np;
+ if(n->reg == r) {
+ p = new(0, Z, Z);
+ regalloc(p, n, Z);
+ gins(AMOVL, n, p);
+ *t = *n;
+ *np = p;
+ return 1;
+ }
+ return 0;
+}
+
+static Node *
+snarfreg(Node *n, Node *t, int r, Node *d, Node *c)
+{
+ if(n == Z || n->op != OREGPAIR || (!getreg(&n->left, t, r) && !getreg(&n->right, t, r))) {
+ if(nodreg(t, Z, r)) {
+ regalloc(c, d, Z);
+ gins(AMOVL, t, c);
+ reg[r]++;
+ return c;
+ }
+ reg[r]++;
+ }
+ return Z;
+}
+
+enum
+{
+ Vstart = OEND,
+
+ Vgo,
+ Vamv,
+ Vmv,
+ Vzero,
+ Vop,
+ Vopx,
+ Vins,
+ Vins0,
+ Vinsl,
+ Vinsr,
+ Vinsla,
+ Vinsra,
+ Vinsx,
+ Vmul,
+ Vshll,
+ VT,
+ VF,
+ V_l_lo_f,
+ V_l_hi_f,
+ V_l_lo_t,
+ V_l_hi_t,
+ V_l_lo_u,
+ V_l_hi_u,
+ V_r_lo_f,
+ V_r_hi_f,
+ V_r_lo_t,
+ V_r_hi_t,
+ V_r_lo_u,
+ V_r_hi_u,
+ Vspazz,
+ Vend,
+
+ V_T0,
+ V_T1,
+ V_F0,
+ V_F1,
+
+ V_a0,
+ V_a1,
+ V_f0,
+ V_f1,
+
+ V_p0,
+ V_p1,
+ V_p2,
+ V_p3,
+ V_p4,
+
+ V_s0,
+ V_s1,
+ V_s2,
+ V_s3,
+ V_s4,
+
+ C00,
+ C01,
+ C31,
+ C32,
+
+ O_l_lo,
+ O_l_hi,
+ O_r_lo,
+ O_r_hi,
+ O_t_lo,
+ O_t_hi,
+ O_l,
+ O_r,
+ O_l_rp,
+ O_r_rp,
+ O_t_rp,
+ O_r0,
+ O_r1,
+ O_Zop,
+
+ O_a0,
+ O_a1,
+
+ V_C0,
+ V_C1,
+
+ V_S0,
+ V_S1,
+
+ VOPS = 5,
+ VLEN = 5,
+ VARGS = 2,
+
+ S00 = 0,
+ Sc0,
+ Sc1,
+ Sc2,
+ Sac3,
+ Sac4,
+ S10,
+
+ SAgen = 0,
+ SAclo,
+ SAc32,
+ SAchi,
+ SAdgen,
+ SAdclo,
+ SAdc32,
+ SAdchi,
+
+ B0c = 0,
+ Bca,
+ Bac,
+
+ T0i = 0,
+ Tii,
+
+ Bop0 = 0,
+ Bop1,
+};
+
+/*
+ * _testv:
+ * CMPL lo,$0
+ * JNE true
+ * CMPL hi,$0
+ * JNE true
+ * GOTO false
+ * false:
+ * GOTO code
+ * true:
+ * GOTO patchme
+ * code:
+ */
+
+static uchar testi[][VLEN] =
+{
+ {Vop, ONE, O_l_lo, C00},
+ {V_s0, Vop, ONE, O_l_hi, C00},
+ {V_s1, Vgo, V_s2, Vgo, V_s3},
+ {VF, V_p0, V_p1, VT, V_p2},
+ {Vgo, V_p3},
+ {VT, V_p0, V_p1, VF, V_p2},
+ {Vend},
+};
+
+/* shift left general case */
+static uchar shll00[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vinsl, ASHLL, O_r, O_l_rp},
+ {Vins, ASHLL, O_r, O_l_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, ASHLL, O_r, O_l_lo},
+ {Vins, AMOVL, O_l_lo, O_l_hi},
+ {Vzero, O_l_lo, V_p0, Vend},
+};
+
+/* shift left rp, const < 32 */
+static uchar shllc0[][VLEN] =
+{
+ {Vinsl, ASHLL, O_r, O_l_rp},
+ {Vshll, O_r, O_l_lo, Vend},
+};
+
+/* shift left rp, const == 32 */
+static uchar shllc1[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_l_hi},
+ {Vzero, O_l_lo, Vend},
+};
+
+/* shift left rp, const > 32 */
+static uchar shllc2[][VLEN] =
+{
+ {Vshll, O_r, O_l_lo},
+ {Vins, AMOVL, O_l_lo, O_l_hi},
+ {Vzero, O_l_lo, Vend},
+};
+
+/* shift left addr, const == 32 */
+static uchar shllac3[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_t_lo, Vend},
+};
+
+/* shift left addr, const > 32 */
+static uchar shllac4[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vshll, O_r, O_t_hi},
+ {Vzero, O_t_lo, Vend},
+};
+
+/* shift left of constant */
+static uchar shll10[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsl, ASHLL, O_r, O_t_rp},
+ {Vins, ASHLL, O_r, O_t_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {V_l_lo_t, Vins, ASHLL, O_r, O_t_hi},
+ {Vzero, O_t_lo, V_p0, Vend},
+};
+
+static uchar (*shlltab[])[VLEN] =
+{
+ shll00,
+ shllc0,
+ shllc1,
+ shllc2,
+ shllac3,
+ shllac4,
+ shll10,
+};
+
+/* shift right general case */
+static uchar shrl00[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vinsr, ASHRL, O_r, O_l_rp},
+ {Vins, O_a0, O_r, O_l_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, O_a0, O_r, O_l_hi},
+ {Vins, AMOVL, O_l_hi, O_l_lo},
+ {V_T1, Vzero, O_l_hi},
+ {V_F1, Vins, ASARL, C31, O_l_hi},
+ {V_p0, Vend},
+};
+
+/* shift right rp, const < 32 */
+static uchar shrlc0[][VLEN] =
+{
+ {Vinsr, ASHRL, O_r, O_l_rp},
+ {Vins, O_a0, O_r, O_l_hi, Vend},
+};
+
+/* shift right rp, const == 32 */
+static uchar shrlc1[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_l_lo},
+ {V_T1, Vzero, O_l_hi},
+ {V_F1, Vins, ASARL, C31, O_l_hi},
+ {Vend},
+};
+
+/* shift right rp, const > 32 */
+static uchar shrlc2[][VLEN] =
+{
+ {Vins, O_a0, O_r, O_l_hi},
+ {Vins, AMOVL, O_l_hi, O_l_lo},
+ {V_T1, Vzero, O_l_hi},
+ {V_F1, Vins, ASARL, C31, O_l_hi},
+ {Vend},
+};
+
+/* shift right addr, const == 32 */
+static uchar shrlac3[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vend},
+};
+
+/* shift right addr, const > 32 */
+static uchar shrlac4[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {Vins, O_a0, O_r, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vend},
+};
+
+/* shift right of constant */
+static uchar shrl10[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsr, ASHRL, O_r, O_t_rp},
+ {Vins, O_a0, O_r, O_t_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_l_hi_t, Vins, O_a0, O_r, O_t_lo},
+ {V_l_hi_u, V_S1},
+ {V_T1, Vzero, O_t_hi, V_p0},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vend},
+};
+
+static uchar (*shrltab[])[VLEN] =
+{
+ shrl00,
+ shrlc0,
+ shrlc1,
+ shrlc2,
+ shrlac3,
+ shrlac4,
+ shrl10,
+};
+
+/* shift asop left general case */
+static uchar asshllgen[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsla, ASHLL, O_r, O_r0},
+ {Vins, ASHLL, O_r, O_r0},
+ {Vins, AMOVL, O_r1, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vzero, O_l_lo},
+ {Vins, ASHLL, O_r, O_r0},
+ {Vins, AMOVL, O_r0, O_l_hi, V_p0},
+ {V_f0, V_f1, Vend},
+};
+
+/* shift asop left, const < 32 */
+static uchar asshllclo[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsla, ASHLL, O_r, O_r0},
+ {Vshll, O_r, O_r0},
+ {Vins, AMOVL, O_r1, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_f0, V_f1, Vend},
+};
+
+/* shift asop left, const == 32 */
+static uchar asshllc32[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vzero, O_l_lo},
+ {Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop left, const > 32 */
+static uchar asshllchi[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vzero, O_l_lo},
+ {Vshll, O_r, O_r0},
+ {Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop dest left general case */
+static uchar asdshllgen[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsl, ASHLL, O_r, O_t_rp},
+ {Vins, ASHLL, O_r, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_l_lo},
+ {Vins, ASHLL, O_r, O_t_hi},
+ {Vzero, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
+ {Vend},
+};
+
+/* shift asop dest left, const < 32 */
+static uchar asdshllclo[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsl, ASHLL, O_r, O_t_rp},
+ {Vshll, O_r, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vend},
+};
+
+/* shift asop dest left, const == 32 */
+static uchar asdshllc32[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_t_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vend},
+};
+
+/* shift asop dest, const > 32 */
+static uchar asdshllchi[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_hi},
+ {Vzero, O_t_lo},
+ {Vshll, O_r, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+static uchar (*asshlltab[])[VLEN] =
+{
+ asshllgen,
+ asshllclo,
+ asshllc32,
+ asshllchi,
+ asdshllgen,
+ asdshllclo,
+ asdshllc32,
+ asdshllchi,
+};
+
+/* shift asop right general case */
+static uchar asshrlgen[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsra, ASHRL, O_r, O_r0},
+ {Vinsx, Bop0, O_r, O_r1},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {Vins, AMOVL, O_r1, O_l_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {Vinsx, Bop0, O_r, O_r0},
+ {V_T1, Vzero, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_F1, Vins, ASARL, C31, O_r0},
+ {V_F1, Vins, AMOVL, O_r0, O_l_hi},
+ {V_p0, V_f0, V_f1, Vend},
+};
+
+/* shift asop right, const < 32 */
+static uchar asshrlclo[][VLEN] =
+{
+ {V_a0, V_a1},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r1},
+ {Vinsra, ASHRL, O_r, O_r0},
+ {Vinsx, Bop0, O_r, O_r1},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {Vins, AMOVL, O_r1, O_l_hi},
+ {V_f0, V_f1, Vend},
+};
+
+/* shift asop right, const == 32 */
+static uchar asshrlc32[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {V_T1, Vzero, O_l_hi},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_F1, Vins, ASARL, C31, O_r0},
+ {V_F1, Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop right, const > 32 */
+static uchar asshrlchi[][VLEN] =
+{
+ {V_a0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {V_T1, Vzero, O_l_hi},
+ {Vinsx, Bop0, O_r, O_r0},
+ {Vins, AMOVL, O_r0, O_l_lo},
+ {V_F1, Vins, ASARL, C31, O_r0},
+ {V_F1, Vins, AMOVL, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* shift asop dest right general case */
+static uchar asdshrlgen[][VLEN] =
+{
+ {Vop, OGE, O_r, C32},
+ {V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsr, ASHRL, O_r, O_t_rp},
+ {Vinsx, Bop0, O_r, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi, Vgo},
+ {V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {Vinsx, Bop0, O_r, O_t_lo},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
+ {Vend},
+};
+
+/* shift asop dest right, const < 32 */
+static uchar asdshrlclo[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsr, ASHRL, O_r, O_t_rp},
+ {Vinsx, Bop0, O_r, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+/* shift asop dest right, const == 32 */
+static uchar asdshrlc32[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+/* shift asop dest, const > 32 */
+static uchar asdshrlchi[][VLEN] =
+{
+ {Vins, AMOVL, O_l_hi, O_t_lo},
+ {V_T1, Vzero, O_t_hi},
+ {Vinsx, Bop0, O_r, O_t_lo},
+ {V_T1, Vins, AMOVL, O_t_hi, O_l_hi},
+ {V_T1, Vins, AMOVL, O_t_lo, O_l_lo},
+ {V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
+ {V_F1, Vins, ASARL, C31, O_t_hi},
+ {V_F1, Vins, AMOVL, O_t_lo, O_l_lo},
+ {V_F1, Vins, AMOVL, O_t_hi, O_l_hi},
+ {Vend},
+};
+
+static uchar (*asshrltab[])[VLEN] =
+{
+ asshrlgen,
+ asshrlclo,
+ asshrlc32,
+ asshrlchi,
+ asdshrlgen,
+ asdshrlclo,
+ asdshrlc32,
+ asdshrlchi,
+};
+
+static uchar shrlargs[] = { ASHRL, 1 };
+static uchar sarlargs[] = { ASARL, 0 };
+
+/* ++ -- */
+static uchar incdec[][VLEN] =
+{
+ {Vinsx, Bop0, C01, O_l_lo},
+ {Vinsx, Bop1, C00, O_l_hi, Vend},
+};
+
+/* ++ -- *p */
+static uchar incdecpre[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop0, C01, O_t_lo},
+ {Vinsx, Bop1, C00, O_t_hi},
+ {Vins, AMOVL, O_t_lo, O_l_lo},
+ {Vins, AMOVL, O_t_hi, O_l_hi, Vend},
+};
+
+/* *p ++ -- */
+static uchar incdecpost[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop0, C01, O_l_lo},
+ {Vinsx, Bop1, C00, O_l_hi, Vend},
+};
+
+/* binop rp, rp */
+static uchar binop00[][VLEN] =
+{
+ {Vinsx, Bop0, O_r_lo, O_l_lo},
+ {Vinsx, Bop1, O_r_hi, O_l_hi, Vend},
+ {Vend},
+};
+
+/* binop rp, addr */
+static uchar binoptmp[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vinsx, Bop0, O_r0, O_l_lo},
+ {Vins, AMOVL, O_r_hi, O_r0},
+ {Vinsx, Bop1, O_r0, O_l_hi},
+ {V_f0, Vend},
+};
+
+/* binop t = *a op *b */
+static uchar binop11[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vinsx, Bop0, O_r_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop1, O_r_hi, O_t_hi, Vend},
+};
+
+/* binop t = rp +- c */
+static uchar add0c[][VLEN] =
+{
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
+ {V_r_lo_f, Vamv, Bop0, Bop1},
+ {Vinsx, Bop1, O_r_hi, O_l_hi},
+ {Vend},
+};
+
+/* binop t = rp & c */
+static uchar and0c[][VLEN] =
+{
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
+ {V_r_lo_f, Vins, AMOVL, C00, O_l_lo},
+ {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
+ {V_r_hi_f, Vins, AMOVL, C00, O_l_hi},
+ {Vend},
+};
+
+/* binop t = rp | c */
+static uchar or0c[][VLEN] =
+{
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
+ {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
+ {Vend},
+};
+
+/* binop t = c - rp */
+static uchar sub10[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vinsx, Bop0, O_r_lo, O_r0},
+ {Vins, AMOVL, O_l_hi, O_r_lo},
+ {Vinsx, Bop1, O_r_hi, O_r_lo},
+ {Vspazz, V_f0, Vend},
+};
+
+/* binop t = c + *b */
+static uchar addca[][VLEN] =
+{
+ {Vins, AMOVL, O_r_lo, O_t_lo},
+ {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
+ {V_l_lo_f, Vamv, Bop0, Bop1},
+ {Vins, AMOVL, O_r_hi, O_t_hi},
+ {Vinsx, Bop1, O_l_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = c & *b */
+static uchar andca[][VLEN] =
+{
+ {V_l_lo_t, Vins, AMOVL, O_r_lo, O_t_lo},
+ {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
+ {V_l_lo_f, Vzero, O_t_lo},
+ {V_l_hi_t, Vins, AMOVL, O_r_hi, O_t_hi},
+ {V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
+ {V_l_hi_f, Vzero, O_t_hi},
+ {Vend},
+};
+
+/* binop t = c | *b */
+static uchar orca[][VLEN] =
+{
+ {Vins, AMOVL, O_r_lo, O_t_lo},
+ {V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_r_hi, O_t_hi},
+ {V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = c - *b */
+static uchar subca[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop0, O_r_lo, O_t_lo},
+ {Vinsx, Bop1, O_r_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = *a +- c */
+static uchar addac[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
+ {V_r_lo_f, Vamv, Bop0, Bop1},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {Vinsx, Bop1, O_r_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = *a | c */
+static uchar orac[][VLEN] =
+{
+ {Vins, AMOVL, O_l_lo, O_t_lo},
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
+ {Vins, AMOVL, O_l_hi, O_t_hi},
+ {V_r_hi_t, Vinsx, Bop1, O_r_hi, O_t_hi},
+ {Vend},
+};
+
+/* binop t = *a & c */
+static uchar andac[][VLEN] =
+{
+ {V_r_lo_t, Vins, AMOVL, O_l_lo, O_t_lo},
+ {V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
+ {V_r_lo_f, Vzero, O_t_lo},
+ {V_r_hi_t, Vins, AMOVL, O_l_hi, O_t_hi},
+ {V_r_hi_t, Vinsx, Bop0, O_r_hi, O_t_hi},
+ {V_r_hi_f, Vzero, O_t_hi},
+ {Vend},
+};
+
+static uchar ADDargs[] = { AADDL, AADCL };
+static uchar ANDargs[] = { AANDL, AANDL };
+static uchar ORargs[] = { AORL, AORL };
+static uchar SUBargs[] = { ASUBL, ASBBL };
+static uchar XORargs[] = { AXORL, AXORL };
+
+static uchar (*ADDtab[])[VLEN] =
+{
+ add0c, addca, addac,
+};
+
+static uchar (*ANDtab[])[VLEN] =
+{
+ and0c, andca, andac,
+};
+
+static uchar (*ORtab[])[VLEN] =
+{
+ or0c, orca, orac,
+};
+
+static uchar (*SUBtab[])[VLEN] =
+{
+ add0c, subca, addac,
+};
+
+/* mul of const32 */
+static uchar mulc32[][VLEN] =
+{
+ {V_a0, Vop, ONE, O_l_hi, C00},
+ {V_s0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vins, AMULL, O_r0, O_Zop},
+ {Vgo, V_p0, V_s0},
+ {Vins, AMOVL, O_l_hi, O_r0},
+ {Vmul, O_r_lo, O_r0},
+ {Vins, AMOVL, O_r_lo, O_l_hi},
+ {Vins, AMULL, O_l_hi, O_Zop},
+ {Vins, AADDL, O_r0, O_l_hi},
+ {V_f0, V_p0, Vend},
+};
+
+/* mul of const64 */
+static uchar mulc64[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_r_hi, O_r0},
+ {Vop, OOR, O_l_hi, O_r0},
+ {Vop, ONE, O_r0, C00},
+ {V_s0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vins, AMULL, O_r0, O_Zop},
+ {Vgo, V_p0, V_s0},
+ {Vmul, O_r_lo, O_l_hi},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vmul, O_r_hi, O_r0},
+ {Vins, AADDL, O_l_hi, O_r0},
+ {Vins, AMOVL, O_r_lo, O_l_hi},
+ {Vins, AMULL, O_l_hi, O_Zop},
+ {Vins, AADDL, O_r0, O_l_hi},
+ {V_f0, V_p0, Vend},
+};
+
+/* mul general */
+static uchar mull[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_r_hi, O_r0},
+ {Vop, OOR, O_l_hi, O_r0},
+ {Vop, ONE, O_r0, C00},
+ {V_s0, Vins, AMOVL, O_r_lo, O_r0},
+ {Vins, AMULL, O_r0, O_Zop},
+ {Vgo, V_p0, V_s0},
+ {Vins, AIMULL, O_r_lo, O_l_hi},
+ {Vins, AMOVL, O_l_lo, O_r0},
+ {Vins, AIMULL, O_r_hi, O_r0},
+ {Vins, AADDL, O_l_hi, O_r0},
+ {Vins, AMOVL, O_r_lo, O_l_hi},
+ {Vins, AMULL, O_l_hi, O_Zop},
+ {Vins, AADDL, O_r0, O_l_hi},
+ {V_f0, V_p0, Vend},
+};
+
+/* cast rp l to rp t */
+static uchar castrp[][VLEN] =
+{
+ {Vmv, O_l, O_t_lo},
+ {VT, Vins, AMOVL, O_t_lo, O_t_hi},
+ {VT, Vins, ASARL, C31, O_t_hi},
+ {VF, Vzero, O_t_hi},
+ {Vend},
+};
+
+/* cast rp l to addr t */
+static uchar castrpa[][VLEN] =
+{
+ {VT, V_a0, Vmv, O_l, O_r0},
+ {VT, Vins, AMOVL, O_r0, O_t_lo},
+ {VT, Vins, ASARL, C31, O_r0},
+ {VT, Vins, AMOVL, O_r0, O_t_hi},
+ {VT, V_f0},
+ {VF, Vmv, O_l, O_t_lo},
+ {VF, Vzero, O_t_hi},
+ {Vend},
+};
+
+static uchar netab0i[][VLEN] =
+{
+ {Vop, ONE, O_l_lo, O_r_lo},
+ {V_s0, Vop, ONE, O_l_hi, O_r_hi},
+ {V_s1, Vgo, V_s2, Vgo, V_s3},
+ {VF, V_p0, V_p1, VT, V_p2},
+ {Vgo, V_p3},
+ {VT, V_p0, V_p1, VF, V_p2},
+ {Vend},
+};
+
+static uchar netabii[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_l_lo, O_r0},
+ {Vop, ONE, O_r0, O_r_lo},
+ {V_s0, Vins, AMOVL, O_l_hi, O_r0},
+ {Vop, ONE, O_r0, O_r_hi},
+ {V_s1, Vgo, V_s2, Vgo, V_s3},
+ {VF, V_p0, V_p1, VT, V_p2},
+ {Vgo, V_p3},
+ {VT, V_p0, V_p1, VF, V_p2},
+ {V_f0, Vend},
+};
+
+static uchar cmptab0i[][VLEN] =
+{
+ {Vopx, Bop0, O_l_hi, O_r_hi},
+ {V_s0, Vins0, AJNE},
+ {V_s1, Vopx, Bop1, O_l_lo, O_r_lo},
+ {V_s2, Vgo, V_s3, Vgo, V_s4},
+ {VT, V_p1, V_p3},
+ {VF, V_p0, V_p2},
+ {Vgo, V_p4},
+ {VT, V_p0, V_p2},
+ {VF, V_p1, V_p3},
+ {Vend},
+};
+
+static uchar cmptabii[][VLEN] =
+{
+ {V_a0, Vins, AMOVL, O_l_hi, O_r0},
+ {Vopx, Bop0, O_r0, O_r_hi},
+ {V_s0, Vins0, AJNE},
+ {V_s1, Vins, AMOVL, O_l_lo, O_r0},
+ {Vopx, Bop1, O_r0, O_r_lo},
+ {V_s2, Vgo, V_s3, Vgo, V_s4},
+ {VT, V_p1, V_p3},
+ {VF, V_p0, V_p2},
+ {Vgo, V_p4},
+ {VT, V_p0, V_p2},
+ {VF, V_p1, V_p3},
+ {V_f0, Vend},
+};
+
+static uchar (*NEtab[])[VLEN] =
+{
+ netab0i, netabii,
+};
+
+static uchar (*cmptab[])[VLEN] =
+{
+ cmptab0i, cmptabii,
+};
+
+static uchar GEargs[] = { OGT, OHS };
+static uchar GTargs[] = { OGT, OHI };
+static uchar HIargs[] = { OHI, OHI };
+static uchar HSargs[] = { OHI, OHS };
+
+/* Big Generator */
+static void
+biggen(Node *l, Node *r, Node *t, int true, uchar code[][VLEN], uchar *a)
+{
+ int i, j, g, oc, op, lo, ro, to, xo, *xp;
+ Type *lt;
+ Prog *pr[VOPS];
+ Node *ot, *tl, *tr, tmps[2];
+ uchar *c, (*cp)[VLEN], args[VARGS];
+
+ if(a != nil)
+ memmove(args, a, VARGS);
+//print("biggen %d %d %d\n", args[0], args[1], args[2]);
+//if(l) prtree(l, "l");
+//if(r) prtree(r, "r");
+//if(t) prtree(t, "t");
+ lo = ro = to = 0;
+ cp = code;
+
+ for (;;) {
+ c = *cp++;
+ g = 1;
+ i = 0;
+//print("code %d %d %d %d %d\n", c[0], c[1], c[2], c[3], c[4]);
+ for(;;) {
+ switch(op = c[i]) {
+ case Vgo:
+ if(g)
+ gbranch(OGOTO);
+ i++;
+ break;
+
+ case Vamv:
+ i += 3;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ if(g)
+ args[c[i - 1]] = args[c[i - 2]];
+ break;
+
+ case Vzero:
+ i += 2;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ j = i - 1;
+ goto op;
+
+ case Vspazz: // nasty hack to save a reg in SUB
+//print("spazz\n");
+ if(g) {
+//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
+ ot = r->right;
+ r->right = r->left;
+ tl = new(0, Z, Z);
+ *tl = tmps[0];
+ r->left = tl;
+ tmps[0] = *ot;
+//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
+ }
+ i++;
+ break;
+
+ case Vmv:
+ case Vmul:
+ case Vshll:
+ i += 3;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ j = i - 2;
+ goto op;
+
+ case Vins0:
+ i += 2;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ gins(c[i - 1], Z, Z);
+ break;
+
+ case Vop:
+ case Vopx:
+ case Vins:
+ case Vinsl:
+ case Vinsr:
+ case Vinsla:
+ case Vinsra:
+ case Vinsx:
+ i += 4;
+ if(i > VLEN) {
+ diag(l, "bad Vop");
+ return;
+ }
+ j = i - 2;
+ goto op;
+
+ op:
+ if(!g)
+ break;
+ tl = Z;
+ tr = Z;
+ for(; j < i; j++) {
+ switch(c[j]) {
+ case C00:
+ ot = nodconst(0);
+ break;
+ case C01:
+ ot = nodconst(1);
+ break;
+ case C31:
+ ot = nodconst(31);
+ break;
+ case C32:
+ ot = nodconst(32);
+ break;
+
+ case O_l:
+ case O_l_lo:
+ ot = l; xp = &lo; xo = 0;
+ goto op0;
+ case O_l_hi:
+ ot = l; xp = &lo; xo = SZ_LONG;
+ goto op0;
+ case O_r:
+ case O_r_lo:
+ ot = r; xp = &ro; xo = 0;
+ goto op0;
+ case O_r_hi:
+ ot = r; xp = &ro; xo = SZ_LONG;
+ goto op0;
+ case O_t_lo:
+ ot = t; xp = &to; xo = 0;
+ goto op0;
+ case O_t_hi:
+ ot = t; xp = &to; xo = SZ_LONG;
+ goto op0;
+ case O_l_rp:
+ ot = l;
+ break;
+ case O_r_rp:
+ ot = r;
+ break;
+ case O_t_rp:
+ ot = t;
+ break;
+ case O_r0:
+ case O_r1:
+ ot = &tmps[c[j] - O_r0];
+ break;
+ case O_Zop:
+ ot = Z;
+ break;
+
+ op0:
+ switch(ot->op) {
+ case OCONST:
+ if(xo)
+ ot = hi64(ot);
+ else
+ ot = lo64(ot);
+ break;
+ case OREGPAIR:
+ if(xo)
+ ot = ot->right;
+ else
+ ot = ot->left;
+ break;
+ case OREGISTER:
+ break;
+ default:
+ if(xo != *xp) {
+ ot->xoffset += xo - *xp;
+ *xp = xo;
+ }
+ }
+ break;
+
+ default:
+ diag(l, "bad V_lop");
+ return;
+ }
+ if(tl == nil)
+ tl = ot;
+ else
+ tr = ot;
+ }
+ if(op == Vzero) {
+ zeroregm(tl);
+ break;
+ }
+ oc = c[i - 3];
+ if(op == Vinsx || op == Vopx) {
+//print("%d -> %d\n", oc, args[oc]);
+ oc = args[oc];
+ }
+ else {
+ switch(oc) {
+ case O_a0:
+ case O_a1:
+ oc = args[oc - O_a0];
+ break;
+ }
+ }
+ switch(op) {
+ case Vmul:
+ mulgen(tr->type, tl, tr);
+ break;
+ case Vmv:
+ gmove(tl, tr);
+ break;
+ case Vshll:
+ shiftit(tr->type, tl, tr);
+ break;
+ case Vop:
+ case Vopx:
+ gopcode(oc, types[TULONG], tl, tr);
+ break;
+ case Vins:
+ case Vinsx:
+ gins(oc, tl, tr);
+ break;
+ case Vinsl:
+ gins(oc, tl, tr->right);
+ p->from.index = tr->left->reg;
+ break;
+ case Vinsr:
+ gins(oc, tl, tr->left);
+ p->from.index = tr->right->reg;
+ break;
+ case Vinsla:
+ gins(oc, tl, tr + 1);
+ p->from.index = tr->reg;
+ break;
+ case Vinsra:
+ gins(oc, tl, tr);
+ p->from.index = (tr + 1)->reg;
+ break;
+ }
+ break;
+
+ case VT:
+ g = true;
+ i++;
+ break;
+ case VF:
+ g = !true;
+ i++;
+ break;
+
+ case V_T0: case V_T1:
+ g = args[op - V_T0];
+ i++;
+ break;
+
+ case V_F0: case V_F1:
+ g = !args[op - V_F0];
+ i++;
+ break;
+
+ case V_C0: case V_C1:
+ if(g)
+ args[op - V_C0] = 0;
+ i++;
+ break;
+
+ case V_S0: case V_S1:
+ if(g)
+ args[op - V_S0] = 1;
+ i++;
+ break;
+
+ case V_l_lo_f:
+ g = lo64v(l) == 0;
+ i++;
+ break;
+ case V_l_hi_f:
+ g = hi64v(l) == 0;
+ i++;
+ break;
+ case V_l_lo_t:
+ g = lo64v(l) != 0;
+ i++;
+ break;
+ case V_l_hi_t:
+ g = hi64v(l) != 0;
+ i++;
+ break;
+ case V_l_lo_u:
+ g = lo64v(l) >= 0;
+ i++;
+ break;
+ case V_l_hi_u:
+ g = hi64v(l) >= 0;
+ i++;
+ break;
+ case V_r_lo_f:
+ g = lo64v(r) == 0;
+ i++;
+ break;
+ case V_r_hi_f:
+ g = hi64v(r) == 0;
+ i++;
+ break;
+ case V_r_lo_t:
+ g = lo64v(r) != 0;
+ i++;
+ break;
+ case V_r_hi_t:
+ g = hi64v(r) != 0;
+ i++;
+ break;
+ case V_r_lo_u:
+ g = lo64v(r) >= 0;
+ i++;
+ break;
+ case V_r_hi_u:
+ g = hi64v(r) >= 0;
+ i++;
+ break;
+
+ case Vend:
+ goto out;
+
+ case V_a0: case V_a1:
+ if(g) {
+ lt = l->type;
+ l->type = types[TULONG];
+ regalloc(&tmps[op - V_a0], l, Z);
+ l->type = lt;
+ }
+ i++;
+ break;
+
+ case V_f0: case V_f1:
+ if(g)
+ regfree(&tmps[op - V_f0]);
+ i++;
+ break;
+
+ case V_p0: case V_p1: case V_p2: case V_p3: case V_p4:
+ if(g)
+ patch(pr[op - V_p0], pc);
+ i++;
+ break;
+
+ case V_s0: case V_s1: case V_s2: case V_s3: case V_s4:
+ if(g)
+ pr[op - V_s0] = p;
+ i++;
+ break;
+
+ default:
+ diag(l, "bad biggen: %d", op);
+ return;
+ }
+ if(i == VLEN || c[i] == 0)
+ break;
+ }
+ }
+out:
+ if(lo)
+ l->xoffset -= lo;
+ if(ro)
+ r->xoffset -= ro;
+ if(to)
+ t->xoffset -= to;
+}
+
+int
+cgen64(Node *n, Node *nn)
+{
+ Type *dt;
+ uchar *args, (*cp)[VLEN], (**optab)[VLEN];
+ int li, ri, lri, dr, si, m, op, sh, cmp, true;
+ Node *c, *d, *l, *r, *t, *s, nod1, nod2, nod3, nod4, nod5;
+
+ if(debug['g']) {
+ prtree(nn, "cgen64 lhs");
+ prtree(n, "cgen64");
+ print("AX = %d\n", reg[D_AX]);
+ }
+ cmp = 0;
+ sh = 0;
+
+ switch(n->op) {
+ case ONEG:
+ d = regpair(nn, n);
+ sugen(n->left, d, 8);
+ gins(ANOTL, Z, d->right);
+ gins(ANEGL, Z, d->left);
+ gins(ASBBL, nodconst(-1), d->right);
+ break;
+
+ case OCOM:
+ if(!vaddr(n->left, 0) || !vaddr(nn, 0))
+ d = regpair(nn, n);
+ else
+ return 0;
+ sugen(n->left, d, 8);
+ gins(ANOTL, Z, d->left);
+ gins(ANOTL, Z, d->right);
+ break;
+
+ case OADD:
+ optab = ADDtab;
+ args = ADDargs;
+ goto twoop;
+ case OAND:
+ optab = ANDtab;
+ args = ANDargs;
+ goto twoop;
+ case OOR:
+ optab = ORtab;
+ args = ORargs;
+ goto twoop;
+ case OSUB:
+ optab = SUBtab;
+ args = SUBargs;
+ goto twoop;
+ case OXOR:
+ optab = ORtab;
+ args = XORargs;
+ goto twoop;
+ case OASHL:
+ sh = 1;
+ args = nil;
+ optab = shlltab;
+ goto twoop;
+ case OLSHR:
+ sh = 1;
+ args = shrlargs;
+ optab = shrltab;
+ goto twoop;
+ case OASHR:
+ sh = 1;
+ args = sarlargs;
+ optab = shrltab;
+ goto twoop;
+ case OEQ:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case ONE:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLE:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLT:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OGE:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OGT:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OHI:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OHS:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLO:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+ case OLS:
+ cmp = 1;
+ args = nil;
+ optab = nil;
+ goto twoop;
+
+twoop:
+ dr = nn != Z && nn->op == OREGPAIR;
+ l = vfunc(n->left, nn);
+ if(sh)
+ r = n->right;
+ else
+ r = vfunc(n->right, nn);
+
+ li = l->op == ONAME || l->op == OINDREG || l->op == OCONST;
+ ri = r->op == ONAME || r->op == OINDREG || r->op == OCONST;
+
+#define IMM(l, r) ((l) | ((r) << 1))
+
+ lri = IMM(li, ri);
+
+ /* find out what is so easy about some operands */
+ if(li)
+ li = whatof(l, sh | cmp);
+ if(ri)
+ ri = whatof(r, cmp);
+
+ if(sh)
+ goto shift;
+
+ if(cmp)
+ goto cmp;
+
+ /* evaluate hard subexps, stealing nn if possible. */
+ switch(lri) {
+ case IMM(0, 0):
+ bin00:
+ if(l->complex > r->complex) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ }
+ else {
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ }
+ break;
+ case IMM(0, 1):
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ break;
+ case IMM(1, 0):
+ if(n->op == OSUB && l->op == OCONST && hi64v(l) == 0) {
+ lri = IMM(0, 0);
+ goto bin00;
+ }
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ break;
+ case IMM(1, 1):
+ break;
+ }
+
+#define WW(l, r) ((l) | ((r) << 2))
+ d = Z;
+ dt = nn->type;
+ nn->type = types[TLONG];
+
+ switch(lri) {
+ case IMM(0, 0):
+ biggen(l, r, Z, 0, binop00, args);
+ break;
+ case IMM(0, 1):
+ switch(ri) {
+ case WNONE:
+ diag(r, "bad whatof\n");
+ break;
+ case WCONST:
+ biggen(l, r, Z, 0, optab[B0c], args);
+ break;
+ case WHARD:
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ /* fall thru */
+ case WADDR:
+ biggen(l, r, Z, 0, binoptmp, args);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+ break;
+ case IMM(1, 0):
+ if(n->op == OSUB) {
+ switch(li) {
+ case WNONE:
+ diag(l, "bad whatof\n");
+ break;
+ case WHARD:
+ reglcgen(&nod2, l, Z);
+ l = &nod2;
+ /* fall thru */
+ case WADDR:
+ case WCONST:
+ biggen(l, r, Z, 0, sub10, args);
+ break;
+ }
+ if(li == WHARD)
+ regfree(l);
+ }
+ else {
+ switch(li) {
+ case WNONE:
+ diag(l, "bad whatof\n");
+ break;
+ case WCONST:
+ biggen(r, l, Z, 0, optab[B0c], args);
+ break;
+ case WHARD:
+ reglcgen(&nod2, l, Z);
+ l = &nod2;
+ /* fall thru */
+ case WADDR:
+ biggen(r, l, Z, 0, binoptmp, args);
+ if(li == WHARD)
+ regfree(l);
+ break;
+ }
+ }
+ break;
+ case IMM(1, 1):
+ switch(WW(li, ri)) {
+ case WW(WCONST, WHARD):
+ if(r->op == ONAME && n->op == OAND && reduxv(l))
+ ri = WADDR;
+ break;
+ case WW(WHARD, WCONST):
+ if(l->op == ONAME && n->op == OAND && reduxv(r))
+ li = WADDR;
+ break;
+ }
+ if(li == WHARD) {
+ reglcgen(&nod3, l, Z);
+ l = &nod3;
+ }
+ if(ri == WHARD) {
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ }
+ d = regpair(nn, n);
+ instpair(d, Z);
+ switch(WW(li, ri)) {
+ case WW(WCONST, WADDR):
+ case WW(WCONST, WHARD):
+ biggen(l, r, d, 0, optab[Bca], args);
+ break;
+
+ case WW(WADDR, WCONST):
+ case WW(WHARD, WCONST):
+ biggen(l, r, d, 0, optab[Bac], args);
+ break;
+
+ case WW(WADDR, WADDR):
+ case WW(WADDR, WHARD):
+ case WW(WHARD, WADDR):
+ case WW(WHARD, WHARD):
+ biggen(l, r, d, 0, binop11, args);
+ break;
+
+ default:
+ diag(r, "bad whatof pair %d %d\n", li, ri);
+ break;
+ }
+ if(li == WHARD)
+ regfree(l);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+
+ nn->type = dt;
+
+ if(d != Z)
+ goto finished;
+
+ switch(lri) {
+ case IMM(0, 0):
+ freepair(r);
+ /* fall thru */;
+ case IMM(0, 1):
+ if(!dr)
+ storepair(l, nn, 1);
+ break;
+ case IMM(1, 0):
+ if(!dr)
+ storepair(r, nn, 1);
+ break;
+ case IMM(1, 1):
+ break;
+ }
+ return 1;
+
+ shift:
+ c = Z;
+
+ /* evaluate hard subexps, stealing nn if possible. */
+ /* must also secure CX. not as many optims as binop. */
+ switch(lri) {
+ case IMM(0, 0):
+ imm00:
+ if(l->complex + 1 > r->complex) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ t = &nod1;
+ c = snarfreg(l, t, D_CX, r, &nod2);
+ cgen(r, t);
+ r = t;
+ }
+ else {
+ t = &nod1;
+ c = snarfreg(nn, t, D_CX, r, &nod2);
+ cgen(r, t);
+ r = t;
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ }
+ break;
+ case IMM(0, 1):
+ imm01:
+ if(ri != WCONST) {
+ lri = IMM(0, 0);
+ goto imm00;
+ }
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ sugen(l, t, 8);
+ l = t;
+ break;
+ case IMM(1, 0):
+ imm10:
+ if(li != WCONST) {
+ lri = IMM(0, 0);
+ goto imm00;
+ }
+ t = &nod1;
+ c = snarfreg(nn, t, D_CX, r, &nod2);
+ cgen(r, t);
+ r = t;
+ break;
+ case IMM(1, 1):
+ if(ri != WCONST) {
+ lri = IMM(1, 0);
+ goto imm10;
+ }
+ if(li == WHARD) {
+ lri = IMM(0, 1);
+ goto imm01;
+ }
+ break;
+ }
+
+ d = Z;
+
+ switch(lri) {
+ case IMM(0, 0):
+ biggen(l, r, Z, 0, optab[S00], args);
+ break;
+ case IMM(0, 1):
+ switch(ri) {
+ case WNONE:
+ case WADDR:
+ case WHARD:
+ diag(r, "bad whatof\n");
+ break;
+ case WCONST:
+ m = r->vconst & 63;
+ s = nodconst(m);
+ if(m < 32)
+ cp = optab[Sc0];
+ else if(m == 32)
+ cp = optab[Sc1];
+ else
+ cp = optab[Sc2];
+ biggen(l, s, Z, 0, cp, args);
+ break;
+ }
+ break;
+ case IMM(1, 0):
+ /* left is const */
+ d = regpair(nn, n);
+ instpair(d, Z);
+ biggen(l, r, d, 0, optab[S10], args);
+ regfree(r);
+ break;
+ case IMM(1, 1):
+ d = regpair(nn, n);
+ instpair(d, Z);
+ switch(WW(li, ri)) {
+ case WW(WADDR, WCONST):
+ m = r->vconst & 63;
+ s = nodconst(m);
+ if(m < 32) {
+ loadpair(l, d);
+ l = d;
+ cp = optab[Sc0];
+ }
+ else if(m == 32)
+ cp = optab[Sac3];
+ else
+ cp = optab[Sac4];
+ biggen(l, s, d, 0, cp, args);
+ break;
+
+ default:
+ diag(r, "bad whatof pair %d %d\n", li, ri);
+ break;
+ }
+ break;
+ }
+
+ if(c != Z) {
+ gins(AMOVL, c, r);
+ regfree(c);
+ }
+
+ if(d != Z)
+ goto finished;
+
+ switch(lri) {
+ case IMM(0, 0):
+ regfree(r);
+ /* fall thru */
+ case IMM(0, 1):
+ if(!dr)
+ storepair(l, nn, 1);
+ break;
+ case IMM(1, 0):
+ regfree(r);
+ break;
+ case IMM(1, 1):
+ break;
+ }
+ return 1;
+
+ cmp:
+ op = n->op;
+ /* evaluate hard subexps */
+ switch(lri) {
+ case IMM(0, 0):
+ if(l->complex > r->complex) {
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ }
+ else {
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ }
+ break;
+ case IMM(1, 0):
+ t = r;
+ r = l;
+ l = t;
+ ri = li;
+ op = invrel[relindex(op)];
+ /* fall thru */
+ case IMM(0, 1):
+ t = regpair(Z, l);
+ sugen(l, t, 8);
+ l = t;
+ break;
+ case IMM(1, 1):
+ break;
+ }
+
+ true = 1;
+ optab = cmptab;
+ switch(op) {
+ case OEQ:
+ optab = NEtab;
+ true = 0;
+ break;
+ case ONE:
+ optab = NEtab;
+ break;
+ case OLE:
+ args = GTargs;
+ true = 0;
+ break;
+ case OGT:
+ args = GTargs;
+ break;
+ case OLS:
+ args = HIargs;
+ true = 0;
+ break;
+ case OHI:
+ args = HIargs;
+ break;
+ case OLT:
+ args = GEargs;
+ true = 0;
+ break;
+ case OGE:
+ args = GEargs;
+ break;
+ case OLO:
+ args = HSargs;
+ true = 0;
+ break;
+ case OHS:
+ args = HSargs;
+ break;
+ default:
+ diag(n, "bad cmp\n");
+ SET(optab);
+ }
+
+ switch(lri) {
+ case IMM(0, 0):
+ biggen(l, r, Z, true, optab[T0i], args);
+ break;
+ case IMM(0, 1):
+ case IMM(1, 0):
+ switch(ri) {
+ case WNONE:
+ diag(l, "bad whatof\n");
+ break;
+ case WCONST:
+ biggen(l, r, Z, true, optab[T0i], args);
+ break;
+ case WHARD:
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ /* fall thru */
+ case WADDR:
+ biggen(l, r, Z, true, optab[T0i], args);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+ break;
+ case IMM(1, 1):
+ if(li == WHARD) {
+ reglcgen(&nod3, l, Z);
+ l = &nod3;
+ }
+ if(ri == WHARD) {
+ reglcgen(&nod2, r, Z);
+ r = &nod2;
+ }
+ biggen(l, r, Z, true, optab[Tii], args);
+ if(li == WHARD)
+ regfree(l);
+ if(ri == WHARD)
+ regfree(r);
+ break;
+ }
+
+ switch(lri) {
+ case IMM(0, 0):
+ freepair(r);
+ /* fall thru */;
+ case IMM(0, 1):
+ case IMM(1, 0):
+ freepair(l);
+ break;
+ case IMM(1, 1):
+ break;
+ }
+ return 1;
+
+ case OASMUL:
+ case OASLMUL:
+ m = 0;
+ goto mulop;
+
+ case OMUL:
+ case OLMUL:
+ m = 1;
+ goto mulop;
+
+ mulop:
+ dr = nn != Z && nn->op == OREGPAIR;
+ l = vfunc(n->left, nn);
+ r = vfunc(n->right, nn);
+ if(r->op != OCONST) {
+ if(l->complex > r->complex) {
+ if(m) {
+ t = l;
+ l = r;
+ r = t;
+ }
+ else if(!vaddr(l, 1)) {
+ reglcgen(&nod5, l, Z);
+ l = &nod5;
+ evacaxdx(l);
+ }
+ }
+ t = regpair(Z, n);
+ sugen(r, t, 8);
+ r = t;
+ evacaxdx(r->left);
+ evacaxdx(r->right);
+ if(l->complex <= r->complex && !m && !vaddr(l, 1)) {
+ reglcgen(&nod5, l, Z);
+ l = &nod5;
+ evacaxdx(l);
+ }
+ }
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, n);
+ c = Z;
+ d = Z;
+ if(!nodreg(&nod1, t->left, D_AX)) {
+ if(t->left->reg != D_AX){
+ t->left->reg = D_AX;
+ reg[D_AX]++;
+ }else if(reg[D_AX] == 0)
+ fatal(Z, "vlong mul AX botch");
+ }
+ if(!nodreg(&nod2, t->right, D_DX)) {
+ if(t->right->reg != D_DX){
+ t->right->reg = D_DX;
+ reg[D_DX]++;
+ }else if(reg[D_DX] == 0)
+ fatal(Z, "vlong mul DX botch");
+ }
+ if(m)
+ sugen(l, t, 8);
+ else
+ loadpair(l, t);
+ if(t->left->reg != D_AX) {
+ c = &nod3;
+ regsalloc(c, t->left);
+ gmove(&nod1, c);
+ gmove(t->left, &nod1);
+ zapreg(t->left);
+ }
+ if(t->right->reg != D_DX) {
+ d = &nod4;
+ regsalloc(d, t->right);
+ gmove(&nod2, d);
+ gmove(t->right, &nod2);
+ zapreg(t->right);
+ }
+ if(c != Z || d != Z) {
+ s = regpair(Z, n);
+ s->left = &nod1;
+ s->right = &nod2;
+ }
+ else
+ s = t;
+ if(r->op == OCONST) {
+ if(hi64v(r) == 0)
+ biggen(s, r, Z, 0, mulc32, nil);
+ else
+ biggen(s, r, Z, 0, mulc64, nil);
+ }
+ else
+ biggen(s, r, Z, 0, mull, nil);
+ instpair(t, Z);
+ if(c != Z) {
+ gmove(&nod1, t->left);
+ gmove(&nod3, &nod1);
+ }
+ if(d != Z) {
+ gmove(&nod2, t->right);
+ gmove(&nod4, &nod2);
+ }
+ if(r->op == OREGPAIR)
+ freepair(r);
+ if(!m)
+ storepair(t, l, 0);
+ if(l == &nod5)
+ regfree(l);
+ if(!dr) {
+ if(nn != Z)
+ storepair(t, nn, 1);
+ else
+ freepair(t);
+ }
+ return 1;
+
+ case OASADD:
+ args = ADDargs;
+ goto vasop;
+ case OASAND:
+ args = ANDargs;
+ goto vasop;
+ case OASOR:
+ args = ORargs;
+ goto vasop;
+ case OASSUB:
+ args = SUBargs;
+ goto vasop;
+ case OASXOR:
+ args = XORargs;
+ goto vasop;
+
+ vasop:
+ l = n->left;
+ r = n->right;
+ dr = nn != Z && nn->op == OREGPAIR;
+ m = 0;
+ if(l->complex > r->complex) {
+ if(!vaddr(l, 1)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ m = 1;
+ }
+ }
+ else {
+ if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
+ if(dr)
+ t = nn;
+ else
+ t = regpair(Z, r);
+ sugen(r, t, 8);
+ r = t;
+ m = 1;
+ }
+ if(!vaddr(l, 1)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ }
+ if(nn != Z) {
+ if(n->op == OASSUB)
+ biggen(l, r, Z, 0, sub10, args);
+ else
+ biggen(r, l, Z, 0, binoptmp, args);
+ storepair(r, l, 0);
+ }
+ else {
+ if(m)
+ biggen(l, r, Z, 0, binop00, args);
+ else
+ biggen(l, r, Z, 0, binoptmp, args);
+ }
+ if(l == &nod1)
+ regfree(&nod1);
+ if(m) {
+ if(nn == Z)
+ freepair(r);
+ else if(!dr)
+ storepair(r, nn, 1);
+ }
+ return 1;
+
+ case OASASHL:
+ args = nil;
+ optab = asshlltab;
+ goto assh;
+ case OASLSHR:
+ args = shrlargs;
+ optab = asshrltab;
+ goto assh;
+ case OASASHR:
+ args = sarlargs;
+ optab = asshrltab;
+ goto assh;
+
+ assh:
+ c = Z;
+ l = n->left;
+ r = n->right;
+ if(r->op == OCONST) {
+ m = r->vconst & 63;
+ if(m < 32)
+ m = SAclo;
+ else if(m == 32)
+ m = SAc32;
+ else
+ m = SAchi;
+ }
+ else
+ m = SAgen;
+ if(l->complex > r->complex) {
+ if(!vaddr(l, 0)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ if(m == SAgen) {
+ t = &nod2;
+ if(l->reg == D_CX) {
+ regalloc(t, r, Z);
+ gmove(l, t);
+ l->reg = t->reg;
+ t->reg = D_CX;
+ }
+ else
+ c = snarfreg(nn, t, D_CX, r, &nod3);
+ cgen(r, t);
+ r = t;
+ }
+ }
+ else {
+ if(m == SAgen) {
+ t = &nod2;
+ c = snarfreg(nn, t, D_CX, r, &nod3);
+ cgen(r, t);
+ r = t;
+ }
+ if(!vaddr(l, 0)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+ }
+
+ if(nn != Z) {
+ m += SAdgen - SAgen;
+ d = regpair(nn, n);
+ instpair(d, Z);
+ biggen(l, r, d, 0, optab[m], args);
+ if(l == &nod1) {
+ regfree(&nod1);
+ l = Z;
+ }
+ if(r == &nod2 && c == Z) {
+ regfree(&nod2);
+ r = Z;
+ }
+ if(d != nn)
+ storepair(d, nn, 1);
+ }
+ else
+ biggen(l, r, Z, 0, optab[m], args);
+
+ if(c != Z) {
+ gins(AMOVL, c, r);
+ regfree(c);
+ }
+ if(l == &nod1)
+ regfree(&nod1);
+ if(r == &nod2)
+ regfree(&nod2);
+ return 1;
+
+ case OPOSTINC:
+ args = ADDargs;
+ cp = incdecpost;
+ goto vinc;
+ case OPOSTDEC:
+ args = SUBargs;
+ cp = incdecpost;
+ goto vinc;
+ case OPREINC:
+ args = ADDargs;
+ cp = incdecpre;
+ goto vinc;
+ case OPREDEC:
+ args = SUBargs;
+ cp = incdecpre;
+ goto vinc;
+
+ vinc:
+ l = n->left;
+ if(!vaddr(l, 1)) {
+ reglcgen(&nod1, l, Z);
+ l = &nod1;
+ }
+
+ if(nn != Z) {
+ d = regpair(nn, n);
+ instpair(d, Z);
+ biggen(l, Z, d, 0, cp, args);
+ if(l == &nod1) {
+ regfree(&nod1);
+ l = Z;
+ }
+ if(d != nn)
+ storepair(d, nn, 1);
+ }
+ else
+ biggen(l, Z, Z, 0, incdec, args);
+
+ if(l == &nod1)
+ regfree(&nod1);
+ return 1;
+
+ case OCAST:
+ l = n->left;
+ if(typev[l->type->etype]) {
+ if(!vaddr(l, 1)) {
+ if(l->complex + 1 > nn->complex) {
+ d = regpair(Z, l);
+ sugen(l, d, 8);
+ if(!vaddr(nn, 1)) {
+ reglcgen(&nod1, nn, Z);
+ r = &nod1;
+ }
+ else
+ r = nn;
+ }
+ else {
+ if(!vaddr(nn, 1)) {
+ reglcgen(&nod1, nn, Z);
+ r = &nod1;
+ }
+ else
+ r = nn;
+ d = regpair(Z, l);
+ sugen(l, d, 8);
+ }
+// d->left->type = r->type;
+ d->left->type = types[TLONG];
+ gmove(d->left, r);
+ freepair(d);
+ }
+ else {
+ if(nn->op != OREGISTER && !vaddr(nn, 1)) {
+ reglcgen(&nod1, nn, Z);
+ r = &nod1;
+ }
+ else
+ r = nn;
+// l->type = r->type;
+ l->type = types[TLONG];
+ gmove(l, r);
+ }
+ if(r != nn)
+ regfree(r);
+ }
+ else {
+ if(typeu[l->type->etype] || cond(l->op))
+ si = TUNSIGNED;
+ else
+ si = TSIGNED;
+ regalloc(&nod1, l, Z);
+ cgen(l, &nod1);
+ if(nn->op == OREGPAIR) {
+ m = instpair(nn, &nod1);
+ biggen(&nod1, Z, nn, si == TSIGNED, castrp, nil);
+ }
+ else {
+ m = 0;
+ if(!vaddr(nn, si != TSIGNED)) {
+ dt = nn->type;
+ nn->type = types[TLONG];
+ reglcgen(&nod2, nn, Z);
+ nn->type = dt;
+ nn = &nod2;
+ }
+ dt = nn->type;
+ nn->type = types[TLONG];
+ biggen(&nod1, Z, nn, si == TSIGNED, castrpa, nil);
+ nn->type = dt;
+ if(nn == &nod2)
+ regfree(&nod2);
+ }
+ if(!m)
+ regfree(&nod1);
+ }
+ return 1;
+
+ default:
+ if(n->op == OREGPAIR) {
+ storepair(n, nn, 1);
+ return 1;
+ }
+ if(nn->op == OREGPAIR) {
+ loadpair(n, nn);
+ return 1;
+ }
+ return 0;
+ }
+finished:
+ if(d != nn)
+ storepair(d, nn, 1);
+ return 1;
+}
+
+void
+testv(Node *n, int true)
+{
+ Type *t;
+ Node *nn, nod;
+
+ switch(n->op) {
+ case OINDREG:
+ case ONAME:
+ biggen(n, Z, Z, true, testi, nil);
+ break;
+
+ default:
+ n = vfunc(n, n);
+ if(n->addable >= INDEXED) {
+ t = n->type;
+ n->type = types[TLONG];
+ reglcgen(&nod, n, Z);
+ n->type = t;
+ n = &nod;
+ biggen(n, Z, Z, true, testi, nil);
+ if(n == &nod)
+ regfree(n);
+ }
+ else {
+ nn = regpair(Z, n);
+ sugen(n, nn, 8);
+ biggen(nn, Z, Z, true, testi, nil);
+ freepair(nn);
+ }
+ }
+}