1
0
mirror of https://github.com/golang/go synced 2024-10-04 13:21:22 -06:00
go/src/cmd/6g/gen.c
Ken Thompson 8231e94520 now method/interface code
R=r
OCL=15627
CL=15627
2008-09-22 12:16:19 -07:00

1248 lines
21 KiB
C

// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#undef EXTERN
#define EXTERN
#include "gg.h"
enum
{
// random unused opcode
AJMPX = AADDPD,
};
void
compile(Node *fn)
{
Plist *pl;
Node nod1;
Prog *ptxt;
int32 lno;
if(newproc == N) {
newproc = nod(ONAME, N, N);
newproc->sym = pkglookup("newproc", "sys");
newproc->class = PEXTERN;
newproc->addable = 1;
newproc->ullman = 0;
}
if(throwindex == N) {
throwindex = nod(ONAME, N, N);
throwindex->sym = pkglookup("throwindex", "sys");
throwindex->class = PEXTERN;
throwindex->addable = 1;
throwindex->ullman = 0;
}
if(throwreturn == N) {
throwreturn = nod(ONAME, N, N);
throwreturn->sym = pkglookup("throwreturn", "sys");
throwreturn->class = PEXTERN;
throwreturn->addable = 1;
throwreturn->ullman = 0;
}
if(fn->nbody == N)
return;
// set up domain for labels
labellist = L;
lno = setlineno(fn);
curfn = fn;
dowidth(curfn->type);
walk(curfn);
if(nerrors != 0)
goto ret;
allocparams();
continpc = P;
breakpc = P;
pl = newplist();
pl->name = curfn->nname;
pl->locals = autodcl;
nodconst(&nod1, types[TINT32], 0);
ptxt = gins(ATEXT, curfn->nname, &nod1);
// inarggen();
ginit();
gen(curfn->nbody, L);
gclean();
checklabels();
if(curfn->type->outtuple != 0) {
gins(ACALL, N, throwreturn);
}
pc->as = ARET; // overwrite AEND
pc->lineno = lineno;
// fill in argument size
ptxt->to.offset = rnd(curfn->type->argwid, maxround);
// fill in final stack size
ptxt->to.offset <<= 32;
ptxt->to.offset |= rnd(stksize+maxarg, maxround);
if(debug['f'])
frame(0);
ret:
lineno = lno;
}
void
allocparams(void)
{
Dcl *d;
Iter list;
Type *t;
Node *n;
uint32 w;
/*
* allocate (set xoffset) the stack
* slots for all automatics.
* allocated starting at -w down.
*/
for(d=autodcl; d!=D; d=d->forw) {
if(d->op != ONAME)
continue;
n = d->dnode;
if(n->class != PAUTO)
continue;
dowidth(n->type);
w = n->type->width;
stksize += w;
stksize = rnd(stksize, w);
n->xoffset = -stksize;
}
}
/*
* compile statements
*/
void
gen(Node *n, Label *labloop)
{
int32 lno;
Prog *scontin, *sbreak;
Prog *p1, *p2, *p3;
Sym *s;
Node *l;
Label *lab;
lno = setlineno(n);
loop:
if(n == N)
goto ret;
if(n->ninit)
gen(n->ninit, L);
setlineno(n);
switch(n->op) {
default:
fatal("gen: unknown op %N", n);
break;
case OLIST:
l = n->left;
gen(l, L);
if(l != N && l->op == OLABEL) {
// call the next statement with a label
l = n->right;
if(l != N) {
if(l->op != OLIST) {
gen(l, labellist);
break;
}
gen(l->left, labellist);
n = l->right;
labloop = L;
goto loop;
}
}
n = n->right;
labloop = L;
goto loop;
case OPANIC:
genpanic();
break;
case OCASE:
case OFALL:
case OXCASE:
case OXFALL:
case OEMPTY:
break;
case OLABEL:
lab = mal(sizeof(*lab));
lab->link = labellist;
labellist = lab;
lab->sym = n->left->sym;
lab->op = OLABEL;
lab->label = pc;
break;
case OGOTO:
lab = mal(sizeof(*lab));
lab->link = labellist;
labellist = lab;
lab->sym = n->left->sym;
lab->op = OGOTO;
lab->label = pc;
gbranch(AJMP, T);
break;
case OBREAK:
if(n->left != N) {
lab = findlab(n->left->sym);
if(lab == L || lab->breakpc == P) {
yyerror("break label is not defined: %S", n->left->sym);
break;
}
patch(gbranch(AJMP, T), lab->breakpc);
break;
}
if(breakpc == P) {
yyerror("break is not in a loop");
break;
}
patch(gbranch(AJMP, T), breakpc);
break;
case OCONTINUE:
if(n->left != N) {
lab = findlab(n->left->sym);
if(lab == L || lab->continpc == P) {
yyerror("continue label is not defined: %S", n->left->sym);
break;
}
patch(gbranch(AJMP, T), lab->continpc);
break;
}
if(continpc == P) {
yyerror("gen: continue is not in a loop");
break;
}
patch(gbranch(AJMP, T), continpc);
break;
case OFOR:
p1 = gbranch(AJMP, T); // goto test
sbreak = breakpc;
breakpc = gbranch(AJMP, T); // break: goto done
scontin = continpc;
continpc = pc;
gen(n->nincr, L); // contin: incr
patch(p1, pc); // test:
if(n->ntest != N)
if(n->ntest->ninit != N)
gen(n->ntest->ninit, L);
bgen(n->ntest, 0, breakpc); // if(!test) goto break
if(labloop != L) {
labloop->op = OFOR;
labloop->continpc = continpc;
labloop->breakpc = breakpc;
}
gen(n->nbody, L); // body
patch(gbranch(AJMP, T), continpc); // goto contin
patch(breakpc, pc); // done:
continpc = scontin;
breakpc = sbreak;
break;
case OIF:
p1 = gbranch(AJMP, T); // goto test
p2 = gbranch(AJMP, T); // p2: goto else
patch(p1, pc); // test:
if(n->ntest != N)
if(n->ntest->ninit != N)
gen(n->ntest->ninit, L);
bgen(n->ntest, 0, p2); // if(!test) goto p2
gen(n->nbody, L); // then
p3 = gbranch(AJMP, T); // goto done
patch(p2, pc); // else:
gen(n->nelse, L); // else
patch(p3, pc); // done:
break;
case OSWITCH:
p1 = gbranch(AJMP, T); // goto test
sbreak = breakpc;
breakpc = gbranch(AJMP, T); // break: goto done
patch(p1, pc); // test:
if(labloop != L) {
labloop->op = OFOR;
labloop->breakpc = breakpc;
}
swgen(n); // switch(test) body
patch(breakpc, pc); // done:
breakpc = sbreak;
break;
case OSELECT:
sbreak = breakpc;
p1 = gbranch(AJMP, T); // goto test
breakpc = gbranch(AJMP, T); // break: goto done
patch(p1, pc); // test:
if(labloop != L) {
labloop->op = OFOR;
labloop->breakpc = breakpc;
}
gen(n->nbody, L); // select() body
patch(breakpc, pc); // done:
breakpc = sbreak;
break;
case OASOP:
cgen_asop(n);
break;
case OAS:
cgen_as(n->left, n->right, n->op);
break;
case OCALLMETH:
cgen_callmeth(n, 0);
break;
case OCALLINTER:
cgen_callinter(n, N, 0);
break;
case OCALL:
cgen_call(n, 0);
break;
case OPROC:
cgen_proc(n);
break;
case ORETURN:
cgen_ret(n);
break;
}
ret:
lineno = lno;
}
void
agen_inter(Node *n, Node *res)
{
Node nodo, nodr, nodt;
Node *var;
Sym *s;
char *e;
int32 o,lno;
lno = setlineno(n);
// stack offset
memset(&nodo, 0, sizeof(nodo));
nodo.op = OINDREG;
nodo.val.u.reg = D_SP;
nodo.addable = 1;
nodo.type = types[tptr];
// pointer register
regalloc(&nodr, types[tptr], res);
switch(n->op) {
default:
fatal("agen_inter %O\n", n->op);
// case OS2I:
// ifaces2i(*sigi, *sigs, i.map, i.s)
// i.s is input
// (i.map, i.s) is output
cgen(n->left, &nodr);
nodo.xoffset = 3*widthptr;
cgen_as(&nodo, &nodr, 0);
nodtypesig(&nodt, n->type);
agen(&nodt, &nodr);
nodo.xoffset = 0*widthptr;
cgen_as(&nodo, &nodr, 0);
nodtypesig(&nodt, n->left->type);
agen(&nodt, &nodr);
nodo.xoffset = 1*widthptr;
cgen_as(&nodo, &nodr, 0);
e = "ifaces2i";
if(maxarg < 4*widthptr)
maxarg = 4*widthptr;
o = 2*widthptr;
break;
// case OI2I:
// ifacei2i(*sigi, i.map, i.s)
// (i.map, i.s) is input
// (i.map, i.s) is output
nodo.xoffset = 1*widthptr;
if(!n->left->addable) {
var = nod(OXXX, N, N);
tempname(var, n->left->type);
cgen(n->left, var);
cgen(var, &nodo);
} else {
cgen(n->left, &nodo);
}
nodtypesig(&nodt, n->type);
agen(&nodt, &nodr);
nodo.xoffset = 0*widthptr;
cgen_as(&nodo, &nodr, 0);
e = "ifacei2i";
if(maxarg < 3*widthptr)
maxarg = 3*widthptr;
o = 1*widthptr;
break;
// case OI2S:
// ifacei2s(*sigs, i.map, i.s)
// (i.map, i.s) is input
// i.s is output
nodo.xoffset = 1*widthptr;
if(!n->left->addable) {
var = nod(OXXX, N, N);
tempname(var, n->left->type);
cgen(n->left, var);
cgen(var, &nodo);
} else {
cgen(n->left, &nodo);
}
nodtypesig(&nodt, n->type);
agen(&nodt, &nodr);
nodo.xoffset = 0*widthptr;
cgen_as(&nodo, &nodr, 0);
e = "ifacei2s";
if(maxarg < 3*widthptr)
maxarg = 3*widthptr;
o = 2*widthptr;
break;
}
s = pkglookup(e, "sys");
if(s->oname == N) {
s->oname = newname(s);
s->oname->class = PEXTERN;
}
gins(ACALL, N, s->oname);
nodo.xoffset = o;
gins(ALEAQ, &nodo, res);
regfree(&nodr);
lineno = lno;
}
void
swgen(Node *n)
{
Node *c1, *c2;
Node n1, tmp;
Case *s0, *se, *s;
Prog *p1, *dflt;
int32 lno;
int any;
Iter save1, save2;
// botch - put most of this code in
// walk. gen binary search for
// sequence of constant cases
lno = setlineno(n);
p1 = gbranch(AJMP, T);
s0 = C;
se = C;
// walk thru the body placing breaks
// and labels into the case statements
any = 0;
dflt = P;
c1 = listfirst(&save1, &n->nbody);
while(c1 != N) {
setlineno(c1);
if(c1->op != OCASE) {
if(s0 == C && dflt == P)
yyerror("unreachable statements in a switch");
gen(c1, L);
any = 1;
if(c1->op == OFALL)
any = 0;
c1 = listnext(&save1);
continue;
}
// put in the break between cases
if(any)
patch(gbranch(AJMP, T), breakpc);
any = 1;
// over case expressions
c2 = listfirst(&save2, &c1->left);
if(c2 == N)
dflt = pc;
while(c2 != N) {
s = mal(sizeof(*s));
if(s0 == C)
s0 = s;
else
se->slink = s;
se = s;
s->scase = c2; // case expression
s->sprog = pc; // where to go
c2 = listnext(&save2);
}
c1 = listnext(&save1);
}
lineno = lno;
if(any)
patch(gbranch(AJMP, T), breakpc);
patch(p1, pc);
if(n->ntest != N)
if(n->ntest->ninit != N)
gen(n->ntest->ninit, L);
tempname(&tmp, n->ntest->type);
cgen(n->ntest, &tmp);
for(s=s0; s!=C; s=s->slink) {
setlineno(s->scase);
memset(&n1, 0, sizeof(n1));
n1.op = OEQ;
n1.left = &tmp;
n1.right = s->scase;
walktype(&n1, Erv);
bgen(&n1, 1, s->sprog);
}
if(dflt != P) {
patch(gbranch(AJMP, T), dflt);
goto ret;
}
patch(gbranch(AJMP, T), breakpc);
ret:
lineno = lno;
}
void
inarggen(void)
{
fatal("inarggen");
}
void
genpanic(void)
{
Node n1, n2;
Prog *p;
nodconst(&n1, types[TINT64], 0xf0);
nodreg(&n2, types[TINT64], D_AX);
gins(AMOVL, &n1, &n2);
p = pc;
gins(AMOVQ, &n2, N);
p->to.type = D_INDIR+D_AX;
}
int
argsize(Type *t)
{
Iter save;
Type *fp;
int w, x;
w = 0;
fp = structfirst(&save, getoutarg(t));
while(fp != T) {
x = fp->width + fp->type->width;
if(x > w)
w = x;
fp = structnext(&save);
}
fp = funcfirst(&save, t);
while(fp != T) {
x = fp->width + fp->type->width;
if(x > w)
w = x;
fp = funcnext(&save);
}
w = (w+7) & ~7;
return w;
}
void
ginscall(Node *f, int proc)
{
Node reg, con;
if(proc) {
nodreg(&reg, types[TINT64], D_AX);
if(f->op != OREGISTER) {
gins(ALEAQ, f, &reg);
gins(APUSHQ, &reg, N);
} else
gins(APUSHQ, f, N);
nodconst(&con, types[TINT32], argsize(f->type));
gins(APUSHQ, &con, N);
gins(ACALL, N, newproc);
gins(APOPQ, N, &reg);
gins(APOPQ, N, &reg);
return;
}
gins(ACALL, N, f);
}
void
cgen_callinter(Node *n, Node *res, int proc)
{
Node *i, *f;
Node tmpi, nodo, nodr, nodsp;
i = n->left;
if(i->op != ODOTINTER)
fatal("cgen_callinter: not ODOTINTER %O", i->op);
f = i->right; // field
if(f->op != ONAME)
fatal("cgen_callinter: not ONAME %O", f->op);
i = i->left; // interface
if(!i->addable) {
tempname(&tmpi, i->type);
cgen(i, &tmpi);
i = &tmpi;
}
gen(n->right, L); // args
regalloc(&nodr, types[tptr], res);
regalloc(&nodo, types[tptr], &nodr);
nodo.op = OINDREG;
agen(i, &nodr); // REG = &inter
nodindreg(&nodsp, types[tptr], D_SP);
nodo.xoffset += widthptr;
cgen(&nodo, &nodsp); // 0(SP) = 8(REG) -- i.s
nodo.xoffset -= widthptr;
cgen(&nodo, &nodr); // REG = 0(REG) -- i.m
nodo.xoffset = n->left->xoffset + 4*widthptr;
cgen(&nodo, &nodr); // REG = 32+offset(REG) -- i.m->fun[f]
// BOTCH nodr.type = fntype;
ginscall(&nodr, proc);
regfree(&nodr);
regfree(&nodo);
setmaxarg(n->left->type);
}
void
cgen_callmeth(Node *n, int proc)
{
Node *l;
// generate a rewrite for method call
// (p.f)(...) goes to (f)(p,...)
l = n->left;
if(l->op != ODOTMETH)
fatal("cgen_callmeth: not dotmethod: %N");
n->op = OCALL;
n->left = n->left->right;
n->left->type = l->type;
if(n->left->op == ONAME)
n->left->class = PEXTERN;
cgen_call(n, proc);
}
void
cgen_call(Node *n, int proc)
{
Type *t;
Node nod, afun, regax;
if(n == N)
return;
if(n->left->ullman >= UINF) {
// if name involves a fn call
// precompute the address of the fn
tempname(&afun, types[tptr]);
if(isptr[n->left->type->etype])
cgen(n->left, &afun);
else
agen(n->left, &afun);
}
gen(n->right, L); // assign the args
t = n->left->type;
if(isptr[t->etype])
t = t->type;
setmaxarg(t);
// call tempname pointer
if(n->left->ullman >= UINF) {
regalloc(&nod, types[tptr], N);
cgen_as(&nod, &afun, 0);
nod.type = t;
ginscall(&nod, proc);
regfree(&nod);
goto ret;
}
// call pointer
if(isptr[n->left->type->etype]) {
regalloc(&nod, types[tptr], N);
cgen_as(&nod, n->left, 0);
nod.type = t;
ginscall(&nod, proc);
regfree(&nod);
goto ret;
}
// call direct
n->left->method = 1;
ginscall(n->left, proc);
ret:
;
}
void
cgen_proc(Node *n)
{
switch(n->left->op) {
default:
fatal("cgen_proc: unknown call %O", n->left->op);
case OCALLMETH:
cgen_callmeth(n->left, 1);
break;
case OCALLINTER:
cgen_callinter(n->left, N, 1);
break;
case OCALL:
cgen_call(n->left, 1);
break;
}
}
void
cgen_callret(Node *n, Node *res)
{
Node nod;
Type *fp, *t;
Iter flist;
t = n->left->type;
if(t->etype == TPTR32 || t->etype == TPTR64)
t = t->type;
fp = structfirst(&flist, getoutarg(t));
if(fp == T)
fatal("cgen_callret: nil");
memset(&nod, 0, sizeof(nod));
nod.op = OINDREG;
nod.val.u.reg = D_SP;
nod.addable = 1;
nod.xoffset = fp->width;
nod.type = fp->type;
cgen_as(res, &nod, 0);
}
void
cgen_aret(Node *n, Node *res)
{
Node nod1, nod2;
Type *fp, *t;
Iter flist;
t = n->left->type;
if(isptr[t->etype])
t = t->type;
fp = structfirst(&flist, getoutarg(t));
if(fp == T)
fatal("cgen_aret: nil");
memset(&nod1, 0, sizeof(nod1));
nod1.op = OINDREG;
nod1.val.u.reg = D_SP;
nod1.addable = 1;
nod1.xoffset = fp->width;
nod1.type = fp->type;
gins(ALEAQ, &nod1, res);
}
void
cgen_ret(Node *n)
{
gen(n->left, L); // copy out args
gins(ARET, N, N);
}
void
cgen_asop(Node *n)
{
Node n1, n2, n3, n4;
Node *nl, *nr;
int32 lno;
nl = n->left;
nr = n->right;
if(nr->ullman >= UINF && nl->ullman >= UINF) {
tempname(&n1, nr->type);
cgen(nr, &n1);
n2 = *n;
n2.right = &n1;
cgen_asop(&n2);
goto ret;
}
if(nr->ullman > nl->ullman) {
regalloc(&n2, nl->type, N);
cgen(nr, &n2);
igen(nl, &n1, N);
} else {
igen(nl, &n1, N);
regalloc(&n2, nl->type, N);
cgen(nr, &n2);
}
n3 = *n;
n3.left = &n1;
n3.right = &n2;
n3.op = n->etype;
regalloc(&n4, nr->type, N);
cgen(&n3, &n4);
gmove(&n4, &n1);
regfree(&n1);
regfree(&n2);
regfree(&n4);
ret:
;
}
void
cgen_as(Node *nl, Node *nr, int op)
{
Node nc, n1;
Type *tl;
uint32 w, c;
if(nl == N)
return;
tl = nl->type;
if(tl == T)
return;
if(nr == N || isnil(nr)) {
if(isfat(tl)) {
/* clear a fat object */
if(debug['g'])
dump("\nclearfat", nl);
w = nl->type->width;
if(w > 0)
gconreg(AMOVQ, 0, D_AX);
if(w > 0) {
nodreg(&n1, types[tptr], D_DI);
agen(nl, &n1);
gins(ACLD, N, N); // clear direction flag
}
c = w / 8;
if(c > 0) {
gconreg(AMOVQ, c, D_CX);
gins(AREP, N, N); // repeat
gins(ASTOSQ, N, N); // STOQ AL,*(DI)+
}
c = w % 8;
if(c > 0) {
gconreg(AMOVQ, c, D_CX);
gins(AREP, N, N); // repeat
gins(ASTOSB, N, N); // STOB AL,*(DI)+
}
goto ret;
}
/* invent a "zero" for the rhs */
nr = &nc;
memset(nr, 0, sizeof(*nr));
switch(tl->etype) {
default:
fatal("cgen_as: tl %T", tl);
break;
case TINT8:
case TUINT8:
case TINT16:
case TUINT16:
case TINT32:
case TUINT32:
case TINT64:
case TUINT64:
nr->val.u.xval = mal(sizeof(*nr->val.u.xval));
mpmovecfix(nr->val.u.xval, 0);
nr->val.ctype = CTINT;
break;
case TFLOAT32:
case TFLOAT64:
case TFLOAT80:
nr->val.u.fval = mal(sizeof(*nr->val.u.fval));
mpmovecflt(nr->val.u.fval, 0.0);
nr->val.ctype = CTFLT;
break;
case TBOOL:
nr->val.u.bval = 0;
nr->val.ctype = CTBOOL;
break;
case TPTR32:
case TPTR64:
nr->val.ctype = CTNIL;
break;
}
nr->op = OLITERAL;
nr->type = tl;
nr->addable = 1;
ullmancalc(nr);
}
cgen(nr, nl);
ret:
;
}
int
samereg(Node *a, Node *b)
{
if(a->op != OREGISTER)
return 0;
if(b->op != OREGISTER)
return 0;
if(a->val.u.reg != b->val.u.reg)
return 0;
return 1;
}
void
dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
{
int a;
Node n3;
Type *t;
t = nl->type;
if(t->width == 1) {
if(issigned[t->etype])
t = types[TINT32];
else
t = types[TUINT32];
}
a = optoas(op, t);
if(!issigned[t->etype]) {
nodconst(&n3, t, 0);
gmove(&n3, dx);
}
regalloc(&n3, nr->type, N);
if(nl->ullman >= nr->ullman) {
cgen(nl, ax);
if(issigned[t->etype])
gins(optoas(OFOR, t), N, N);
cgen(nr, &n3);
gins(a, &n3, N);
} else {
cgen(nr, &n3);
cgen(nl, ax);
if(issigned[t->etype])
gins(optoas(OFOR, t), N, N);
gins(a, &n3, N);
}
regfree(&n3);
if(op == ODIV)
gmove(ax, res);
else
gmove(dx, res);
}
/*
* this is hard because divide
* is done in a fixed numerator
* of combined DX:AX registers
*/
void
cgen_div(int op, Node *nl, Node *nr, Node *res)
{
Node ax, dx, n3, tmpax, tmpdx;
int a, rax, rdx;
rax = reg[D_AX];
rdx = reg[D_DX];
nodreg(&ax, types[TINT64], D_AX);
nodreg(&dx, types[TINT64], D_DX);
regalloc(&ax, nl->type, &ax);
regalloc(&dx, nl->type, &dx);
// clean out the AX register
if(rax && !samereg(res, &ax)) {
if(rdx && !samereg(res, &dx)) {
regalloc(&tmpdx, types[TINT64], N);
regalloc(&tmpax, types[TINT64], N);
regalloc(&n3, nl->type, N); // dest for div
gins(AMOVQ, &dx, &tmpdx);
gins(AMOVQ, &ax, &tmpax);
dodiv(op, nl, nr, &n3, &ax, &dx);
gins(AMOVQ, &tmpax, &ax);
gins(AMOVQ, &tmpdx, &dx);
gmove(&n3, res);
regfree(&tmpdx);
regfree(&tmpax);
regfree(&n3);
goto ret;
}
regalloc(&tmpax, types[TINT64], N);
regalloc(&n3, nl->type, N); // dest for div
gins(AMOVQ, &ax, &tmpax);
dodiv(op, nl, nr, &n3, &ax, &dx);
gins(AMOVQ, &tmpax, &ax);
gmove(&n3, res);
regfree(&tmpax);
regfree(&n3);
goto ret;
}
// clean out the DX register
if(rdx && !samereg(res, &dx)) {
regalloc(&tmpdx, types[TINT64], N);
regalloc(&n3, nl->type, N); // dest for div
gins(AMOVQ, &dx, &tmpdx);
dodiv(op, nl, nr, &n3, &ax, &dx);
gins(AMOVQ, &tmpdx, &dx);
gmove(&n3, res);
regfree(&tmpdx);
regfree(&n3);
goto ret;
}
dodiv(op, nl, nr, res, &ax, &dx);
ret:
regfree(&ax);
regfree(&dx);
}
/*
* this is hard because shift
* count is either constant
* or the CL register
*/
void
cgen_shift(int op, Node *nl, Node *nr, Node *res)
{
Node n1, n2, n3;
int a, rcl;
Prog *p1;
a = optoas(op, nl->type);
if(nr->op == OLITERAL) {
regalloc(&n1, nr->type, res);
cgen(nl, &n1);
gins(a, nr, &n1);
gmove(&n1, res);
regfree(&n1);
goto ret;
}
rcl = reg[D_CX];
nodreg(&n1, types[TINT64], D_CX);
regalloc(&n1, nr->type, &n1);
// clean out the CL register
if(rcl && !samereg(res, &n1)) {
regalloc(&n2, types[TINT64], N);
gins(AMOVQ, &n1, &n2);
regfree(&n1);
reg[D_CX] = 0;
cgen_shift(op, nl, nr, res);
reg[D_CX] = rcl;
gins(AMOVQ, &n2, &n1);
regfree(&n2);
goto ret;
}
regalloc(&n2, nl->type, res); // can one shift the CL register
if(nl->ullman >= nr->ullman) {
cgen(nl, &n2);
cgen(nr, &n1);
} else {
cgen(nr, &n1);
cgen(nl, &n2);
}
// test and fix up large shifts
nodconst(&n3, types[TUINT32], nl->type->width*8);
gins(optoas(OCMP, types[TUINT32]), &n1, &n3);
p1 = gbranch(optoas(OLT, types[TUINT32]), T);
if(op == ORSH && issigned[nl->type->etype]) {
nodconst(&n3, types[TUINT32], nl->type->width*8-1);
gins(a, &n3, &n2);
} else {
nodconst(&n3, nl->type, 0);
gmove(&n3, &n2);
}
patch(p1, pc);
gins(a, &n1, &n2);
gmove(&n2, res);
regfree(&n1);
regfree(&n2);
ret:
;
}
void
checklabels(void)
{
Label *l, *m;
Sym *s;
// // print the label list
// for(l=labellist; l!=L; l=l->link) {
// print("lab %O %S\n", l->op, l->sym);
// }
for(l=labellist; l!=L; l=l->link) {
switch(l->op) {
case OFOR:
case OLABEL:
// these are definitions -
s = l->sym;
for(m=labellist; m!=L; m=m->link) {
if(m->sym != s)
continue;
switch(m->op) {
case OFOR:
case OLABEL:
// these are definitions -
// look for redefinitions
if(l != m)
yyerror("label %S redefined", s);
break;
case OGOTO:
// these are references -
// patch to definition
patch(m->label, l->label);
m->sym = S; // mark done
break;
}
}
}
}
// diagnostic for all undefined references
for(l=labellist; l!=L; l=l->link)
if(l->op == OGOTO && l->sym != S)
yyerror("label %S not defined", l->sym);
}
Label*
findlab(Sym *s)
{
Label *l;
for(l=labellist; l!=L; l=l->link) {
if(l->sym != s)
continue;
if(l->op != OFOR)
continue;
return l;
}
return L;
}