blob: af40220ccb02ff22e18d640cd27773f8133c9e24 [file] [log] [blame]
// Inferno utils/5c/txt.c
// http://code.google.com/p/inferno-os/source/browse/utils/5c/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"
int thechar = '5';
char *thestring = "arm";
LinkArch *thelinkarch = &linkarm;
void
linkarchinit(void)
{
}
void
ginit(void)
{
Type *t;
exregoffset = REGEXT;
exfregoffset = FREGEXT;
listinit();
nstring = 0;
mnstring = 0;
nrathole = 0;
pc = 0;
breakpc = -1;
continpc = -1;
cases = C;
lastp = P;
tfield = types[TLONG];
zprog.link = P;
zprog.as = AGOK;
zprog.reg = NREG;
zprog.from.type = D_NONE;
zprog.from.name = D_NONE;
zprog.from.reg = NREG;
zprog.to = zprog.from;
zprog.scond = 0xE;
regnode.op = OREGISTER;
regnode.class = CEXREG;
regnode.reg = REGTMP;
regnode.complex = 0;
regnode.addable = 11;
regnode.type = types[TLONG];
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();
memset(reg, 0, sizeof(reg));
}
void
gclean(void)
{
int i;
Sym *s;
for(i=0; i<NREG; i++)
if(reg[i])
diag(Z, "reg %d left allocated", i);
for(i=NREG; i<NREG+NFREG; i++)
if(reg[i])
diag(Z, "freg %d left allocated", i-NREG);
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)
{
Plist *pl;
p = alloc(sizeof(*p));
*p = zprog;
p->lineno = nearln;
pc++;
if(lastp == nil) {
pl = linknewplist(ctxt);
pl->firstpc = p;
} else
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;
}
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(typesuv[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 && typechlp[n->type->etype]) {
regaalloc1(tn1, n);
if(n->complex >= FNX) {
cgen(*fnxp, tn1);
(*fnxp)++;
} else
cgen(n, tn1);
return;
}
regalloc(tn1, n, Z);
if(n->complex >= FNX) {
cgen(*fnxp, tn1);
(*fnxp)++;
} else
cgen(n, tn1);
regaalloc(tn2, n);
gopcode(OAS, tn1, Z, tn2);
regfree(tn1);
}
Node*
nodconst(int32 v)
{
constnode.vconst = v;
return &constnode;
}
Node*
nod32const(vlong v)
{
constnode.vconst = v & MASK(32);
return &constnode;
}
Node*
nodfconst(double d)
{
fconstnode.fconst = d;
return &fconstnode;
}
void
nodreg(Node *n, Node *nn, int reg)
{
*n = regnode;
n->reg = reg;
n->type = nn->type;
n->lineno = nn->lineno;
}
void
regret(Node *n, Node *nn, Type *t, int mode)
{
int r;
if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
r = REGRET;
if(typefd[nn->type->etype])
r = FREGRET+NREG;
nodreg(n, nn, r);
reg[r]++;
return;
}
if(mode == 1) {
// fetch returned value after call.
// already called gargs, so curarg is set.
curarg = (curarg+3) & ~3;
regaalloc(n, nn);
return;
}
if(mode == 2) {
// store value to be returned.
// must compute arg offset.
if(t->etype != TFUNC)
fatal(Z, "bad regret func %T", t);
*n = *nn;
n->op = ONAME;
n->class = CPARAM;
n->sym = slookup(".ret");
n->complex = nodret->complex;
n->xoffset = argsize(0);
n->addable = 20;
return;
}
fatal(Z, "bad regret");
}
int
tmpreg(void)
{
int i;
for(i=REGRET+1; i<NREG; i++)
if(reg[i] == 0)
return i;
diag(Z, "out of fixed registers");
return 0;
}
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 >= 0 && i < NREG)
goto out;
}
for(i=REGRET+1; i<=REGEXT-2; i++)
if(reg[i] == 0)
goto out;
diag(tn, "out of fixed registers");
goto err;
case TFLOAT:
case TDOUBLE:
case TVLONG:
if(o != Z && o->op == OREGISTER) {
i = o->reg;
if(i >= NREG && i < NREG+NFREG)
goto out;
}
for(i=NREG; i<NREG+NFREG; i++)
if(reg[i] == 0)
goto out;
diag(tn, "out of float registers");
goto err;
}
diag(tn, "unknown type in regalloc: %T", tn->type);
err:
nodreg(n, tn, 0);
return;
out:
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 >= nelem(reg))
goto err;
if(reg[i] <= 0)
goto err;
reg[i]--;
return;
err:
diag(n, "error in regfree: %d", i);
}
void
regsalloc(Node *n, Node *nn)
{
cursafe = align(cursafe, nn->type, Aaut3, nil);
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)
{
if(REGARG < 0) {
fatal(n, "regaalloc1 and REGARG<0");
return;
}
nodreg(n, nn, REGARG);
reg[REGARG]++;
curarg = align(curarg, nn->type, Aarg1, nil);
curarg = align(curarg, nn->type, Aarg2, nil);
maxargsafe = maxround(maxargsafe, cursafe+curarg);
}
void
regaalloc(Node *n, Node *nn)
{
curarg = align(curarg, nn->type, Aarg1, nil);
*n = *nn;
n->op = OINDREG;
n->reg = REGSP;
n->xoffset = curarg + SZ_LONG;
n->complex = 0;
n->addable = 20;
curarg = align(curarg, nn->type, Aarg2, nil);
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
raddr(Node *n, Prog *p)
{
Addr a;
naddr(n, &a);
if(R0ISZERO && a.type == D_CONST && a.offset == 0) {
a.type = D_REG;
a.reg = 0;
}
if(a.type != D_REG && a.type != D_FREG) {
if(n)
diag(n, "bad in raddr: %O", n->op);
else
diag(n, "bad in raddr: <null>");
p->reg = NREG;
} else
p->reg = a.reg;
}
void
naddr(Node *n, Addr *a)
{
int32 v;
a->type = D_NONE;
if(n == Z)
return;
switch(n->op) {
default:
bad:
diag(n, "bad in naddr: %O", n->op);
break;
case OREGISTER:
a->type = D_REG;
a->sym = nil;
a->reg = n->reg;
if(a->reg >= NREG) {
a->type = D_FREG;
a->reg -= NREG;
}
break;
case OIND:
naddr(n->left, a);
if(a->type == D_REG) {
a->type = D_OREG;
break;
}
if(a->type == D_CONST) {
a->type = D_OREG;
break;
}
goto bad;
case OINDREG:
a->type = D_OREG;
a->sym = nil;
a->offset = n->xoffset;
a->reg = n->reg;
break;
case ONAME:
a->etype = n->etype;
a->type = D_OREG;
a->name = D_STATIC;
a->sym = linksym(n->sym);
a->offset = n->xoffset;
if(n->class == CSTATIC)
break;
if(n->class == CEXTERN || n->class == CGLOBL) {
a->name = D_EXTERN;
break;
}
if(n->class == CAUTO) {
a->name = D_AUTO;
break;
}
if(n->class == CPARAM) {
a->name = D_PARAM;
break;
}
goto bad;
case OCONST:
a->sym = nil;
a->reg = NREG;
if(typefd[n->type->etype]) {
a->type = D_FCONST;
a->u.dval = n->fconst;
} else {
a->type = D_CONST;
a->offset = n->vconst;
}
break;
case OADDR:
naddr(n->left, a);
if(a->type == D_OREG) {
a->type = D_CONST;
break;
}
goto bad;
case OADD:
if(n->left->op == OCONST) {
naddr(n->left, a);
v = a->offset;
naddr(n->right, a);
} else {
naddr(n->right, a);
v = a->offset;
naddr(n->left, a);
}
a->offset += v;
break;
}
}
void
fop(int as, int f1, int f2, Node *t)
{
Node nod1, nod2, nod3;
nodreg(&nod1, t, NREG+f1);
nodreg(&nod2, t, NREG+f2);
regalloc(&nod3, t, t);
gopcode(as, &nod1, &nod2, &nod3);
gmove(&nod3, t);
regfree(&nod3);
}
void
gmovm(Node *f, Node *t, int w)
{
gins(AMOVM, f, t);
p->scond |= C_UBIT;
if(w)
p->scond |= C_WBIT;
}
void
gmove(Node *f, Node *t)
{
int ft, tt, a;
Node nod, nod1;
Prog *p1;
ft = f->type->etype;
tt = t->type->etype;
if(ft == TDOUBLE && f->op == OCONST) {
}
if(ft == TFLOAT && f->op == OCONST) {
}
/*
* a load --
* put it into a register then
* worry what to do with it.
*/
if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
switch(ft) {
default:
a = AMOVW;
break;
case TFLOAT:
a = AMOVF;
break;
case TDOUBLE:
a = AMOVD;
break;
case TCHAR:
a = AMOVBS;
break;
case TUCHAR:
a = AMOVBU;
break;
case TSHORT:
a = AMOVHS;
break;
case TUSHORT:
a = AMOVHU;
break;
}
if(typechlp[ft] && typeilp[tt])
regalloc(&nod, t, t);
else
regalloc(&nod, f, t);
gins(a, f, &nod);
gmove(&nod, t);
regfree(&nod);
return;
}
/*
* a store --
* put it into a register then
* store it.
*/
if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
switch(tt) {
default:
a = AMOVW;
break;
case TUCHAR:
a = AMOVBU;
break;
case TCHAR:
a = AMOVBS;
break;
case TUSHORT:
a = AMOVHU;
break;
case TSHORT:
a = AMOVHS;
break;
case TFLOAT:
a = AMOVF;
break;
case TVLONG:
case TDOUBLE:
a = AMOVD;
break;
}
if(ft == tt)
regalloc(&nod, t, f);
else
regalloc(&nod, t, Z);
gmove(f, &nod);
gins(a, &nod, t);
regfree(&nod);
return;
}
/*
* type x type cross table
*/
a = AGOK;
switch(ft) {
case TDOUBLE:
case TVLONG:
case TFLOAT:
switch(tt) {
case TDOUBLE:
case TVLONG:
a = AMOVD;
if(ft == TFLOAT)
a = AMOVFD;
break;
case TFLOAT:
a = AMOVDF;
if(ft == TFLOAT)
a = AMOVF;
break;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
a = AMOVDW;
if(ft == TFLOAT)
a = AMOVFW;
break;
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
a = AMOVDW;
if(ft == TFLOAT)
a = AMOVFW;
break;
}
break;
case TUINT:
case TULONG:
if(tt == TFLOAT || tt == TDOUBLE) {
// ugly and probably longer than necessary,
// but vfp has a single instruction for this,
// so hopefully it won't last long.
//
// tmp = f
// tmp1 = tmp & 0x80000000
// tmp ^= tmp1
// t = float(int32(tmp))
// if(tmp1)
// t += 2147483648.
//
regalloc(&nod, f, Z);
regalloc(&nod1, f, Z);
gins(AMOVW, f, &nod);
gins(AMOVW, &nod, &nod1);
gins(AAND, nodconst(0x80000000), &nod1);
gins(AEOR, &nod1, &nod);
if(tt == TFLOAT)
gins(AMOVWF, &nod, t);
else
gins(AMOVWD, &nod, t);
gins(ACMP, nodconst(0), Z);
raddr(&nod1, p);
gins(ABEQ, Z, Z);
regfree(&nod);
regfree(&nod1);
p1 = p;
regalloc(&nod, t, Z);
gins(AMOVF, nodfconst(2147483648.), &nod);
gins(AADDF, &nod, t);
regfree(&nod);
patch(p1, pc);
return;
}
// fall through
case TINT:
case TLONG:
case TIND:
switch(tt) {
case TDOUBLE:
gins(AMOVWD, f, t);
return;
case TFLOAT:
gins(AMOVWF, f, t);
return;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
a = AMOVW;
break;
}
break;
case TSHORT:
switch(tt) {
case TDOUBLE:
regalloc(&nod, f, Z);
gins(AMOVHS, f, &nod);
gins(AMOVWD, &nod, t);
regfree(&nod);
return;
case TFLOAT:
regalloc(&nod, f, Z);
gins(AMOVHS, f, &nod);
gins(AMOVWF, &nod, t);
regfree(&nod);
return;
case TUINT:
case TINT:
case TULONG:
case TLONG:
case TIND:
a = AMOVHS;
break;
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
a = AMOVW;
break;
}
break;
case TUSHORT:
switch(tt) {
case TDOUBLE:
regalloc(&nod, f, Z);
gins(AMOVHU, f, &nod);
gins(AMOVWD, &nod, t);
regfree(&nod);
return;
case TFLOAT:
regalloc(&nod, f, Z);
gins(AMOVHU, f, &nod);
gins(AMOVWF, &nod, t);
regfree(&nod);
return;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
a = AMOVHU;
break;
case TSHORT:
case TUSHORT:
case TCHAR:
case TUCHAR:
a = AMOVW;
break;
}
break;
case TCHAR:
switch(tt) {
case TDOUBLE:
regalloc(&nod, f, Z);
gins(AMOVBS, f, &nod);
gins(AMOVWD, &nod, t);
regfree(&nod);
return;
case TFLOAT:
regalloc(&nod, f, Z);
gins(AMOVBS, f, &nod);
gins(AMOVWF, &nod, t);
regfree(&nod);
return;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
case TSHORT:
case TUSHORT:
a = AMOVBS;
break;
case TCHAR:
case TUCHAR:
a = AMOVW;
break;
}
break;
case TUCHAR:
switch(tt) {
case TDOUBLE:
regalloc(&nod, f, Z);
gins(AMOVBU, f, &nod);
gins(AMOVWD, &nod, t);
regfree(&nod);
return;
case TFLOAT:
regalloc(&nod, f, Z);
gins(AMOVBU, f, &nod);
gins(AMOVWF, &nod, t);
regfree(&nod);
return;
case TINT:
case TUINT:
case TLONG:
case TULONG:
case TIND:
case TSHORT:
case TUSHORT:
a = AMOVBU;
break;
case TCHAR:
case TUCHAR:
a = AMOVW;
break;
}
break;
}
if(a == AGOK)
diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
if(a == AMOVW || a == AMOVF || a == AMOVD)
if(samaddr(f, t))
return;
gins(a, f, t);
}
void
gmover(Node *f, Node *t)
{
int ft, tt, a;
ft = f->type->etype;
tt = t->type->etype;
a = AGOK;
if(typechlp[ft] && typechlp[tt] && ewidth[ft] >= ewidth[tt]){
switch(tt){
case TSHORT:
a = AMOVHS;
break;
case TUSHORT:
a = AMOVHU;
break;
case TCHAR:
a = AMOVBS;
break;
case TUCHAR:
a = AMOVBU;
break;
}
}
if(a == AGOK)
gmove(f, t);
else
gins(a, f, t);
}
void
gins(int a, Node *f, Node *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
gopcode(int o, Node *f1, Node *f2, Node *t)
{
int a, et;
Addr ta;
et = TLONG;
if(f1 != Z && f1->type != T)
et = f1->type->etype;
a = AGOK;
switch(o) {
case OAS:
gmove(f1, t);
return;
case OASADD:
case OADD:
a = AADD;
if(et == TFLOAT)
a = AADDF;
else
if(et == TDOUBLE || et == TVLONG)
a = AADDD;
break;
case OASSUB:
case OSUB:
if(f2 && f2->op == OCONST) {
Node *t = f1;
f1 = f2;
f2 = t;
a = ARSB;
} else
a = ASUB;
if(et == TFLOAT)
a = ASUBF;
else
if(et == TDOUBLE || et == TVLONG)
a = ASUBD;
break;
case OASOR:
case OOR:
a = AORR;
break;
case OASAND:
case OAND:
a = AAND;
break;
case OASXOR:
case OXOR:
a = AEOR;
break;
case OASLSHR:
case OLSHR:
a = ASRL;
break;
case OASASHR:
case OASHR:
a = ASRA;
break;
case OASASHL:
case OASHL:
a = ASLL;
break;
case OFUNC:
a = ABL;
break;
case OASMUL:
case OMUL:
a = AMUL;
if(et == TFLOAT)
a = AMULF;
else
if(et == TDOUBLE || et == TVLONG)
a = AMULD;
break;
case OASDIV:
case ODIV:
a = ADIV;
if(et == TFLOAT)
a = ADIVF;
else
if(et == TDOUBLE || et == TVLONG)
a = ADIVD;
break;
case OASMOD:
case OMOD:
a = AMOD;
break;
case OASLMUL:
case OLMUL:
a = AMULU;
break;
case OASLMOD:
case OLMOD:
a = AMODU;
break;
case OASLDIV:
case OLDIV:
a = ADIVU;
break;
case OCASE:
case OEQ:
case ONE:
case OLT:
case OLE:
case OGE:
case OGT:
case OLO:
case OLS:
case OHS:
case OHI:
a = ACMP;
if(et == TFLOAT)
a = ACMPF;
else
if(et == TDOUBLE || et == TVLONG)
a = ACMPD;
nextpc();
p->as = a;
naddr(f1, &p->from);
if(a == ACMP && f1->op == OCONST && p->from.offset < 0) {
p->as = ACMN;
p->from.offset = -p->from.offset;
}
raddr(f2, p);
switch(o) {
case OEQ:
a = ABEQ;
break;
case ONE:
a = ABNE;
break;
case OLT:
a = ABLT;
break;
case OLE:
a = ABLE;
break;
case OGE:
a = ABGE;
break;
case OGT:
a = ABGT;
break;
case OLO:
a = ABLO;
break;
case OLS:
a = ABLS;
break;
case OHS:
a = ABHS;
break;
case OHI:
a = ABHI;
break;
case OCASE:
nextpc();
p->as = ACASE;
p->scond = 0x9;
naddr(f2, &p->from);
a = ABHI;
break;
}
f1 = Z;
f2 = Z;
break;
}
if(a == AGOK)
diag(Z, "bad in gopcode %O", o);
nextpc();
p->as = a;
if(f1 != Z)
naddr(f1, &p->from);
if(f2 != Z) {
naddr(f2, &ta);
p->reg = ta.reg;
}
if(t != Z)
naddr(t, &p->to);
if(debug['g'])
print("%P\n", p);
}
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 = AB;
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_OREG;
p->from.sym = linksym(s);
p->from.name = D_EXTERN;
switch(a) {
case ATEXT:
p->reg = textflag;
textflag = 0;
break;
case AGLOBL:
p->reg = s->dataflag;
break;
}
if(s->class == CSTATIC)
p->from.name = D_STATIC;
naddr(n, &p->to);
if(a == ADATA || a == AGLOBL)
pc--;
}
void
gpcdata(int index, int value)
{
Node n1;
n1 = *nodconst(index);
gins(APCDATA, &n1, nodconst(value));
}
void
gprefetch(Node *n)
{
Node n1;
regalloc(&n1, n, Z);
gmove(n, &n1);
n1.op = OINDREG;
gins(APLD, &n1, Z);
regfree(&n1);
}
int
sconst(Node *n)
{
vlong vv;
if(n->op == OCONST) {
if(!typefd[n->type->etype]) {
vv = n->vconst;
if(vv >= (vlong)(-32766) && vv < (vlong)32766)
return 1;
/*
* should be specialised for constant values which will
* fit in different instructionsl; for now, let 5l
* sort it out
*/
return 1;
}
}
return 0;
}
int
sval(int32 v)
{
int i;
for(i=0; i<16; i++) {
if((v & ~0xff) == 0)
return 1;
if((~v & ~0xff) == 0)
return 1;
v = (v<<2) | ((uint32)v>>30);
}
return 0;
}
int32
exreg(Type *t)
{
int32 o;
if(typechlp[t->etype]) {
if(exregoffset <= REGEXT-4)
return 0;
o = exregoffset;
exregoffset--;
return o;
}
if(typefd[t->etype]) {
if(exfregoffset <= NFREG-1)
return 0;
o = exfregoffset + NREG;
exfregoffset--;
return o;
}
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] */
};