root/src/cmd/8c/cgen64.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zeroregm
  2. vaddr
  3. hi64v
  4. lo64v
  5. hi64
  6. lo64
  7. anonreg
  8. regpair
  9. evacaxdx
  10. instpair
  11. zapreg
  12. freepair
  13. loadpair
  14. storepair
  15. whatof
  16. reduxv
  17. cond
  18. vfunc
  19. getreg
  20. snarfreg
  21. biggen
  22. cgen64
  23. testv

// 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;
}

int32
hi64v(Node *n)
{
        if(align(0, types[TCHAR], Aarg1, nil))  /* isbigendian */
                return (int32)(n->vconst) & ~0L;
        else
                return (int32)((uvlong)n->vconst>>32) & ~0L;
}

int32
lo64v(Node *n)
{
        if(align(0, types[TCHAR], Aarg1, nil))  /* isbigendian */
                return (int32)((uvlong)n->vconst>>32) & ~0L;
        else
                return (int32)(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);
}

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;
}

/* 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);
                }
        }
}

/* [<][>][^][v][top][bottom][index][help] */