blob: 3424f762c53a817e964e3a3db073bc5088d858b9 [file] [log] [blame]
// 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);
}
}
}