mirror of
https://github.com/golang/go
synced 2024-10-05 06:11:21 -06:00
dc9a3b2791
cc: same runtime: test cc alignment (required moving #define of offsetof to runtime.h) fix bug260 Fixes #482. Fixes #609. R=ken2, r CC=golang-dev https://golang.org/cl/3563042
2658 lines
45 KiB
C
2658 lines
45 KiB
C
// 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);
|
|
}
|
|
}
|
|
}
|