// Inferno utils/8c/txt.c
// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.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
ginit(void)
{
int i;
Type *t;
thechar = '8';
thestring = "386";
exregoffset = 0;
exfregoffset = 0;
listinit();
nstring = 0;
mnstring = 0;
nrathole = 0;
pc = 0;
breakpc = -1;
continpc = -1;
cases = C;
firstp = P;
lastp = P;
tfield = types[TLONG];
zprog.link = P;
zprog.as = AGOK;
zprog.from.type = D_NONE;
zprog.from.index = D_NONE;
zprog.from.scale = 0;
zprog.to = zprog.from;
regnode.op = OREGISTER;
regnode.class = CEXREG;
regnode.reg = REGTMP;
regnode.complex = 0;
regnode.addable = 11;
regnode.type = types[TLONG];
fregnode0 = regnode;
fregnode0.reg = D_F0;
fregnode0.type = types[TDOUBLE];
fregnode1 = fregnode0;
fregnode1.reg = D_F0+1;
constnode.op = OCONST;
constnode.class = CXXX;
constnode.complex = 0;
constnode.addable = 20;
constnode.type = types[TLONG];
fconstnode.op = OCONST;
fconstnode.class = CXXX;
fconstnode.complex = 0;
fconstnode.addable = 20;
fconstnode.type = types[TDOUBLE];
nodsafe = new(ONAME, Z, Z);
nodsafe->sym = slookup(".safe");
nodsafe->type = types[TINT];
nodsafe->etype = types[TINT]->etype;
nodsafe->class = CAUTO;
complex(nodsafe);
t = typ(TARRAY, types[TCHAR]);
symrathole = slookup(".rathole");
symrathole->class = CGLOBL;
symrathole->type = t;
nodrat = new(ONAME, Z, Z);
nodrat->sym = symrathole;
nodrat->type = types[TIND];
nodrat->etype = TVOID;
nodrat->class = CGLOBL;
complex(nodrat);
nodrat->type = t;
nodret = new(ONAME, Z, Z);
nodret->sym = slookup(".ret");
nodret->type = types[TIND];
nodret->etype = TIND;
nodret->class = CPARAM;
nodret = new(OIND, nodret, Z);
complex(nodret);
com64init();
for(i=0; i<nelem(reg); i++) {
reg[i] = 1;
if(i >= D_AX && i <= D_DI && i != D_SP)
reg[i] = 0;
}
}
void
gclean(void)
{
int i;
Sym *s;
reg[D_SP]--;
for(i=D_AX; i<=D_DI; i++)
if(reg[i])
diag(Z, "reg %R left allocated", i);
while(mnstring)
outstring("", 1L);
symstring->type->width = nstring;
symrathole->type->width = nrathole;
for(i=0; i<NHASH; i++)
for(s = hash[i]; s != S; s = s->link) {
if(s->type == T)
continue;
if(s->type->width == 0)
continue;
if(s->class != CGLOBL && s->class != CSTATIC)
continue;
if(s->type == types[TENUM])
continue;
gpseudo(AGLOBL, s, nodconst(s->type->width));
}
nextpc();
p->as = AEND;
outcode();
}
void
nextpc(void)
{
p = alloc(sizeof(*p));
*p = zprog;
p->lineno = nearln;
pc++;
if(firstp == P) {
firstp = p;
lastp = p;
return;
}
lastp->link = p;
lastp = p;
}
void
gargs(Node *n, Node *tn1, Node *tn2)
{
int32 regs;
Node fnxargs[20], *fnxp;
regs = cursafe;
fnxp = fnxargs;
garg1(n, tn1, tn2, 0, &fnxp); /* compile fns to temps */
curarg = 0;
fnxp = fnxargs;
garg1(n, tn1, tn2, 1, &fnxp); /* compile normal args and temps */
cursafe = regs;
}
int nareg(void)
{
int i, n;
n = 0;
for(i=D_AX; i<=D_DI; i++)
if(reg[i] == 0)
n++;
return n;
}
void
garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
{
Node nod;
if(n == Z)
return;
if(n->op == OLIST) {
garg1(n->left, tn1, tn2, f, fnxp);
garg1(n->right, tn1, tn2, f, fnxp);
return;
}
if(f == 0) {
if(n->complex >= FNX) {
regsalloc(*fnxp, n);
nod = znode;
nod.op = OAS;
nod.left = *fnxp;
nod.right = n;
nod.type = n->type;
cgen(&nod, Z);
(*fnxp)++;
}
return;
}
if(typesu[n->type->etype] || typev[n->type->etype]) {
regaalloc(tn2, n);
if(n->complex >= FNX) {
sugen(*fnxp, tn2, n->type->width);
(*fnxp)++;
} else
sugen(n, tn2, n->type->width);
return;
}
if(REGARG >= 0 && curarg == 0 && typeilp[n->type->etype]) {
regaalloc1(tn1, n);
if(n->complex >= FNX) {
cgen(*fnxp, tn1);
(*fnxp)++;
} else
cgen(n, tn1);
return;
}
if(vconst(n) == 0) {
regaalloc(tn2, n);
gmove(n, tn2);
return;
}
regalloc(tn1, n, Z);
if(n->complex >= FNX) {
cgen(*fnxp, tn1);
(*fnxp)++;
} else
cgen(n, tn1);
regaalloc(tn2, n);
gmove(tn1, tn2);
regfree(tn1);
}
Node*
nodconst(int32 v)
{
constnode.vconst = v;
return &constnode;
}
Node*
nodfconst(double d)
{
fconstnode.fconst = d;
return &fconstnode;
}
int
isreg(Node *n, int r)
{
if(n->op == OREGISTER)
if(n->reg == r)
return 1;
return 0;
}
int
nodreg(Node *n, Node *nn, int r)
{
*n = regnode;
n->reg = r;
if(reg[r] == 0)
return 0;
if(nn != Z) {
n->type = nn->type;
n->lineno = nn->lineno;
if(nn->op == OREGISTER)
if(nn->reg == r)
return 0;
}
return 1;
}
void
regret(Node *n, Node *nn)
{
int r;
r = REGRET;
if(typefd[nn->type->etype])
r = FREGRET;
nodreg(n, nn, r);
reg[r]++;
}
void
regalloc(Node *n, Node *tn, Node *o)
{
int i;
switch(tn->type->etype) {
case TCHAR:
case TUCHAR:
case TSHORT:
case TUSHORT:
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
if(o != Z && o->op == OREGISTER) {
i = o->reg;
if(i >= D_AX && i <= D_DI)
goto out;
}
for(i=D_AX; i<=D_DI; i++)
if(reg[i] == 0)
goto out;
diag(tn, "out of fixed registers");
goto err;
case TFLOAT:
case TDOUBLE:
case TVLONG:
i = D_F0;
goto out;
}
diag(tn, "unknown type in regalloc: %T", tn->type);
err:
i = 0;
out:
if(i)
reg[i]++;
nodreg(n, tn, i);
}
void
regialloc(Node *n, Node *tn, Node *o)
{
Node nod;
nod = *tn;
nod.type = types[TIND];
regalloc(n, &nod, o);
}
void
regfree(Node *n)
{
int i;
i = 0;
if(n->op != OREGISTER && n->op != OINDREG)
goto err;
i = n->reg;
if(i < 0 || i >= sizeof(reg))
goto err;
if(reg[i] <= 0)
goto err;
reg[i]--;
return;
err:
diag(n, "error in regfree: %R", i);
}
void
regsalloc(Node *n, Node *nn)
{
cursafe = align(cursafe, nn->type, Aaut3);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
*n = *nodsafe;
n->xoffset = -(stkoff + cursafe);
n->type = nn->type;
n->etype = nn->type->etype;
n->lineno = nn->lineno;
}
void
regaalloc1(Node *n, Node *nn)
{
nodreg(n, nn, REGARG);
reg[REGARG]++;
curarg = align(curarg, nn->type, Aarg1);
curarg = align(curarg, nn->type, Aarg2);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
void
regaalloc(Node *n, Node *nn)
{
curarg = align(curarg, nn->type, Aarg1);
*n = *nn;
n->op = OINDREG;
n->reg = REGSP;
n->xoffset = curarg;
n->complex = 0;
n->addable = 20;
curarg = align(curarg, nn->type, Aarg2);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
void
regind(Node *n, Node *nn)
{
if(n->op != OREGISTER) {
diag(n, "regind not OREGISTER");
return;
}
n->op = OINDREG;
n->type = nn->type;
}
void
naddr(Node *n, Adr *a)
{
int32 v;
a->type = D_NONE;
if(n == Z)
return;
switch(n->op) {
default:
bad:
diag(n, "bad in naddr: %O %D", n->op, a);
break;
case OREGISTER:
a->type = n->reg;
a->sym = S;
break;
case OEXREG:
a->type = D_INDIR + D_GS;
a->offset = n->reg - 1;
break;
case OIND:
naddr(n->left, a);
if(a->type >= D_AX && a->type <= D_DI)
a->type += D_INDIR;
else
if(a->type == D_CONST)
a->type = D_NONE+D_INDIR;
else
if(a->type == D_ADDR) {
a->type = a->index;
a->index = D_NONE;
} else
goto bad;
break;
case OINDEX:
a->type = idx.ptr;
if(n->left->op == OADDR || n->left->op == OCONST)
naddr(n->left, a);
if(a->type >= D_AX && a->type <= D_DI)
a->type += D_INDIR;
else
if(a->type == D_CONST)
a->type = D_NONE+D_INDIR;
else
if(a->type == D_ADDR) {
a->type = a->index;
a->index = D_NONE;
} else
goto bad;
a->index = idx.reg;
a->scale = n->scale;
a->offset += n->xoffset;
break;
case OINDREG:
a->type = n->reg+D_INDIR;
a->sym = S;
a->offset = n->xoffset;
break;
case ONAME:
a->etype = n->etype;
a->type = D_STATIC;
a->sym = n->sym;
a->offset = n->xoffset;
if(n->class == CSTATIC)
break;
if(n->class == CEXTERN || n->class == CGLOBL) {
a->type = D_EXTERN;
break;
}
if(n->class == CAUTO) {
a->type = D_AUTO;
break;
}
if(n->class == CPARAM) {
a->type = D_PARAM;
break;
}
goto bad;
case OCONST:
if(typefd[n->type->etype]) {
a->type = D_FCONST;
a->dval = n->fconst;
break;
}
a->sym = S;
a->type = D_CONST;
a->offset = n->vconst;
break;
case OADDR:
naddr(n->left, a);
if(a->type >= D_INDIR) {
a->type -= D_INDIR;
break;
}
if(a->type == D_EXTERN || a->type == D_STATIC ||
a->type == D_AUTO || a->type == D_PARAM)
if(a->index == D_NONE) {
a->index = a->type;
a->type = D_ADDR;
break;
}
goto bad;
case OADD:
if(n->right->op == OCONST) {
v = n->right->vconst;
naddr(n->left, a);
} else
if(n->left->op == OCONST) {
v = n->left->vconst;
naddr(n->right, a);
} else
goto bad;
a->offset += v;
break;
}
}
#define CASE(a,b) ((a<<8)|(b<<0))
void
gmove(Node *f, Node *t)
{
int ft, tt, a;
Node nod, nod1;
Prog *p1;
ft = f->type->etype;
tt = t->type->etype;
if(debug['M'])
print("gop: %O %O[%s],%O[%s]\n", OAS,
f->op, tnames[ft], t->op, tnames[tt]);
if(typefd[ft] && f->op == OCONST) {
if(f->fconst == 0)
gins(AFLDZ, Z, Z);
else
if(f->fconst == 1)
gins(AFLD1, Z, Z);
else
gins(AFMOVD, f, &fregnode0);
gmove(&fregnode0, t);
return;
}
/*
* load
*/
if(f->op == ONAME || f->op == OINDREG ||
f->op == OIND || f->op == OINDEX)
switch(ft) {
case TCHAR:
a = AMOVBLSX;
goto ld;
case TUCHAR:
a = AMOVBLZX;
goto ld;
case TSHORT:
if(typefd[tt]) {
gins(AFMOVW, f, &fregnode0);
gmove(&fregnode0, t);
return;
}
a = AMOVWLSX;
goto ld;
case TUSHORT:
a = AMOVWLZX;
goto ld;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
if(typefd[tt]) {
gins(AFMOVL, f, &fregnode0);
gmove(&fregnode0, t);
return;
}
a = AMOVL;
ld:
regalloc(&nod, f, t);
nod.type = types[TLONG];
gins(a, f, &nod);
gmove(&nod, t);
regfree(&nod);
return;
case TFLOAT:
gins(AFMOVF, f, t);
return;
case TDOUBLE:
gins(AFMOVD, f, t);
return;
case TVLONG:
gins(AFMOVV, f, t);
return;
}
/*
* store
*/
if(t->op == ONAME || t->op == OINDREG ||
t->op == OIND || t->op == OINDEX)
switch(tt) {
case TCHAR:
case TUCHAR:
a = AMOVB; goto st;
case TSHORT:
case TUSHORT:
a = AMOVW; goto st;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
a = AMOVL; goto st;
st:
if(f->op == OCONST) {
gins(a, f, t);
return;
}
regalloc(&nod, t, f);
gmove(f, &nod);
gins(a, &nod, t);
regfree(&nod);
return;
case TFLOAT:
gins(AFMOVFP, f, t);
return;
case TDOUBLE:
gins(AFMOVDP, f, t);
return;
case TVLONG:
gins(AFMOVVP, f, t);
return;
}
/*
* convert
*/
switch(CASE(ft,tt)) {
default:
/*
* integer to integer
********
a = AGOK; break;
case CASE( TCHAR, TCHAR):
case CASE( TUCHAR, TCHAR):
case CASE( TSHORT, TCHAR):
case CASE( TUSHORT,TCHAR):
case CASE( TINT, TCHAR):
case CASE( TUINT, TCHAR):
case CASE( TLONG, TCHAR):
case CASE( TULONG, TCHAR):
case CASE( TIND, TCHAR):
case CASE( TCHAR, TUCHAR):
case CASE( TUCHAR, TUCHAR):
case CASE( TSHORT, TUCHAR):
case CASE( TUSHORT,TUCHAR):
case CASE( TINT, TUCHAR):
case CASE( TUINT, TUCHAR):
case CASE( TLONG, TUCHAR):
case CASE( TULONG, TUCHAR):
case CASE( TIND, TUCHAR):
case CASE( TSHORT, TSHORT):
case CASE( TUSHORT,TSHORT):
case CASE( TINT, TSHORT):
case CASE( TUINT, TSHORT):
case CASE( TLONG, TSHORT):
case CASE( TULONG, TSHORT):
case CASE( TIND, TSHORT):
case CASE( TSHORT, TUSHORT):
case CASE( TUSHORT,TUSHORT):
case CASE( TINT, TUSHORT):
case CASE( TUINT, TUSHORT):
case CASE( TLONG, TUSHORT):
case CASE( TULONG, TUSHORT):
case CASE( TIND, TUSHORT):
case CASE( TINT, TINT):
case CASE( TUINT, TINT):
case CASE( TLONG, TINT):
case CASE( TULONG, TINT):
case CASE( TIND, TINT):
case CASE( TINT, TUINT):
case CASE( TUINT, TUINT):
case CASE( TLONG, TUINT):
case CASE( TULONG, TUINT):
case CASE( TIND, TUINT):
case CASE( TINT, TLONG):
case CASE( TUINT, TLONG):
case CASE( TLONG, TLONG):
case CASE( TULONG, TLONG):
case CASE( TIND, TLONG):
case CASE( TINT, TULONG):
case CASE( TUINT, TULONG):
case CASE( TLONG, TULONG):
case CASE( TULONG, TULONG):
case CASE( TIND, TULONG):
case CASE( TINT, TIND):
case CASE( TUINT, TIND):
case CASE( TLONG, TIND):
case CASE( TULONG, TIND):
case CASE( TIND, TIND):
*****/
a = AMOVL;
break;
case CASE( TSHORT, TINT):
case CASE( TSHORT, TUINT):
case CASE( TSHORT, TLONG):
case CASE( TSHORT, TULONG):
case CASE( TSHORT, TIND):
a = AMOVWLSX;
if(f->op == OCONST) {
f->vconst &= 0xffff;
if(f->vconst & 0x8000)
f->vconst |= 0xffff0000;
a = AMOVL;
}
break;
case CASE( TUSHORT,TINT):
case CASE( TUSHORT,TUINT):
case CASE( TUSHORT,TLONG):
case CASE( TUSHORT,TULONG):
case CASE( TUSHORT,TIND):
a = AMOVWLZX;
if(f->op == OCONST) {
f->vconst &= 0xffff;
a = AMOVL;
}
break;
case CASE( TCHAR, TSHORT):
case CASE( TCHAR, TUSHORT):
case CASE( TCHAR, TINT):
case CASE( TCHAR, TUINT):
case CASE( TCHAR, TLONG):
case CASE( TCHAR, TULONG):
case CASE( TCHAR, TIND):
a = AMOVBLSX;
if(f->op == OCONST) {
f->vconst &= 0xff;
if(f->vconst & 0x80)
f->vconst |= 0xffffff00;
a = AMOVL;
}
break;
case CASE( TUCHAR, TSHORT):
case CASE( TUCHAR, TUSHORT):
case CASE( TUCHAR, TINT):
case CASE( TUCHAR, TUINT):
case CASE( TUCHAR, TLONG):
case CASE( TUCHAR, TULONG):
case CASE( TUCHAR, TIND):
a = AMOVBLZX;
if(f->op == OCONST) {
f->vconst &= 0xff;
a = AMOVL;
}
break;
/*
* float to fix
*/
case CASE( TFLOAT, TCHAR):
case CASE( TFLOAT, TUCHAR):
case CASE( TFLOAT, TSHORT):
case CASE( TFLOAT, TUSHORT):
case CASE( TFLOAT, TINT):
case CASE( TFLOAT, TUINT):
case CASE( TFLOAT, TLONG):
case CASE( TFLOAT, TULONG):
case CASE( TFLOAT, TIND):
case CASE( TDOUBLE,TCHAR):
case CASE( TDOUBLE,TUCHAR):
case CASE( TDOUBLE,TSHORT):
case CASE( TDOUBLE,TUSHORT):
case CASE( TDOUBLE,TINT):
case CASE( TDOUBLE,TUINT):
case CASE( TDOUBLE,TLONG):
case CASE( TDOUBLE,TULONG):
case CASE( TDOUBLE,TIND):
case CASE( TVLONG, TCHAR):
case CASE( TVLONG, TUCHAR):
case CASE( TVLONG, TSHORT):
case CASE( TVLONG, TUSHORT):
case CASE( TVLONG, TINT):
case CASE( TVLONG, TUINT):
case CASE( TVLONG, TLONG):
case CASE( TVLONG, TULONG):
case CASE( TVLONG, TIND):
if(fproundflg) {
regsalloc(&nod, ®node);
gins(AFMOVLP, f, &nod);
gmove(&nod, t);
return;
}
regsalloc(&nod, ®node);
regsalloc(&nod1, ®node);
gins(AFSTCW, Z, &nod1);
nod1.xoffset += 2;
gins(AMOVW, nodconst(0xf7f), &nod1);
gins(AFLDCW, &nod1, Z);
gins(AFMOVLP, f, &nod);
nod1.xoffset -= 2;
gins(AFLDCW, &nod1, Z);
gmove(&nod, t);
return;
/*
* ulong to float
*/
case CASE( TULONG, TDOUBLE):
case CASE( TULONG, TVLONG):
case CASE( TULONG, TFLOAT):
case CASE( TUINT, TDOUBLE):
case CASE( TUINT, TVLONG):
case CASE( TUINT, TFLOAT):
regalloc(&nod, f, f);
gmove(f, &nod);
regsalloc(&nod1, ®node);
gmove(&nod, &nod1);
gins(AFMOVL, &nod1, &fregnode0);
gins(ACMPL, &nod, nodconst(0));
gins(AJGE, Z, Z);
p1 = p;
gins(AFADDD, nodfconst(4294967296.), &fregnode0);
patch(p1, pc);
regfree(&nod);
return;
/*
* fix to float
*/
case CASE( TCHAR, TFLOAT):
case CASE( TUCHAR, TFLOAT):
case CASE( TSHORT, TFLOAT):
case CASE( TUSHORT,TFLOAT):
case CASE( TINT, TFLOAT):
case CASE( TLONG, TFLOAT):
case CASE( TIND, TFLOAT):
case CASE( TCHAR, TDOUBLE):
case CASE( TUCHAR, TDOUBLE):
case CASE( TSHORT, TDOUBLE):
case CASE( TUSHORT,TDOUBLE):
case CASE( TINT, TDOUBLE):
case CASE( TLONG, TDOUBLE):
case CASE( TIND, TDOUBLE):
case CASE( TCHAR, TVLONG):
case CASE( TUCHAR, TVLONG):
case CASE( TSHORT, TVLONG):
case CASE( TUSHORT,TVLONG):
case CASE( TINT, TVLONG):
case CASE( TLONG, TVLONG):
case CASE( TIND, TVLONG):
regsalloc(&nod, ®node);
gmove(f, &nod);
gins(AFMOVL, &nod, &fregnode0);
return;
/*
* float to float
*/
case CASE( TFLOAT, TFLOAT):
case CASE( TDOUBLE,TFLOAT):
case CASE( TVLONG, TFLOAT):
case CASE( TFLOAT, TDOUBLE):
case CASE( TDOUBLE,TDOUBLE):
case CASE( TVLONG, TDOUBLE):
case CASE( TFLOAT, TVLONG):
case CASE( TDOUBLE,TVLONG):
case CASE( TVLONG, TVLONG):
a = AFMOVD; break;
}
if(a == AMOVL || a == AFMOVD)
if(samaddr(f, t))
return;
gins(a, f, t);
}
void
doindex(Node *n)
{
Node nod, nod1;
int32 v;
if(debug['Y'])
prtree(n, "index");
if(n->left->complex >= FNX)
print("botch in doindex\n");
regalloc(&nod, ®node, Z);
v = constnode.vconst;
cgen(n->right, &nod);
idx.ptr = D_NONE;
if(n->left->op == OCONST)
idx.ptr = D_CONST;
else if(n->left->op == OREGISTER)
idx.ptr = n->left->reg;
else if(n->left->op != OADDR) {
reg[D_BP]++; // cant be used as a base
regalloc(&nod1, ®node, Z);
cgen(n->left, &nod1);
idx.ptr = nod1.reg;
regfree(&nod1);
reg[D_BP]--;
}
idx.reg = nod.reg;
regfree(&nod);
constnode.vconst = v;
}
void
gins(int a, Node *f, Node *t)
{
if(f != Z && f->op == OINDEX)
doindex(f);
if(t != Z && t->op == OINDEX)
doindex(t);
nextpc();
p->as = a;
if(f != Z)
naddr(f, &p->from);
if(t != Z)
naddr(t, &p->to);
if(debug['g'])
print("%P\n", p);
}
void
fgopcode(int o, Node *f, Node *t, int pop, int rev)
{
int a, et;
Node nod;
et = TLONG;
if(f != Z && f->type != T)
et = f->type->etype;
if(!typefd[et]) {
diag(f, "fop: integer %O", o);
return;
}
if(debug['M']) {
if(t != Z && t->type != T)
print("gop: %O %O-%s Z\n", o, f->op, tnames[et]);
else
print("gop: %O %O-%s %O-%s\n", o,
f->op, tnames[et], t->op, tnames[t->type->etype]);
}
a = AGOK;
switch(o) {
case OASADD:
case OADD:
if(et == TFLOAT)
a = AFADDF;
else
if(et == TDOUBLE || et == TVLONG) {
a = AFADDD;
if(pop)
a = AFADDDP;
}
break;
case OASSUB:
case OSUB:
if(et == TFLOAT) {
a = AFSUBF;
if(rev)
a = AFSUBRF;
} else
if(et == TDOUBLE || et == TVLONG) {
a = AFSUBD;
if(pop)
a = AFSUBDP;
if(rev) {
a = AFSUBRD;
if(pop)
a = AFSUBRDP;
}
}
break;
case OASMUL:
case OMUL:
if(et == TFLOAT)
a = AFMULF;
else
if(et == TDOUBLE || et == TVLONG) {
a = AFMULD;
if(pop)
a = AFMULDP;
}
break;
case OASMOD:
case OMOD:
case OASDIV:
case ODIV:
if(et == TFLOAT) {
a = AFDIVF;
if(rev)
a = AFDIVRF;
} else
if(et == TDOUBLE || et == TVLONG) {
a = AFDIVD;
if(pop)
a = AFDIVDP;
if(rev) {
a = AFDIVRD;
if(pop)
a = AFDIVRDP;
}
}
break;
case OEQ:
case ONE:
case OLT:
case OLE:
case OGE:
case OGT:
pop += rev;
if(et == TFLOAT) {
a = AFCOMF;
if(pop) {
a = AFCOMFP;
if(pop > 1)
a = AGOK;
}
} else
if(et == TDOUBLE || et == TVLONG) {
a = AFCOMF;
if(pop) {
a = AFCOMDP;
if(pop > 1)
a = AFCOMDPP;
}
}
gins(a, f, t);
regalloc(&nod, ®node, Z);
if(nod.reg != D_AX) {
regfree(&nod);
nod.reg = D_AX;
gins(APUSHL, &nod, Z);
gins(AWAIT, Z, Z);
gins(AFSTSW, Z, &nod);
gins(ASAHF, Z, Z);
gins(APOPL, Z, &nod);
} else {
gins(AWAIT, Z, Z);
gins(AFSTSW, Z, &nod);
gins(ASAHF, Z, Z);
regfree(&nod);
}
switch(o) {
case OEQ: a = AJEQ; break;
case ONE: a = AJNE; break;
case OLT: a = AJCS; break;
case OLE: a = AJLS; break;
case OGE: a = AJCC; break;
case OGT: a = AJHI; break;
}
gins(a, Z, Z);
return;
}
if(a == AGOK)
diag(Z, "bad in gopcode %O", o);
gins(a, f, t);
}
void
gopcode(int o, Type *ty, Node *f, Node *t)
{
int a, et;
et = TLONG;
if(ty != T)
et = ty->etype;
if(typefd[et] && o != OADDR && o != OFUNC) {
diag(f, "gop: float %O", o);
return;
}
if(debug['M']) {
if(f != Z && f->type != T)
print("gop: %O %O[%s],", o, f->op, tnames[et]);
else
print("gop: %O Z,", o);
if(t != Z && t->type != T)
print("%O[%s]\n", t->op, tnames[t->type->etype]);
else
print("Z\n");
}
a = AGOK;
switch(o) {
case OCOM:
a = ANOTL;
if(et == TCHAR || et == TUCHAR)
a = ANOTB;
if(et == TSHORT || et == TUSHORT)
a = ANOTW;
break;
case ONEG:
a = ANEGL;
if(et == TCHAR || et == TUCHAR)
a = ANEGB;
if(et == TSHORT || et == TUSHORT)
a = ANEGW;
break;
case OADDR:
a = ALEAL;
break;
case OASADD:
case OADD:
a = AADDL;
if(et == TCHAR || et == TUCHAR)
a = AADDB;
if(et == TSHORT || et == TUSHORT)
a = AADDW;
break;
case OASSUB:
case OSUB:
a = ASUBL;
if(et == TCHAR || et == TUCHAR)
a = ASUBB;
if(et == TSHORT || et == TUSHORT)
a = ASUBW;
break;
case OASOR:
case OOR:
a = AORL;
if(et == TCHAR || et == TUCHAR)
a = AORB;
if(et == TSHORT || et == TUSHORT)
a = AORW;
break;
case OASAND:
case OAND:
a = AANDL;
if(et == TCHAR || et == TUCHAR)
a = AANDB;
if(et == TSHORT || et == TUSHORT)
a = AANDW;
break;
case OASXOR:
case OXOR:
a = AXORL;
if(et == TCHAR || et == TUCHAR)
a = AXORB;
if(et == TSHORT || et == TUSHORT)
a = AXORW;
break;
case OASLSHR:
case OLSHR:
a = ASHRL;
if(et == TCHAR || et == TUCHAR)
a = ASHRB;
if(et == TSHORT || et == TUSHORT)
a = ASHRW;
break;
case OASASHR:
case OASHR:
a = ASARL;
if(et == TCHAR || et == TUCHAR)
a = ASARB;
if(et == TSHORT || et == TUSHORT)
a = ASARW;
break;
case OASASHL:
case OASHL:
a = ASALL;
if(et == TCHAR || et == TUCHAR)
a = ASALB;
if(et == TSHORT || et == TUSHORT)
a = ASALW;
break;
case OFUNC:
a = ACALL;
break;
case OASMUL:
case OMUL:
if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
t = Z;
a = AIMULL;
break;
case OASMOD:
case OMOD:
case OASDIV:
case ODIV:
a = AIDIVL;
break;
case OASLMUL:
case OLMUL:
a = AMULL;
break;
case OASLMOD:
case OLMOD:
case OASLDIV:
case OLDIV:
a = ADIVL;
break;
case OEQ:
case ONE:
case OLT:
case OLE:
case OGE:
case OGT:
case OLO:
case OLS:
case OHS:
case OHI:
a = ACMPL;
if(et == TCHAR || et == TUCHAR)
a = ACMPB;
if(et == TSHORT || et == TUSHORT)
a = ACMPW;
gins(a, f, t);
switch(o) {
case OEQ: a = AJEQ; break;
case ONE: a = AJNE; break;
case OLT: a = AJLT; break;
case OLE: a = AJLE; break;
case OGE: a = AJGE; break;
case OGT: a = AJGT; break;
case OLO: a = AJCS; break;
case OLS: a = AJLS; break;
case OHS: a = AJCC; break;
case OHI: a = AJHI; break;
}
gins(a, Z, Z);
return;
}
if(a == AGOK)
diag(Z, "bad in gopcode %O", o);
gins(a, f, t);
}
int
samaddr(Node *f, Node *t)
{
if(f->op != t->op)
return 0;
switch(f->op) {
case OREGISTER:
if(f->reg != t->reg)
break;
return 1;
}
return 0;
}
void
gbranch(int o)
{
int a;
a = AGOK;
switch(o) {
case ORETURN:
a = ARET;
break;
case OGOTO:
a = AJMP;
break;
}
nextpc();
if(a == AGOK) {
diag(Z, "bad in gbranch %O", o);
nextpc();
}
p->as = a;
}
void
patch(Prog *op, int32 pc)
{
op->to.offset = pc;
op->to.type = D_BRANCH;
}
void
gpseudo(int a, Sym *s, Node *n)
{
nextpc();
p->as = a;
p->from.type = D_EXTERN;
p->from.sym = s;
p->from.scale = textflag;
textflag = 0;
if(s->class == CSTATIC)
p->from.type = D_STATIC;
naddr(n, &p->to);
if(a == ADATA || a == AGLOBL)
pc--;
}
int
sconst(Node *n)
{
int32 v;
if(n->op == OCONST && !typefd[n->type->etype]) {
v = n->vconst;
if(v >= -32766L && v < 32766L)
return 1;
}
return 0;
}
int32
exreg(Type *t)
{
int32 o;
if(typechlp[t->etype]){
if(exregoffset >= 32)
return 0;
o = exregoffset;
exregoffset += 4;
return o+1; // +1 to avoid 0 == failure; naddr case OEXREG will -1.
}
USED(t);
return 0;
}
schar ewidth[NTYPE] =
{
-1, /*[TXXX]*/
SZ_CHAR, /*[TCHAR]*/
SZ_CHAR, /*[TUCHAR]*/
SZ_SHORT, /*[TSHORT]*/
SZ_SHORT, /*[TUSHORT]*/
SZ_INT, /*[TINT]*/
SZ_INT, /*[TUINT]*/
SZ_LONG, /*[TLONG]*/
SZ_LONG, /*[TULONG]*/
SZ_VLONG, /*[TVLONG]*/
SZ_VLONG, /*[TUVLONG]*/
SZ_FLOAT, /*[TFLOAT]*/
SZ_DOUBLE, /*[TDOUBLE]*/
SZ_IND, /*[TIND]*/
0, /*[TFUNC]*/
-1, /*[TARRAY]*/
0, /*[TVOID]*/
-1, /*[TSTRUCT]*/
-1, /*[TUNION]*/
SZ_INT, /*[TENUM]*/
};
int32 ncast[NTYPE] =
{
0, /*[TXXX]*/
BCHAR|BUCHAR, /*[TCHAR]*/
BCHAR|BUCHAR, /*[TUCHAR]*/
BSHORT|BUSHORT, /*[TSHORT]*/
BSHORT|BUSHORT, /*[TUSHORT]*/
BINT|BUINT|BLONG|BULONG|BIND, /*[TINT]*/
BINT|BUINT|BLONG|BULONG|BIND, /*[TUINT]*/
BINT|BUINT|BLONG|BULONG|BIND, /*[TLONG]*/
BINT|BUINT|BLONG|BULONG|BIND, /*[TULONG]*/
BVLONG|BUVLONG, /*[TVLONG]*/
BVLONG|BUVLONG, /*[TUVLONG]*/
BFLOAT, /*[TFLOAT]*/
BDOUBLE, /*[TDOUBLE]*/
BLONG|BULONG|BIND, /*[TIND]*/
0, /*[TFUNC]*/
0, /*[TARRAY]*/
0, /*[TVOID]*/
BSTRUCT, /*[TSTRUCT]*/
BUNION, /*[TUNION]*/
0, /*[TENUM]*/
};
|