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