diff options
Diffstat (limited to 'src/cmd/8c/cgen64.c')
-rw-r--r-- | src/cmd/8c/cgen64.c | 2741 |
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); + } + } +} |