mirror of
https://github.com/golang/go
synced 2024-11-20 06:44:40 -07:00
bb192d1399
For simplicity, only recognizes expressions of the exact form "(x << a) | (x >> b)" where x is a variable and a and b are integer constant expressions that add to x's bit width. Fixes #4629. $ cat rotate.c unsigned int rotate(unsigned int x) { x = (x << 3) | (x >> (sizeof(x) * 8 - 3)); return x; } ## BEFORE $ go tool 6c -S rotate.c (rotate.c:2) TEXT rotate+0(SB),$0-8 (rotate.c:2) MOVL x+0(FP),!!DX (rotate.c:4) MOVL DX,!!AX (rotate.c:4) SALL $3,!!AX (rotate.c:4) MOVL DX,!!CX (rotate.c:4) SHRL $29,!!CX (rotate.c:4) ORL CX,!!AX (rotate.c:5) RET ,!! (rotate.c:5) RET ,!! (rotate.c:5) END ,!! ## AFTER $ go tool 6c -S rotate.c (rotate.c:2) TEXT rotate+0(SB),$0-8 (rotate.c:4) MOVL x+0(FP),!!AX (rotate.c:4) ROLL $3,!!AX (rotate.c:5) RET ,!! (rotate.c:5) RET ,!! (rotate.c:5) END ,!! R=rsc, minux.ma CC=golang-dev https://golang.org/cl/7069056
1601 lines
29 KiB
C
1601 lines
29 KiB
C
// Inferno utils/6c/txt.c
|
|
// http://code.google.com/p/inferno-os/source/browse/utils/6c/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 = '6';
|
|
thestring = "amd64";
|
|
dodefine("_64BIT");
|
|
listinit();
|
|
nstring = 0;
|
|
mnstring = 0;
|
|
nrathole = 0;
|
|
pc = 0;
|
|
breakpc = -1;
|
|
continpc = -1;
|
|
cases = C;
|
|
firstp = P;
|
|
lastp = P;
|
|
tfield = types[TINT];
|
|
|
|
typeword = typechlvp;
|
|
typecmplx = typesu;
|
|
|
|
/* TO DO */
|
|
memmove(typechlpv, typechlp, sizeof(typechlpv));
|
|
typechlpv[TVLONG] = 1;
|
|
typechlpv[TUVLONG] = 1;
|
|
|
|
zprog.link = P;
|
|
zprog.as = AGOK;
|
|
zprog.from.type = D_NONE;
|
|
zprog.from.index = D_NONE;
|
|
zprog.from.scale = 0;
|
|
zprog.to = zprog.from;
|
|
|
|
lregnode.op = OREGISTER;
|
|
lregnode.class = CEXREG;
|
|
lregnode.reg = REGTMP;
|
|
lregnode.complex = 0;
|
|
lregnode.addable = 11;
|
|
lregnode.type = types[TLONG];
|
|
|
|
qregnode = lregnode;
|
|
qregnode.type = types[TVLONG];
|
|
|
|
constnode.op = OCONST;
|
|
constnode.class = CXXX;
|
|
constnode.complex = 0;
|
|
constnode.addable = 20;
|
|
constnode.type = types[TLONG];
|
|
|
|
vconstnode = constnode;
|
|
vconstnode.type = types[TVLONG];
|
|
|
|
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);
|
|
|
|
if(0)
|
|
com64init();
|
|
|
|
for(i=0; i<nelem(reg); i++) {
|
|
reg[i] = 1;
|
|
if(i >= D_AX && i <= D_R15 && i != D_SP)
|
|
reg[i] = 0;
|
|
if(i >= D_X0 && i <= D_X7)
|
|
reg[i] = 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
gclean(void)
|
|
{
|
|
int i;
|
|
Sym *s;
|
|
|
|
reg[D_SP]--;
|
|
for(i=D_AX; i<=D_R15; i++)
|
|
if(reg[i])
|
|
diag(Z, "reg %R left allocated", i);
|
|
for(i=D_X0; i<=D_X7; 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;
|
|
textflag = s->dataflag;
|
|
gpseudo(AGLOBL, s, nodconst(s->type->width));
|
|
textflag = 0;
|
|
}
|
|
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_R15; 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]) {
|
|
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 && typechlpv[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*
|
|
nodgconst(vlong v, Type *t)
|
|
{
|
|
if(!typev[t->etype])
|
|
return nodconst((int32)v);
|
|
vconstnode.vconst = v;
|
|
return &vconstnode;
|
|
}
|
|
|
|
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)
|
|
{
|
|
int et;
|
|
|
|
*n = qregnode;
|
|
n->reg = r;
|
|
if(nn != Z){
|
|
et = nn->type->etype;
|
|
if(!typefd[et] && nn->type->width <= SZ_LONG && 0)
|
|
n->type = typeu[et]? types[TUINT]: types[TINT];
|
|
else
|
|
n->type = nn->type;
|
|
//print("nodreg %s [%s]\n", tnames[et], tnames[n->type->etype]);
|
|
n->lineno = nn->lineno;
|
|
}
|
|
if(reg[r] == 0)
|
|
return 0;
|
|
if(nn != Z) {
|
|
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 TVLONG:
|
|
case TUVLONG:
|
|
case TIND:
|
|
if(o != Z && o->op == OREGISTER) {
|
|
i = o->reg;
|
|
if(i >= D_AX && i <= D_R15)
|
|
goto out;
|
|
}
|
|
for(i=D_AX; i<=D_R15; i++)
|
|
if(reg[i] == 0)
|
|
goto out;
|
|
diag(tn, "out of fixed registers");
|
|
goto err;
|
|
|
|
case TFLOAT:
|
|
case TDOUBLE:
|
|
if(o != Z && o->op == OREGISTER) {
|
|
i = o->reg;
|
|
if(i >= D_X0 && i <= D_X7)
|
|
goto out;
|
|
}
|
|
for(i=D_X0; i<=D_X7; i++)
|
|
if(reg[i] == 0)
|
|
goto out;
|
|
diag(tn, "out of float registers");
|
|
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 >= nelem(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, 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;
|
|
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
|
|
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_R15)
|
|
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_R15)
|
|
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;
|
|
if(typev[n->type->etype] || n->type->etype == TIND)
|
|
a->offset = n->vconst;
|
|
else
|
|
a->offset = convvtox(n->vconst, typeu[n->type->etype]? TULONG: TLONG);
|
|
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;
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
gcmp(int op, Node *n, vlong val)
|
|
{
|
|
Node *cn, nod;
|
|
|
|
cn = nodgconst(val, n->type);
|
|
if(!immconst(cn)){
|
|
regalloc(&nod, n, Z);
|
|
gmove(cn, &nod);
|
|
gopcode(op, n->type, n, &nod);
|
|
regfree(&nod);
|
|
}else
|
|
gopcode(op, n->type, n, cn);
|
|
}
|
|
|
|
#define CASE(a,b) ((a<<8)|(b<<0))
|
|
|
|
void
|
|
gmove(Node *f, Node *t)
|
|
{
|
|
int ft, tt, t64, a;
|
|
Node nod, nod1, nod2, nod3;
|
|
Prog *p1, *p2;
|
|
|
|
ft = f->type->etype;
|
|
tt = t->type->etype;
|
|
t64 = tt == TVLONG || tt == TUVLONG || tt == TIND;
|
|
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) {
|
|
/* TO DO: pick up special constants, possibly preloaded */
|
|
if(f->fconst == 0.0){
|
|
regalloc(&nod, t, t);
|
|
gins(AXORPD, &nod, &nod);
|
|
gmove(&nod, t);
|
|
regfree(&nod);
|
|
return;
|
|
}
|
|
}
|
|
/*
|
|
* load
|
|
*/
|
|
if(ft == TVLONG || ft == TUVLONG)
|
|
if(f->op == OCONST)
|
|
if(f->vconst > 0x7fffffffLL || f->vconst < -0x7fffffffLL)
|
|
if(t->op != OREGISTER) {
|
|
regalloc(&nod, f, Z);
|
|
gmove(f, &nod);
|
|
gmove(&nod, t);
|
|
regfree(&nod);
|
|
return;
|
|
}
|
|
|
|
if(f->op == ONAME || f->op == OINDREG ||
|
|
f->op == OIND || f->op == OINDEX)
|
|
switch(ft) {
|
|
case TCHAR:
|
|
a = AMOVBLSX;
|
|
if(t64)
|
|
a = AMOVBQSX;
|
|
goto ld;
|
|
case TUCHAR:
|
|
a = AMOVBLZX;
|
|
if(t64)
|
|
a = AMOVBQZX;
|
|
goto ld;
|
|
case TSHORT:
|
|
a = AMOVWLSX;
|
|
if(t64)
|
|
a = AMOVWQSX;
|
|
goto ld;
|
|
case TUSHORT:
|
|
a = AMOVWLZX;
|
|
if(t64)
|
|
a = AMOVWQZX;
|
|
goto ld;
|
|
case TINT:
|
|
case TLONG:
|
|
if(typefd[tt]) {
|
|
regalloc(&nod, t, t);
|
|
if(tt == TDOUBLE)
|
|
a = ACVTSL2SD;
|
|
else
|
|
a = ACVTSL2SS;
|
|
gins(a, f, &nod);
|
|
gmove(&nod, t);
|
|
regfree(&nod);
|
|
return;
|
|
}
|
|
a = AMOVL;
|
|
if(t64)
|
|
a = AMOVLQSX;
|
|
goto ld;
|
|
case TUINT:
|
|
case TULONG:
|
|
a = AMOVL;
|
|
if(t64)
|
|
a = AMOVLQZX; /* could probably use plain MOVL */
|
|
goto ld;
|
|
case TVLONG:
|
|
if(typefd[tt]) {
|
|
regalloc(&nod, t, t);
|
|
if(tt == TDOUBLE)
|
|
a = ACVTSQ2SD;
|
|
else
|
|
a = ACVTSQ2SS;
|
|
gins(a, f, &nod);
|
|
gmove(&nod, t);
|
|
regfree(&nod);
|
|
return;
|
|
}
|
|
case TUVLONG:
|
|
a = AMOVQ;
|
|
goto ld;
|
|
case TIND:
|
|
a = AMOVQ;
|
|
|
|
ld:
|
|
regalloc(&nod, f, t);
|
|
nod.type = t64? types[TVLONG]: types[TINT];
|
|
gins(a, f, &nod);
|
|
gmove(&nod, t);
|
|
regfree(&nod);
|
|
return;
|
|
|
|
case TFLOAT:
|
|
a = AMOVSS;
|
|
goto fld;
|
|
case TDOUBLE:
|
|
a = AMOVSD;
|
|
fld:
|
|
regalloc(&nod, f, t);
|
|
if(tt != TDOUBLE && tt != TFLOAT){ /* TO DO: why is this here */
|
|
prtree(f, "odd tree");
|
|
nod.type = t64? types[TVLONG]: types[TINT];
|
|
}
|
|
gins(a, f, &nod);
|
|
gmove(&nod, t);
|
|
regfree(&nod);
|
|
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:
|
|
a = AMOVL; goto st;
|
|
case TVLONG:
|
|
case TUVLONG:
|
|
case TIND:
|
|
a = AMOVQ; goto st;
|
|
|
|
st:
|
|
if(f->op == OCONST) {
|
|
gins(a, f, t);
|
|
return;
|
|
}
|
|
fst:
|
|
regalloc(&nod, t, f);
|
|
gmove(f, &nod);
|
|
gins(a, &nod, t);
|
|
regfree(&nod);
|
|
return;
|
|
|
|
case TFLOAT:
|
|
a = AMOVSS;
|
|
goto fst;
|
|
case TDOUBLE:
|
|
a = AMOVSD;
|
|
goto fst;
|
|
}
|
|
|
|
/*
|
|
* 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( 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( TSHORT, TSHORT):
|
|
case CASE( TUSHORT,TSHORT):
|
|
case CASE( TINT, TSHORT):
|
|
case CASE( TUINT, TSHORT):
|
|
case CASE( TLONG, TSHORT):
|
|
case CASE( TULONG, 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( TINT, TINT):
|
|
case CASE( TUINT, TINT):
|
|
case CASE( TLONG, TINT):
|
|
case CASE( TULONG, TINT):
|
|
|
|
case CASE( TINT, TUINT):
|
|
case CASE( TUINT, TUINT):
|
|
case CASE( TLONG, TUINT):
|
|
case CASE( TULONG, TUINT):
|
|
*****/
|
|
a = AMOVL;
|
|
break;
|
|
|
|
case CASE( TINT, TIND):
|
|
case CASE( TINT, TVLONG):
|
|
case CASE( TINT, TUVLONG):
|
|
case CASE( TLONG, TIND):
|
|
case CASE( TLONG, TVLONG):
|
|
case CASE( TLONG, TUVLONG):
|
|
a = AMOVLQSX;
|
|
if(f->op == OCONST) {
|
|
f->vconst &= (uvlong)0xffffffffU;
|
|
if(f->vconst & 0x80000000)
|
|
f->vconst |= (vlong)0xffffffff << 32;
|
|
a = AMOVQ;
|
|
}
|
|
break;
|
|
|
|
case CASE( TUINT, TIND):
|
|
case CASE( TUINT, TVLONG):
|
|
case CASE( TUINT, TUVLONG):
|
|
case CASE( TULONG, TVLONG):
|
|
case CASE( TULONG, TUVLONG):
|
|
case CASE( TULONG, TIND):
|
|
a = AMOVLQZX;
|
|
if(f->op == OCONST) {
|
|
f->vconst &= (uvlong)0xffffffffU;
|
|
a = AMOVQ;
|
|
}
|
|
break;
|
|
|
|
case CASE( TIND, TCHAR):
|
|
case CASE( TIND, TUCHAR):
|
|
case CASE( TIND, TSHORT):
|
|
case CASE( TIND, TUSHORT):
|
|
case CASE( TIND, TINT):
|
|
case CASE( TIND, TUINT):
|
|
case CASE( TIND, TLONG):
|
|
case CASE( TIND, TULONG):
|
|
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( TUVLONG, TCHAR):
|
|
case CASE( TUVLONG, TUCHAR):
|
|
case CASE( TUVLONG, TSHORT):
|
|
case CASE( TUVLONG, TUSHORT):
|
|
case CASE( TUVLONG, TINT):
|
|
case CASE( TUVLONG, TUINT):
|
|
case CASE( TUVLONG, TLONG):
|
|
case CASE( TUVLONG, TULONG):
|
|
a = AMOVQL;
|
|
if(f->op == OCONST) {
|
|
f->vconst &= (int)0xffffffffU;
|
|
a = AMOVL;
|
|
}
|
|
break;
|
|
|
|
case CASE( TIND, TIND):
|
|
case CASE( TIND, TVLONG):
|
|
case CASE( TIND, TUVLONG):
|
|
case CASE( TVLONG, TIND):
|
|
case CASE( TVLONG, TVLONG):
|
|
case CASE( TVLONG, TUVLONG):
|
|
case CASE( TUVLONG, TIND):
|
|
case CASE( TUVLONG, TVLONG):
|
|
case CASE( TUVLONG, TUVLONG):
|
|
a = AMOVQ;
|
|
break;
|
|
|
|
case CASE( TSHORT, TINT):
|
|
case CASE( TSHORT, TUINT):
|
|
case CASE( TSHORT, TLONG):
|
|
case CASE( TSHORT, TULONG):
|
|
a = AMOVWLSX;
|
|
if(f->op == OCONST) {
|
|
f->vconst &= 0xffff;
|
|
if(f->vconst & 0x8000)
|
|
f->vconst |= 0xffff0000;
|
|
a = AMOVL;
|
|
}
|
|
break;
|
|
|
|
case CASE( TSHORT, TVLONG):
|
|
case CASE( TSHORT, TUVLONG):
|
|
case CASE( TSHORT, TIND):
|
|
a = AMOVWQSX;
|
|
if(f->op == OCONST) {
|
|
f->vconst &= 0xffff;
|
|
if(f->vconst & 0x8000){
|
|
f->vconst |= 0xffff0000;
|
|
f->vconst |= (vlong)~0 << 32;
|
|
}
|
|
a = AMOVL;
|
|
}
|
|
break;
|
|
|
|
case CASE( TUSHORT,TINT):
|
|
case CASE( TUSHORT,TUINT):
|
|
case CASE( TUSHORT,TLONG):
|
|
case CASE( TUSHORT,TULONG):
|
|
a = AMOVWLZX;
|
|
if(f->op == OCONST) {
|
|
f->vconst &= 0xffff;
|
|
a = AMOVL;
|
|
}
|
|
break;
|
|
|
|
case CASE( TUSHORT,TVLONG):
|
|
case CASE( TUSHORT,TUVLONG):
|
|
case CASE( TUSHORT,TIND):
|
|
a = AMOVWQZX;
|
|
if(f->op == OCONST) {
|
|
f->vconst &= 0xffff;
|
|
a = AMOVL; /* MOVL also zero-extends to 64 bits */
|
|
}
|
|
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):
|
|
a = AMOVBLSX;
|
|
if(f->op == OCONST) {
|
|
f->vconst &= 0xff;
|
|
if(f->vconst & 0x80)
|
|
f->vconst |= 0xffffff00;
|
|
a = AMOVL;
|
|
}
|
|
break;
|
|
|
|
case CASE( TCHAR, TVLONG):
|
|
case CASE( TCHAR, TUVLONG):
|
|
case CASE( TCHAR, TIND):
|
|
a = AMOVBQSX;
|
|
if(f->op == OCONST) {
|
|
f->vconst &= 0xff;
|
|
if(f->vconst & 0x80){
|
|
f->vconst |= 0xffffff00;
|
|
f->vconst |= (vlong)~0 << 32;
|
|
}
|
|
a = AMOVQ;
|
|
}
|
|
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):
|
|
a = AMOVBLZX;
|
|
if(f->op == OCONST) {
|
|
f->vconst &= 0xff;
|
|
a = AMOVL;
|
|
}
|
|
break;
|
|
|
|
case CASE( TUCHAR, TVLONG):
|
|
case CASE( TUCHAR, TUVLONG):
|
|
case CASE( TUCHAR, TIND):
|
|
a = AMOVBQZX;
|
|
if(f->op == OCONST) {
|
|
f->vconst &= 0xff;
|
|
a = AMOVL; /* zero-extends to 64-bits */
|
|
}
|
|
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, TVLONG):
|
|
case CASE( TFLOAT, TUVLONG):
|
|
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,TVLONG):
|
|
case CASE( TDOUBLE,TUVLONG):
|
|
case CASE( TDOUBLE,TIND):
|
|
regalloc(&nod, t, Z);
|
|
if(ewidth[tt] == SZ_VLONG || typeu[tt] && ewidth[tt] == SZ_INT){
|
|
if(ft == TFLOAT)
|
|
a = ACVTTSS2SQ;
|
|
else
|
|
a = ACVTTSD2SQ;
|
|
}else{
|
|
if(ft == TFLOAT)
|
|
a = ACVTTSS2SL;
|
|
else
|
|
a = ACVTTSD2SL;
|
|
}
|
|
gins(a, f, &nod);
|
|
gmove(&nod, t);
|
|
regfree(&nod);
|
|
return;
|
|
|
|
/*
|
|
* uvlong to float
|
|
*/
|
|
case CASE( TUVLONG, TDOUBLE):
|
|
case CASE( TUVLONG, TFLOAT):
|
|
a = ACVTSQ2SS;
|
|
if(tt == TDOUBLE)
|
|
a = ACVTSQ2SD;
|
|
regalloc(&nod, f, f);
|
|
gmove(f, &nod);
|
|
regalloc(&nod1, t, t);
|
|
gins(ACMPQ, &nod, nodconst(0));
|
|
gins(AJLT, Z, Z);
|
|
p1 = p;
|
|
gins(a, &nod, &nod1);
|
|
gins(AJMP, Z, Z);
|
|
p2 = p;
|
|
patch(p1, pc);
|
|
regalloc(&nod2, f, Z);
|
|
regalloc(&nod3, f, Z);
|
|
gmove(&nod, &nod2);
|
|
gins(ASHRQ, nodconst(1), &nod2);
|
|
gmove(&nod, &nod3);
|
|
gins(AANDL, nodconst(1), &nod3);
|
|
gins(AORQ, &nod3, &nod2);
|
|
gins(a, &nod2, &nod1);
|
|
gins(tt == TDOUBLE? AADDSD: AADDSS, &nod1, &nod1);
|
|
regfree(&nod2);
|
|
regfree(&nod3);
|
|
patch(p2, pc);
|
|
regfree(&nod);
|
|
regfree(&nod1);
|
|
return;
|
|
|
|
case CASE( TULONG, TDOUBLE):
|
|
case CASE( TUINT, TDOUBLE):
|
|
case CASE( TULONG, TFLOAT):
|
|
case CASE( TUINT, TFLOAT):
|
|
a = ACVTSQ2SS;
|
|
if(tt == TDOUBLE)
|
|
a = ACVTSQ2SD;
|
|
regalloc(&nod, f, f);
|
|
gins(AMOVLQZX, f, &nod);
|
|
regalloc(&nod1, t, t);
|
|
gins(a, &nod, &nod1);
|
|
gmove(&nod1, t);
|
|
regfree(&nod);
|
|
regfree(&nod1);
|
|
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( TVLONG, 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( TVLONG, TDOUBLE):
|
|
case CASE( TIND, TDOUBLE):
|
|
regalloc(&nod, t, t);
|
|
if(ewidth[ft] == SZ_VLONG){
|
|
if(tt == TFLOAT)
|
|
a = ACVTSQ2SS;
|
|
else
|
|
a = ACVTSQ2SD;
|
|
}else{
|
|
if(tt == TFLOAT)
|
|
a = ACVTSL2SS;
|
|
else
|
|
a = ACVTSL2SD;
|
|
}
|
|
gins(a, f, &nod);
|
|
gmove(&nod, t);
|
|
regfree(&nod);
|
|
return;
|
|
|
|
/*
|
|
* float to float
|
|
*/
|
|
case CASE( TFLOAT, TFLOAT):
|
|
a = AMOVSS;
|
|
break;
|
|
case CASE( TDOUBLE,TFLOAT):
|
|
a = ACVTSD2SS;
|
|
break;
|
|
case CASE( TFLOAT, TDOUBLE):
|
|
a = ACVTSS2SD;
|
|
break;
|
|
case CASE( TDOUBLE,TDOUBLE):
|
|
a = AMOVSD;
|
|
break;
|
|
}
|
|
if(a == AMOVQ || a == AMOVSD || a == AMOVSS || a == AMOVL && ewidth[ft] == ewidth[tt]) /* TO DO: check AMOVL */
|
|
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, &qregnode, 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, &qregnode, 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
|
|
gopcode(int o, Type *ty, Node *f, Node *t)
|
|
{
|
|
int a, et;
|
|
|
|
et = TLONG;
|
|
if(ty != T)
|
|
et = ty->etype;
|
|
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;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = ANOTQ;
|
|
break;
|
|
|
|
case ONEG:
|
|
a = ANEGL;
|
|
if(et == TCHAR || et == TUCHAR)
|
|
a = ANEGB;
|
|
if(et == TSHORT || et == TUSHORT)
|
|
a = ANEGW;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = ANEGQ;
|
|
break;
|
|
|
|
case OADDR:
|
|
a = ALEAQ;
|
|
break;
|
|
|
|
case OASADD:
|
|
case OADD:
|
|
a = AADDL;
|
|
if(et == TCHAR || et == TUCHAR)
|
|
a = AADDB;
|
|
if(et == TSHORT || et == TUSHORT)
|
|
a = AADDW;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = AADDQ;
|
|
if(et == TFLOAT)
|
|
a = AADDSS;
|
|
if(et == TDOUBLE)
|
|
a = AADDSD;
|
|
break;
|
|
|
|
case OASSUB:
|
|
case OSUB:
|
|
a = ASUBL;
|
|
if(et == TCHAR || et == TUCHAR)
|
|
a = ASUBB;
|
|
if(et == TSHORT || et == TUSHORT)
|
|
a = ASUBW;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = ASUBQ;
|
|
if(et == TFLOAT)
|
|
a = ASUBSS;
|
|
if(et == TDOUBLE)
|
|
a = ASUBSD;
|
|
break;
|
|
|
|
case OASOR:
|
|
case OOR:
|
|
a = AORL;
|
|
if(et == TCHAR || et == TUCHAR)
|
|
a = AORB;
|
|
if(et == TSHORT || et == TUSHORT)
|
|
a = AORW;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = AORQ;
|
|
break;
|
|
|
|
case OASAND:
|
|
case OAND:
|
|
a = AANDL;
|
|
if(et == TCHAR || et == TUCHAR)
|
|
a = AANDB;
|
|
if(et == TSHORT || et == TUSHORT)
|
|
a = AANDW;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = AANDQ;
|
|
break;
|
|
|
|
case OASXOR:
|
|
case OXOR:
|
|
a = AXORL;
|
|
if(et == TCHAR || et == TUCHAR)
|
|
a = AXORB;
|
|
if(et == TSHORT || et == TUSHORT)
|
|
a = AXORW;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = AXORQ;
|
|
break;
|
|
|
|
case OASLSHR:
|
|
case OLSHR:
|
|
a = ASHRL;
|
|
if(et == TCHAR || et == TUCHAR)
|
|
a = ASHRB;
|
|
if(et == TSHORT || et == TUSHORT)
|
|
a = ASHRW;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = ASHRQ;
|
|
break;
|
|
|
|
case OASASHR:
|
|
case OASHR:
|
|
a = ASARL;
|
|
if(et == TCHAR || et == TUCHAR)
|
|
a = ASARB;
|
|
if(et == TSHORT || et == TUSHORT)
|
|
a = ASARW;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = ASARQ;
|
|
break;
|
|
|
|
case OASASHL:
|
|
case OASHL:
|
|
a = ASALL;
|
|
if(et == TCHAR || et == TUCHAR)
|
|
a = ASALB;
|
|
if(et == TSHORT || et == TUSHORT)
|
|
a = ASALW;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = ASALQ;
|
|
break;
|
|
|
|
case OROTL:
|
|
a = AROLL;
|
|
if(et == TCHAR || et == TUCHAR)
|
|
a = AROLB;
|
|
if(et == TSHORT || et == TUSHORT)
|
|
a = AROLW;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = AROLQ;
|
|
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;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = AIMULQ;
|
|
if(et == TFLOAT)
|
|
a = AMULSS;
|
|
if(et == TDOUBLE)
|
|
a = AMULSD;
|
|
break;
|
|
|
|
case OASMOD:
|
|
case OMOD:
|
|
case OASDIV:
|
|
case ODIV:
|
|
a = AIDIVL;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = AIDIVQ;
|
|
if(et == TFLOAT)
|
|
a = ADIVSS;
|
|
if(et == TDOUBLE)
|
|
a = ADIVSD;
|
|
break;
|
|
|
|
case OASLMUL:
|
|
case OLMUL:
|
|
a = AMULL;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = AMULQ;
|
|
break;
|
|
|
|
case OASLMOD:
|
|
case OLMOD:
|
|
case OASLDIV:
|
|
case OLDIV:
|
|
a = ADIVL;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = ADIVQ;
|
|
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;
|
|
if(et == TVLONG || et == TUVLONG || et == TIND)
|
|
a = ACMPQ;
|
|
if(et == TFLOAT)
|
|
a = AUCOMISS;
|
|
if(et == TDOUBLE)
|
|
a = AUCOMISD;
|
|
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)
|
|
{
|
|
return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg;
|
|
}
|
|
|
|
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--;
|
|
}
|
|
|
|
void
|
|
gprefetch(Node *n)
|
|
{
|
|
Node n1;
|
|
|
|
regalloc(&n1, n, Z);
|
|
gmove(n, &n1);
|
|
n1.op = OINDREG;
|
|
gins(APREFETCHNTA, &n1, Z);
|
|
regfree(&n1);
|
|
}
|
|
|
|
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(typechlpv[t->etype]) {
|
|
if(exregoffset >= 64)
|
|
return 0;
|
|
o = exregoffset;
|
|
exregoffset += 8;
|
|
return o+1; // +1 to avoid 0 == failure; naddr's case OEXREG will subtract 1.
|
|
}
|
|
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, /*[TINT]*/
|
|
BINT|BUINT|BLONG|BULONG, /*[TUINT]*/
|
|
BINT|BUINT|BLONG|BULONG, /*[TLONG]*/
|
|
BINT|BUINT|BLONG|BULONG, /*[TULONG]*/
|
|
BVLONG|BUVLONG|BIND, /*[TVLONG]*/
|
|
BVLONG|BUVLONG|BIND, /*[TUVLONG]*/
|
|
BFLOAT, /*[TFLOAT]*/
|
|
BDOUBLE, /*[TDOUBLE]*/
|
|
BVLONG|BUVLONG|BIND, /*[TIND]*/
|
|
0, /*[TFUNC]*/
|
|
0, /*[TARRAY]*/
|
|
0, /*[TVOID]*/
|
|
BSTRUCT, /*[TSTRUCT]*/
|
|
BUNION, /*[TUNION]*/
|
|
0, /*[TENUM]*/
|
|
};
|