mirror of
https://github.com/golang/go.git
synced 2025-05-31 23:25:39 +00:00
cmd/gc: factor newly-portable code into gc directory
This isn't everything, but it's a start. Still producing bit-identical compiler output. The semantics of the old back ends is preserved, even when they are probably buggy. There are some TODOs in gc/gsubr.c to remove special cases to preserve bugs in 5g and 8g. Change-Id: I28ae295fbfc94ef9df43e13ab96bd6fc2f194bc4 Reviewed-on: https://go-review.googlesource.com/3802 Reviewed-by: Austin Clements <austin@google.com>
This commit is contained in:
parent
81a3f291f0
commit
eb1774fa19
@ -277,6 +277,9 @@ enum {
|
||||
A_ARCHSPECIFIC, // first architecture-specific opcode value
|
||||
};
|
||||
|
||||
void nopout(Prog*);
|
||||
void nocache(Prog*);
|
||||
|
||||
// prevent incompatible type signatures between liblink and 8l on Plan 9
|
||||
#pragma incomplete struct Section
|
||||
|
||||
|
@ -46,8 +46,9 @@ main(int argc, char **argv)
|
||||
arch.thestring = thestring;
|
||||
arch.thelinkarch = thelinkarch;
|
||||
arch.typedefs = typedefs;
|
||||
arch.REGSP = REGSP;
|
||||
arch.REGCTXT = REGCTXT;
|
||||
arch.MAXWIDTH = MAXWIDTH;
|
||||
arch.afunclit = afunclit;
|
||||
arch.anyregalloc = anyregalloc;
|
||||
arch.betypeinit = betypeinit;
|
||||
arch.bgen = bgen;
|
||||
@ -57,37 +58,15 @@ main(int argc, char **argv)
|
||||
arch.cgen_callinter = cgen_callinter;
|
||||
arch.cgen_ret = cgen_ret;
|
||||
arch.clearfat = clearfat;
|
||||
arch.clearp = clearp;
|
||||
arch.defframe = defframe;
|
||||
arch.dgostringptr = dgostringptr;
|
||||
arch.dgostrlitptr = dgostrlitptr;
|
||||
arch.dsname = dsname;
|
||||
arch.dsymptr = dsymptr;
|
||||
arch.dumpdata = dumpdata;
|
||||
arch.dumpit = dumpit;
|
||||
arch.excise = excise;
|
||||
arch.expandchecks = expandchecks;
|
||||
arch.fixautoused = fixautoused;
|
||||
arch.gclean = gclean;
|
||||
arch.gdata = gdata;
|
||||
arch.gdatacomplex = gdatacomplex;
|
||||
arch.gdatastring = gdatastring;
|
||||
arch.ggloblnod = ggloblnod;
|
||||
arch.ggloblsym = ggloblsym;
|
||||
arch.ginit = ginit;
|
||||
arch.gins = gins;
|
||||
arch.ginscall = ginscall;
|
||||
arch.gjmp = gjmp;
|
||||
arch.gtrack = gtrack;
|
||||
arch.gused = gused;
|
||||
arch.igen = igen;
|
||||
arch.isfat = isfat;
|
||||
arch.linkarchinit = linkarchinit;
|
||||
arch.markautoused = markautoused;
|
||||
arch.naddr = naddr;
|
||||
arch.newplist = newplist;
|
||||
arch.nodarg = nodarg;
|
||||
arch.patch = patch;
|
||||
arch.proginfo = proginfo;
|
||||
arch.regalloc = regalloc;
|
||||
arch.regfree = regfree;
|
||||
@ -96,7 +75,6 @@ main(int argc, char **argv)
|
||||
arch.sameaddr = sameaddr;
|
||||
arch.smallindir = smallindir;
|
||||
arch.stackaddr = stackaddr;
|
||||
arch.unpatch = unpatch;
|
||||
|
||||
gcmain(argc, argv);
|
||||
}
|
||||
|
@ -17,10 +17,7 @@ enum
|
||||
REGALLOC_FMAX = FREGEXT,
|
||||
};
|
||||
|
||||
EXTERN int32 dynloc;
|
||||
EXTERN uchar reg[REGALLOC_FMAX+1];
|
||||
EXTERN int32 pcloc; // instruction counter
|
||||
EXTERN Strlit emptystring;
|
||||
extern long unmappedzero;
|
||||
|
||||
/*
|
||||
|
@ -117,52 +117,6 @@ appendpp(Prog *p, int as, int ftype, int freg, int32 foffset, int ttype, int tre
|
||||
return q;
|
||||
}
|
||||
|
||||
// Sweep the prog list to mark any used nodes.
|
||||
void
|
||||
markautoused(Prog* p)
|
||||
{
|
||||
for (; p; p = p->link) {
|
||||
if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
|
||||
continue;
|
||||
|
||||
if (p->from.node)
|
||||
((Node*)(p->from.node))->used = 1;
|
||||
|
||||
if (p->to.node)
|
||||
((Node*)(p->to.node))->used = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
|
||||
void
|
||||
fixautoused(Prog* p)
|
||||
{
|
||||
Prog **lp;
|
||||
|
||||
for (lp=&p; (p=*lp) != P; ) {
|
||||
if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
|
||||
*lp = p->link;
|
||||
continue;
|
||||
}
|
||||
if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
|
||||
// Cannot remove VARDEF instruction, because - unlike TYPE handled above -
|
||||
// VARDEFs are interspersed with other code, and a jump might be using the
|
||||
// VARDEF as a target. Replace with a no-op instead. A later pass will remove
|
||||
// the no-ops.
|
||||
nopout(p);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p->from.name == NAME_AUTO && p->from.node)
|
||||
p->from.offset += ((Node*)(p->from.node))->stkdelta;
|
||||
|
||||
if (p->to.name == NAME_AUTO && p->to.node)
|
||||
p->to.offset += ((Node*)(p->to.node))->stkdelta;
|
||||
|
||||
lp = &p->link;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* generate:
|
||||
* call f
|
||||
@ -176,7 +130,7 @@ void
|
||||
ginscall(Node *f, int proc)
|
||||
{
|
||||
Prog *p;
|
||||
Node n1, r, r1, con;
|
||||
Node r, r1, con;
|
||||
int32 extra;
|
||||
|
||||
if(f->type != T) {
|
||||
@ -238,10 +192,7 @@ ginscall(Node *f, int proc)
|
||||
p->to.reg = REGSP;
|
||||
p->to.offset = 4;
|
||||
|
||||
memset(&n1, 0, sizeof n1);
|
||||
n1.op = OADDR;
|
||||
n1.left = f;
|
||||
gins(AMOVW, &n1, &r);
|
||||
gins(AMOVW, f, &r);
|
||||
p = gins(AMOVW, &r, N);
|
||||
p->to.type = TYPE_MEM;
|
||||
p->to.reg = REGSP;
|
||||
@ -615,18 +566,6 @@ 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate high multiply
|
||||
* res = (nl * nr) >> wordsize
|
||||
|
@ -1,267 +0,0 @@
|
||||
// Derived from Inferno utils/5c/swt.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.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 <u.h>
|
||||
#include <libc.h>
|
||||
#include "gg.h"
|
||||
|
||||
int
|
||||
dsname(Sym *sym, int off, char *t, int n)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.etype = TINT32;
|
||||
p->from.offset = off;
|
||||
p->from.reg = 0;
|
||||
p->from.sym = linksym(sym);
|
||||
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = n;
|
||||
|
||||
p->to.type = TYPE_SCONST;
|
||||
p->to.name = NAME_NONE;
|
||||
p->to.reg = 0;
|
||||
p->to.offset = 0;
|
||||
memmove(p->to.u.sval, t, n);
|
||||
return off + n;
|
||||
}
|
||||
|
||||
/*
|
||||
* make a refer to the data s, s+len
|
||||
* emitting DATA if needed.
|
||||
*/
|
||||
void
|
||||
datastring(char *s, int len, Addr *a)
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
sym = stringsym(s, len);
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_EXTERN;
|
||||
a->etype = TINT32;
|
||||
a->offset = widthptr+4; // skip header
|
||||
a->reg = 0;
|
||||
a->sym = linksym(sym);
|
||||
a->node = sym->def;
|
||||
}
|
||||
|
||||
/*
|
||||
* make a refer to the string sval,
|
||||
* emitting DATA if needed.
|
||||
*/
|
||||
void
|
||||
datagostring(Strlit *sval, Addr *a)
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
sym = stringsym(sval->s, sval->len);
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_EXTERN;
|
||||
a->etype = TSTRING;
|
||||
a->offset = 0; // header
|
||||
a->reg = 0;
|
||||
a->sym = linksym(sym);
|
||||
a->node = sym->def;
|
||||
}
|
||||
|
||||
void
|
||||
gdata(Node *nam, Node *nr, int wid)
|
||||
{
|
||||
Prog *p;
|
||||
vlong v;
|
||||
|
||||
if(nr->op == OLITERAL) {
|
||||
switch(nr->val.ctype) {
|
||||
case CTCPLX:
|
||||
gdatacomplex(nam, nr->val.u.cval);
|
||||
return;
|
||||
case CTSTR:
|
||||
gdatastring(nam, nr->val.u.sval);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(wid == 8 && is64(nr->type)) {
|
||||
v = mpgetfix(nr->val.u.xval);
|
||||
p = gins(ADATA, nam, nodintconst(v));
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = 4;
|
||||
p = gins(ADATA, nam, nodintconst(v>>32));
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = 4;
|
||||
p->from.offset += 4;
|
||||
return;
|
||||
}
|
||||
p = gins(ADATA, nam, nr);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = wid;
|
||||
}
|
||||
|
||||
void
|
||||
gdatacomplex(Node *nam, Mpcplx *cval)
|
||||
{
|
||||
Prog *p;
|
||||
int w;
|
||||
|
||||
w = cplxsubtype(nam->type->etype);
|
||||
w = types[w]->width;
|
||||
|
||||
p = gins(ADATA, nam, N);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = w;
|
||||
p->to.type = TYPE_FCONST;
|
||||
p->to.u.dval = mpgetflt(&cval->real);
|
||||
|
||||
p = gins(ADATA, nam, N);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = w;
|
||||
p->from.offset += w;
|
||||
p->to.type = TYPE_FCONST;
|
||||
p->to.u.dval = mpgetflt(&cval->imag);
|
||||
}
|
||||
|
||||
void
|
||||
gdatastring(Node *nam, Strlit *sval)
|
||||
{
|
||||
Prog *p;
|
||||
Node nod1;
|
||||
|
||||
p = gins(ADATA, nam, N);
|
||||
datastring(sval->s, sval->len, &p->to);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = types[tptr]->width;
|
||||
p->to.type = TYPE_CONST;
|
||||
p->to.etype = TINT32;
|
||||
//print("%P\n", p);
|
||||
|
||||
nodconst(&nod1, types[TINT32], sval->len);
|
||||
p = gins(ADATA, nam, &nod1);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = types[TINT32]->width;
|
||||
p->from.offset += types[tptr]->width;
|
||||
}
|
||||
|
||||
int
|
||||
dstringptr(Sym *s, int off, char *str)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
off = rnd(off, widthptr);
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthptr;
|
||||
|
||||
datastring(str, strlen(str)+1, &p->to);
|
||||
p->to.type = TYPE_CONST;
|
||||
p->to.etype = TINT32;
|
||||
off += widthptr;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
int
|
||||
dgostrlitptr(Sym *s, int off, Strlit *lit)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
if(lit == nil)
|
||||
return duintptr(s, off, 0);
|
||||
|
||||
off = rnd(off, widthptr);
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthptr;
|
||||
datagostring(lit, &p->to);
|
||||
p->to.type = TYPE_CONST;
|
||||
p->to.etype = TINT32;
|
||||
off += widthptr;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
int
|
||||
dgostringptr(Sym *s, int off, char *str)
|
||||
{
|
||||
int n;
|
||||
Strlit *lit;
|
||||
|
||||
if(str == nil)
|
||||
return duintptr(s, off, 0);
|
||||
|
||||
n = strlen(str);
|
||||
lit = mal(sizeof *lit + n);
|
||||
strcpy(lit->s, str);
|
||||
lit->len = n;
|
||||
return dgostrlitptr(s, off, lit);
|
||||
}
|
||||
|
||||
int
|
||||
dsymptr(Sym *s, int off, Sym *x, int xoff)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
off = rnd(off, widthptr);
|
||||
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthptr;
|
||||
p->to.type = TYPE_ADDR;
|
||||
p->to.name = NAME_EXTERN;
|
||||
p->to.sym = linksym(x);
|
||||
p->to.offset = xoff;
|
||||
off += widthptr;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
void
|
||||
nopout(Prog *p)
|
||||
{
|
||||
p->as = ANOP;
|
||||
p->scond = zprog.scond;
|
||||
p->from = zprog.from;
|
||||
p->to = zprog.to;
|
||||
p->reg = zprog.reg;
|
||||
}
|
@ -38,229 +38,6 @@
|
||||
// At the same time, can raise StackBig in ../../runtime/stack.h.
|
||||
long unmappedzero = 4096;
|
||||
|
||||
void
|
||||
clearp(Prog *p)
|
||||
{
|
||||
p->as = AEND;
|
||||
p->reg = 0;
|
||||
p->scond = C_SCOND_NONE;
|
||||
p->from.type = TYPE_NONE;
|
||||
p->from.name = NAME_NONE;
|
||||
p->from.reg = 0;
|
||||
p->to.type = TYPE_NONE;
|
||||
p->to.name = NAME_NONE;
|
||||
p->to.reg = 0;
|
||||
p->pc = pcloc;
|
||||
pcloc++;
|
||||
}
|
||||
|
||||
static int ddumped;
|
||||
static Prog *dfirst;
|
||||
static Prog *dpc;
|
||||
|
||||
/*
|
||||
* generate and return proc with p->as = as,
|
||||
* linked into program. pc is next instruction.
|
||||
*/
|
||||
Prog*
|
||||
prog(int as)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
if(as == ADATA || as == AGLOBL) {
|
||||
if(ddumped)
|
||||
fatal("already dumped data");
|
||||
if(dpc == nil) {
|
||||
dpc = mal(sizeof(*dpc));
|
||||
dfirst = dpc;
|
||||
}
|
||||
p = dpc;
|
||||
dpc = mal(sizeof(*dpc));
|
||||
p->link = dpc;
|
||||
p->reg = 0; // used for flags
|
||||
} else {
|
||||
p = pc;
|
||||
pc = mal(sizeof(*pc));
|
||||
clearp(pc);
|
||||
p->link = pc;
|
||||
}
|
||||
|
||||
if(lineno == 0) {
|
||||
if(debug['K'])
|
||||
warn("prog: line 0");
|
||||
}
|
||||
|
||||
p->as = as;
|
||||
p->lineno = lineno;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
dumpdata(void)
|
||||
{
|
||||
ddumped = 1;
|
||||
if(dfirst == nil)
|
||||
return;
|
||||
newplist();
|
||||
*pc = *dfirst;
|
||||
pc = dpc;
|
||||
clearp(pc);
|
||||
}
|
||||
|
||||
/*
|
||||
* generate a branch.
|
||||
* t is ignored.
|
||||
* likely values are for branch prediction:
|
||||
* -1 unlikely
|
||||
* 0 no opinion
|
||||
* +1 likely
|
||||
*/
|
||||
Prog*
|
||||
gbranch(int as, Type *t, int likely)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
USED(t);
|
||||
USED(likely); // TODO: record this for linker
|
||||
|
||||
p = prog(as);
|
||||
p->to.type = TYPE_BRANCH;
|
||||
p->to.u.branch = P;
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* patch previous branch to jump to to.
|
||||
*/
|
||||
void
|
||||
patch(Prog *p, Prog *to)
|
||||
{
|
||||
if(p->to.type != TYPE_BRANCH)
|
||||
fatal("patch: not a branch");
|
||||
p->to.u.branch = to;
|
||||
p->to.offset = to->pc;
|
||||
}
|
||||
|
||||
Prog*
|
||||
unpatch(Prog *p)
|
||||
{
|
||||
Prog *q;
|
||||
|
||||
if(p->to.type != TYPE_BRANCH)
|
||||
fatal("unpatch: not a branch");
|
||||
q = p->to.u.branch;
|
||||
p->to.u.branch = P;
|
||||
p->to.offset = 0;
|
||||
return q;
|
||||
}
|
||||
|
||||
/*
|
||||
* start a new Prog list.
|
||||
*/
|
||||
Plist*
|
||||
newplist(void)
|
||||
{
|
||||
Plist *pl;
|
||||
|
||||
pl = linknewplist(ctxt);
|
||||
|
||||
pc = mal(sizeof(*pc));
|
||||
clearp(pc);
|
||||
pl->firstpc = pc;
|
||||
|
||||
return pl;
|
||||
}
|
||||
|
||||
void
|
||||
gused(Node *n)
|
||||
{
|
||||
gins(ANOP, n, N); // used
|
||||
}
|
||||
|
||||
Prog*
|
||||
gjmp(Prog *to)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gbranch(AB, T, 0);
|
||||
if(to != P)
|
||||
patch(p, to);
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
ggloblnod(Node *nam)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(AGLOBL, nam, N);
|
||||
p->lineno = nam->lineno;
|
||||
p->from.sym->gotype = linksym(ngotype(nam));
|
||||
p->to.sym = nil;
|
||||
p->to.type = TYPE_CONST;
|
||||
p->to.offset = nam->type->width;
|
||||
if(nam->readonly)
|
||||
p->from3.offset = RODATA;
|
||||
if(nam->type != T && !haspointers(nam->type))
|
||||
p->from3.offset |= NOPTR;
|
||||
}
|
||||
|
||||
void
|
||||
ggloblsym(Sym *s, int32 width, int8 flags)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(AGLOBL, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->to.type = TYPE_CONST;
|
||||
p->to.name = NAME_NONE;
|
||||
p->to.offset = width;
|
||||
p->from3.offset = flags;
|
||||
}
|
||||
|
||||
void
|
||||
gtrack(Sym *s)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(AUSEFIELD, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
}
|
||||
|
||||
int
|
||||
isfat(Type *t)
|
||||
{
|
||||
if(t != T)
|
||||
switch(t->etype) {
|
||||
case TSTRUCT:
|
||||
case TARRAY:
|
||||
case TSTRING:
|
||||
case TINTER: // maybe remove later
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* naddr of func generates code for address of func.
|
||||
* if using opcode that can take address implicitly,
|
||||
* call afunclit to fix up the argument.
|
||||
* also fix up direct register references to be TYPE_MEM.
|
||||
*/
|
||||
void
|
||||
afunclit(Addr *a, Node *n)
|
||||
{
|
||||
if(a->type == TYPE_ADDR && a->name == NAME_EXTERN || a->type == TYPE_REG) {
|
||||
a->type = TYPE_MEM;
|
||||
if(n->op == ONAME)
|
||||
a->sym = linksym(n->sym);
|
||||
}
|
||||
}
|
||||
|
||||
static int resvd[] =
|
||||
{
|
||||
9, // reserved for m
|
||||
@ -426,101 +203,6 @@ regfree(Node *n)
|
||||
regpc[i] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize n to be register r of type t.
|
||||
*/
|
||||
void
|
||||
nodreg(Node *n, Type *t, int r)
|
||||
{
|
||||
if(t == T)
|
||||
fatal("nodreg: t nil");
|
||||
|
||||
memset(n, 0, sizeof(*n));
|
||||
n->op = OREGISTER;
|
||||
n->addable = 1;
|
||||
ullmancalc(n);
|
||||
n->val.u.reg = r;
|
||||
n->type = t;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize n to be indirect of register r; n is type t.
|
||||
*/
|
||||
void
|
||||
nodindreg(Node *n, Type *t, int r)
|
||||
{
|
||||
nodreg(n, t, r);
|
||||
n->op = OINDREG;
|
||||
}
|
||||
|
||||
Node*
|
||||
nodarg(Type *t, int fp)
|
||||
{
|
||||
Node *n;
|
||||
NodeList *l;
|
||||
Type *first;
|
||||
Iter savet;
|
||||
|
||||
// entire argument struct, not just one arg
|
||||
if(t->etype == TSTRUCT && t->funarg) {
|
||||
n = nod(ONAME, N, N);
|
||||
n->sym = lookup(".args");
|
||||
n->type = t;
|
||||
first = structfirst(&savet, &t);
|
||||
if(first == nil)
|
||||
fatal("nodarg: bad struct");
|
||||
if(first->width == BADWIDTH)
|
||||
fatal("nodarg: offset not computed for %T", t);
|
||||
n->xoffset = first->width;
|
||||
n->addable = 1;
|
||||
goto fp;
|
||||
}
|
||||
|
||||
if(t->etype != TFIELD)
|
||||
fatal("nodarg: not field %T", t);
|
||||
|
||||
if(fp == 1) {
|
||||
for(l=curfn->dcl; l; l=l->next) {
|
||||
n = l->n;
|
||||
if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
n = nod(ONAME, N, N);
|
||||
n->type = t->type;
|
||||
n->sym = t->sym;
|
||||
if(t->width == BADWIDTH)
|
||||
fatal("nodarg: offset not computed for %T", t);
|
||||
n->xoffset = t->width;
|
||||
n->addable = 1;
|
||||
n->orig = t->nname;
|
||||
|
||||
fp:
|
||||
// Rewrite argument named _ to __,
|
||||
// or else the assignment to _ will be
|
||||
// discarded during code generation.
|
||||
if(isblank(n))
|
||||
n->sym = lookup("__");
|
||||
|
||||
switch(fp) {
|
||||
default:
|
||||
fatal("nodarg %T %d", t, fp);
|
||||
|
||||
case 0: // output arg for calling another function
|
||||
n->op = OINDREG;
|
||||
n->val.u.reg = REGSP;
|
||||
n->xoffset += 4;
|
||||
break;
|
||||
|
||||
case 1: // input arg to current function
|
||||
n->class = PPARAM;
|
||||
break;
|
||||
}
|
||||
n->typecheck = 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* return constant i node.
|
||||
* overwritten by next call, but useful in calls to gins.
|
||||
@ -536,22 +218,6 @@ ncon(uint32 i)
|
||||
return &n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this node a memory operand?
|
||||
*/
|
||||
int
|
||||
ismem(Node *n)
|
||||
{
|
||||
switch(n->op) {
|
||||
case OINDREG:
|
||||
case ONAME:
|
||||
case OPARAM:
|
||||
case OCLOSUREVAR:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Node sclean[10];
|
||||
int nsclean;
|
||||
|
||||
@ -1181,228 +847,6 @@ gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs)
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate code to compute n;
|
||||
* make a refer to result.
|
||||
*/
|
||||
void
|
||||
naddr(Node *n, Addr *a, int canemitcode)
|
||||
{
|
||||
Sym *s;
|
||||
|
||||
a->type = TYPE_NONE;
|
||||
a->name = NAME_NONE;
|
||||
a->reg = 0;
|
||||
a->gotype = nil;
|
||||
a->node = N;
|
||||
a->etype = 0;
|
||||
if(n == N)
|
||||
return;
|
||||
|
||||
if(n->type != T && n->type->etype != TIDEAL) {
|
||||
dowidth(n->type);
|
||||
a->width = n->type->width;
|
||||
}
|
||||
|
||||
switch(n->op) {
|
||||
default:
|
||||
fatal("naddr: bad %O %D", n->op, a);
|
||||
break;
|
||||
|
||||
case OREGISTER:
|
||||
a->type = TYPE_REG;
|
||||
a->reg = n->val.u.reg;
|
||||
a->sym = nil;
|
||||
break;
|
||||
|
||||
case OINDEX:
|
||||
case OIND:
|
||||
fatal("naddr: OINDEX");
|
||||
// naddr(n->left, a);
|
||||
// if(a->type >= D_AX && a->type <= D_DI)
|
||||
// a->type += D_INDIR;
|
||||
// else
|
||||
// if(a->type == TYPE_ADDR)
|
||||
// a->type = TYPE_NONE+D_INDIR;
|
||||
// else
|
||||
// if(a->type == TYPE_ADDR) {
|
||||
// a->type = a->index;
|
||||
// a->index = TYPE_NONE;
|
||||
// } else
|
||||
// goto bad;
|
||||
// if(n->op == OINDEX) {
|
||||
// a->index = idx.reg;
|
||||
// a->scale = n->scale;
|
||||
// }
|
||||
// break;
|
||||
|
||||
case OINDREG:
|
||||
a->type = TYPE_MEM;
|
||||
a->reg = n->val.u.reg;
|
||||
a->sym = linksym(n->sym);
|
||||
a->offset = n->xoffset;
|
||||
break;
|
||||
|
||||
case OPARAM:
|
||||
// n->left is PHEAP ONAME for stack parameter.
|
||||
// compute address of actual parameter on stack.
|
||||
a->etype = simtype[n->left->type->etype];
|
||||
a->width = n->left->type->width;
|
||||
a->offset = n->xoffset;
|
||||
a->sym = linksym(n->left->sym);
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_PARAM;
|
||||
a->node = n->left->orig;
|
||||
break;
|
||||
|
||||
case OCLOSUREVAR:
|
||||
if(!curfn->needctxt)
|
||||
fatal("closurevar without needctxt");
|
||||
a->type = TYPE_MEM;
|
||||
a->reg = REG_R7;
|
||||
a->offset = n->xoffset;
|
||||
a->sym = nil;
|
||||
break;
|
||||
|
||||
case OCFUNC:
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->sym = linksym(n->left->sym);
|
||||
break;
|
||||
|
||||
case ONAME:
|
||||
a->etype = 0;
|
||||
a->width = 0;
|
||||
a->reg = 0;
|
||||
if(n->type != T) {
|
||||
a->etype = simtype[n->type->etype];
|
||||
a->width = n->type->width;
|
||||
}
|
||||
a->offset = n->xoffset;
|
||||
s = n->sym;
|
||||
a->node = n->orig;
|
||||
//if(a->node >= (Node*)&n)
|
||||
// fatal("stack node");
|
||||
if(s == S)
|
||||
s = lookup(".noname");
|
||||
if(n->method) {
|
||||
if(n->type != T)
|
||||
if(n->type->sym != S)
|
||||
if(n->type->sym->pkg != nil)
|
||||
s = pkglookup(s->name, n->type->sym->pkg);
|
||||
}
|
||||
|
||||
a->type = TYPE_MEM;
|
||||
switch(n->class) {
|
||||
default:
|
||||
fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
|
||||
case PEXTERN:
|
||||
a->name = NAME_EXTERN;
|
||||
break;
|
||||
case PAUTO:
|
||||
a->name = NAME_AUTO;
|
||||
break;
|
||||
case PPARAM:
|
||||
case PPARAMOUT:
|
||||
a->name = NAME_PARAM;
|
||||
break;
|
||||
case PFUNC:
|
||||
a->name = NAME_EXTERN;
|
||||
a->type = TYPE_ADDR;
|
||||
s = funcsym(s);
|
||||
break;
|
||||
}
|
||||
a->sym = linksym(s);
|
||||
break;
|
||||
|
||||
case OLITERAL:
|
||||
switch(n->val.ctype) {
|
||||
default:
|
||||
fatal("naddr: const %lT", n->type);
|
||||
break;
|
||||
case CTFLT:
|
||||
a->type = TYPE_FCONST;
|
||||
a->u.dval = mpgetflt(n->val.u.fval);
|
||||
break;
|
||||
case CTINT:
|
||||
case CTRUNE:
|
||||
a->sym = nil;
|
||||
a->type = TYPE_CONST;
|
||||
a->offset = mpgetfix(n->val.u.xval);
|
||||
break;
|
||||
case CTSTR:
|
||||
datagostring(n->val.u.sval, a);
|
||||
break;
|
||||
case CTBOOL:
|
||||
a->sym = nil;
|
||||
a->type = TYPE_CONST;
|
||||
a->offset = n->val.u.bval;
|
||||
break;
|
||||
case CTNIL:
|
||||
a->sym = nil;
|
||||
a->type = TYPE_CONST;
|
||||
a->offset = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case OITAB:
|
||||
// itable of interface value
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->etype = simtype[tptr];
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // len(nil)
|
||||
a->width = widthptr;
|
||||
break;
|
||||
|
||||
case OSPTR:
|
||||
// pointer in a string or slice
|
||||
naddr(n->left, a, canemitcode);
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // ptr(nil)
|
||||
a->etype = simtype[tptr];
|
||||
a->offset += Array_array;
|
||||
a->width = widthptr;
|
||||
break;
|
||||
|
||||
case OLEN:
|
||||
// len of string or slice
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->etype = TINT32;
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // len(nil)
|
||||
a->offset += Array_nel;
|
||||
break;
|
||||
|
||||
case OCAP:
|
||||
// cap of string or slice
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->etype = TINT32;
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // cap(nil)
|
||||
a->offset += Array_cap;
|
||||
break;
|
||||
|
||||
case OADDR:
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->etype = tptr;
|
||||
switch(a->type) {
|
||||
case TYPE_MEM:
|
||||
a->type = TYPE_ADDR;
|
||||
break;
|
||||
|
||||
case TYPE_REG:
|
||||
case TYPE_ADDR:
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("naddr: OADDR %d\n", a->type);
|
||||
}
|
||||
}
|
||||
|
||||
if(a->width < 0)
|
||||
fatal("naddr: bad width for %N -> %D", n, a);
|
||||
}
|
||||
|
||||
/*
|
||||
* return Axxx for Oxxx on type t.
|
||||
*/
|
||||
|
@ -725,7 +725,7 @@ mkvar(Reg *r, Adr *a)
|
||||
flag = 0;
|
||||
switch(t) {
|
||||
default:
|
||||
print("type %d %d %D\n", t, a->name, a);
|
||||
print("mkvar: type %d %d %D\n", t, a->name, a);
|
||||
goto none;
|
||||
|
||||
case TYPE_NONE:
|
||||
|
@ -91,6 +91,7 @@ enum
|
||||
REGG = REGEXT-0,
|
||||
REGM = REGEXT-1,
|
||||
|
||||
REGCTXT = REG_R7,
|
||||
REGTMP = REG_R11,
|
||||
REGSP = REG_R13,
|
||||
REGLINK = REG_R14,
|
||||
|
@ -69,8 +69,9 @@ main(int argc, char **argv)
|
||||
arch.thestring = thestring;
|
||||
arch.thelinkarch = thelinkarch;
|
||||
arch.typedefs = typedefs;
|
||||
arch.REGSP = REGSP;
|
||||
arch.REGCTXT = REGCTXT;
|
||||
arch.MAXWIDTH = MAXWIDTH;
|
||||
arch.afunclit = afunclit;
|
||||
arch.anyregalloc = anyregalloc;
|
||||
arch.betypeinit = betypeinit;
|
||||
arch.bgen = bgen;
|
||||
@ -80,37 +81,15 @@ main(int argc, char **argv)
|
||||
arch.cgen_callinter = cgen_callinter;
|
||||
arch.cgen_ret = cgen_ret;
|
||||
arch.clearfat = clearfat;
|
||||
arch.clearp = clearp;
|
||||
arch.defframe = defframe;
|
||||
arch.dgostringptr = dgostringptr;
|
||||
arch.dgostrlitptr = dgostrlitptr;
|
||||
arch.dsname = dsname;
|
||||
arch.dsymptr = dsymptr;
|
||||
arch.dumpdata = dumpdata;
|
||||
arch.dumpit = dumpit;
|
||||
arch.excise = excise;
|
||||
arch.expandchecks = expandchecks;
|
||||
arch.fixautoused = fixautoused;
|
||||
arch.gclean = gclean;
|
||||
arch.gdata = gdata;
|
||||
arch.gdatacomplex = gdatacomplex;
|
||||
arch.gdatastring = gdatastring;
|
||||
arch.ggloblnod = ggloblnod;
|
||||
arch.ggloblsym = ggloblsym;
|
||||
arch.ginit = ginit;
|
||||
arch.gins = gins;
|
||||
arch.ginscall = ginscall;
|
||||
arch.gjmp = gjmp;
|
||||
arch.gtrack = gtrack;
|
||||
arch.gused = gused;
|
||||
arch.igen = igen;
|
||||
arch.isfat = isfat;
|
||||
arch.linkarchinit = linkarchinit;
|
||||
arch.markautoused = markautoused;
|
||||
arch.naddr = naddr;
|
||||
arch.newplist = newplist;
|
||||
arch.nodarg = nodarg;
|
||||
arch.patch = patch;
|
||||
arch.proginfo = proginfo;
|
||||
arch.regalloc = regalloc;
|
||||
arch.regfree = regfree;
|
||||
@ -119,7 +98,6 @@ main(int argc, char **argv)
|
||||
arch.sameaddr = sameaddr;
|
||||
arch.smallindir = smallindir;
|
||||
arch.stackaddr = stackaddr;
|
||||
arch.unpatch = unpatch;
|
||||
|
||||
gcmain(argc, argv);
|
||||
}
|
||||
|
@ -9,10 +9,7 @@
|
||||
#include "../gc/go.h"
|
||||
#include "../6l/6.out.h"
|
||||
|
||||
EXTERN int32 dynloc;
|
||||
EXTERN uchar reg[MAXREG];
|
||||
EXTERN int32 pcloc; // instruction counter
|
||||
EXTERN Strlit emptystring;
|
||||
EXTERN Node* panicdiv;
|
||||
extern vlong unmappedzero;
|
||||
extern int addptr;
|
||||
|
@ -115,52 +115,6 @@ appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int tre
|
||||
return q;
|
||||
}
|
||||
|
||||
// Sweep the prog list to mark any used nodes.
|
||||
void
|
||||
markautoused(Prog* p)
|
||||
{
|
||||
for (; p; p = p->link) {
|
||||
if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
|
||||
continue;
|
||||
|
||||
if (p->from.node)
|
||||
((Node*)(p->from.node))->used = 1;
|
||||
|
||||
if (p->to.node)
|
||||
((Node*)(p->to.node))->used = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
|
||||
void
|
||||
fixautoused(Prog *p)
|
||||
{
|
||||
Prog **lp;
|
||||
|
||||
for (lp=&p; (p=*lp) != P; ) {
|
||||
if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
|
||||
*lp = p->link;
|
||||
continue;
|
||||
}
|
||||
if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
|
||||
// Cannot remove VARDEF instruction, because - unlike TYPE handled above -
|
||||
// VARDEFs are interspersed with other code, and a jump might be using the
|
||||
// VARDEF as a target. Replace with a no-op instead. A later pass will remove
|
||||
// the no-ops.
|
||||
nopout(p);
|
||||
continue;
|
||||
}
|
||||
if (p->from.name == NAME_AUTO && p->from.node)
|
||||
p->from.offset += ((Node*)(p->from.node))->stkdelta;
|
||||
|
||||
if (p->to.name == NAME_AUTO && p->to.node)
|
||||
p->to.offset += ((Node*)(p->to.node))->stkdelta;
|
||||
|
||||
lp = &p->link;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* generate:
|
||||
* call f
|
||||
@ -616,20 +570,6 @@ ret:
|
||||
;
|
||||
}
|
||||
|
||||
int
|
||||
samereg(Node *a, Node *b)
|
||||
{
|
||||
if(a == N || b == N)
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate division.
|
||||
* generates one of:
|
||||
|
@ -1,244 +0,0 @@
|
||||
// Derived from Inferno utils/6c/swt.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.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 <u.h>
|
||||
#include <libc.h>
|
||||
#include "gg.h"
|
||||
|
||||
int
|
||||
dsname(Sym *s, int off, char *t, int n)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.offset = off;
|
||||
p->from.sym = linksym(s);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = n;
|
||||
|
||||
p->to.type = TYPE_SCONST;
|
||||
memmove(p->to.u.sval, t, n);
|
||||
return off + n;
|
||||
}
|
||||
|
||||
/*
|
||||
* make a refer to the data s, s+len
|
||||
* emitting DATA if needed.
|
||||
*/
|
||||
void
|
||||
datastring(char *s, int len, Addr *a)
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
sym = stringsym(s, len);
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_EXTERN;
|
||||
a->sym = linksym(sym);
|
||||
a->node = sym->def;
|
||||
a->offset = widthptr+widthint; // skip header
|
||||
a->etype = simtype[TINT];
|
||||
}
|
||||
|
||||
/*
|
||||
* make a refer to the string sval,
|
||||
* emitting DATA if needed.
|
||||
*/
|
||||
void
|
||||
datagostring(Strlit *sval, Addr *a)
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
sym = stringsym(sval->s, sval->len);
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_EXTERN;
|
||||
a->sym = linksym(sym);
|
||||
a->node = sym->def;
|
||||
a->offset = 0; // header
|
||||
a->etype = TSTRING;
|
||||
}
|
||||
|
||||
void
|
||||
gdata(Node *nam, Node *nr, int wid)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
if(nr->op == OLITERAL) {
|
||||
switch(nr->val.ctype) {
|
||||
case CTCPLX:
|
||||
gdatacomplex(nam, nr->val.u.cval);
|
||||
return;
|
||||
case CTSTR:
|
||||
gdatastring(nam, nr->val.u.sval);
|
||||
return;
|
||||
}
|
||||
}
|
||||
p = gins(ADATA, nam, nr);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = wid;
|
||||
}
|
||||
|
||||
void
|
||||
gdatacomplex(Node *nam, Mpcplx *cval)
|
||||
{
|
||||
Prog *p;
|
||||
int w;
|
||||
|
||||
w = cplxsubtype(nam->type->etype);
|
||||
w = types[w]->width;
|
||||
|
||||
p = gins(ADATA, nam, N);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = w;
|
||||
p->to.type = TYPE_FCONST;
|
||||
p->to.u.dval = mpgetflt(&cval->real);
|
||||
|
||||
p = gins(ADATA, nam, N);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = w;
|
||||
p->from.offset += w;
|
||||
p->to.type = TYPE_FCONST;
|
||||
p->to.u.dval = mpgetflt(&cval->imag);
|
||||
}
|
||||
|
||||
void
|
||||
gdatastring(Node *nam, Strlit *sval)
|
||||
{
|
||||
Prog *p;
|
||||
Node nod1;
|
||||
|
||||
p = gins(ADATA, nam, N);
|
||||
datastring(sval->s, sval->len, &p->to);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = types[tptr]->width;
|
||||
p->to.type = TYPE_ADDR;
|
||||
//print("%P\n", p);
|
||||
|
||||
nodconst(&nod1, types[TINT], sval->len);
|
||||
p = gins(ADATA, nam, &nod1);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthint;
|
||||
p->from.offset += widthptr;
|
||||
}
|
||||
|
||||
int
|
||||
dstringptr(Sym *s, int off, char *str)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
off = rnd(off, widthptr);
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthptr;
|
||||
|
||||
datastring(str, strlen(str)+1, &p->to);
|
||||
p->to.type = TYPE_ADDR;
|
||||
p->to.etype = simtype[TINT];
|
||||
off += widthptr;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
int
|
||||
dgostrlitptr(Sym *s, int off, Strlit *lit)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
if(lit == nil)
|
||||
return duintptr(s, off, 0);
|
||||
|
||||
off = rnd(off, widthptr);
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthptr;
|
||||
datagostring(lit, &p->to);
|
||||
p->to.type = TYPE_ADDR;
|
||||
p->to.etype = simtype[TINT];
|
||||
off += widthptr;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
int
|
||||
dgostringptr(Sym *s, int off, char *str)
|
||||
{
|
||||
int n;
|
||||
Strlit *lit;
|
||||
|
||||
if(str == nil)
|
||||
return duintptr(s, off, 0);
|
||||
|
||||
n = strlen(str);
|
||||
lit = mal(sizeof *lit + n);
|
||||
strcpy(lit->s, str);
|
||||
lit->len = n;
|
||||
return dgostrlitptr(s, off, lit);
|
||||
}
|
||||
|
||||
int
|
||||
dsymptr(Sym *s, int off, Sym *x, int xoff)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
off = rnd(off, widthptr);
|
||||
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthptr;
|
||||
p->to.type = TYPE_ADDR;
|
||||
p->to.name = NAME_EXTERN;
|
||||
p->to.sym = linksym(x);
|
||||
p->to.offset = xoff;
|
||||
off += widthptr;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
void
|
||||
nopout(Prog *p)
|
||||
{
|
||||
p->as = ANOP;
|
||||
p->from = zprog.from;
|
||||
p->to = zprog.to;
|
||||
}
|
||||
|
@ -37,225 +37,6 @@
|
||||
// the text segment up higher in 6l for all GOOS.
|
||||
// At the same time, can raise StackBig in ../../runtime/stack.h.
|
||||
vlong unmappedzero = 4096;
|
||||
|
||||
void
|
||||
clearp(Prog *p)
|
||||
{
|
||||
p->as = AEND;
|
||||
p->from.type = TYPE_NONE;
|
||||
p->from.index = TYPE_NONE;
|
||||
p->to.type = TYPE_NONE;
|
||||
p->to.index = TYPE_NONE;
|
||||
p->pc = pcloc;
|
||||
pcloc++;
|
||||
}
|
||||
|
||||
static int ddumped;
|
||||
static Prog *dfirst;
|
||||
static Prog *dpc;
|
||||
|
||||
/*
|
||||
* generate and return proc with p->as = as,
|
||||
* linked into program. pc is next instruction.
|
||||
*/
|
||||
Prog*
|
||||
prog(int as)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
if(as == ADATA || as == AGLOBL) {
|
||||
if(ddumped)
|
||||
fatal("already dumped data");
|
||||
if(dpc == nil) {
|
||||
dpc = mal(sizeof(*dpc));
|
||||
dfirst = dpc;
|
||||
}
|
||||
p = dpc;
|
||||
dpc = mal(sizeof(*dpc));
|
||||
p->link = dpc;
|
||||
} else {
|
||||
p = pc;
|
||||
pc = mal(sizeof(*pc));
|
||||
clearp(pc);
|
||||
p->link = pc;
|
||||
}
|
||||
|
||||
if(lineno == 0) {
|
||||
if(debug['K'])
|
||||
warn("prog: line 0");
|
||||
}
|
||||
|
||||
p->as = as;
|
||||
p->lineno = lineno;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
dumpdata(void)
|
||||
{
|
||||
ddumped = 1;
|
||||
if(dfirst == nil)
|
||||
return;
|
||||
newplist();
|
||||
*pc = *dfirst;
|
||||
pc = dpc;
|
||||
clearp(pc);
|
||||
}
|
||||
|
||||
/*
|
||||
* generate a branch.
|
||||
* t is ignored.
|
||||
* likely values are for branch prediction:
|
||||
* -1 unlikely
|
||||
* 0 no opinion
|
||||
* +1 likely
|
||||
*/
|
||||
Prog*
|
||||
gbranch(int as, Type *t, int likely)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
USED(t);
|
||||
|
||||
p = prog(as);
|
||||
p->to.type = TYPE_BRANCH;
|
||||
p->to.u.branch = P;
|
||||
if(as != AJMP && likely != 0) {
|
||||
p->from.type = TYPE_CONST;
|
||||
p->from.offset = likely > 0;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* patch previous branch to jump to to.
|
||||
*/
|
||||
void
|
||||
patch(Prog *p, Prog *to)
|
||||
{
|
||||
if(p->to.type != TYPE_BRANCH)
|
||||
fatal("patch: not a branch");
|
||||
p->to.u.branch = to;
|
||||
p->to.offset = to->pc;
|
||||
}
|
||||
|
||||
Prog*
|
||||
unpatch(Prog *p)
|
||||
{
|
||||
Prog *q;
|
||||
|
||||
if(p->to.type != TYPE_BRANCH)
|
||||
fatal("unpatch: not a branch");
|
||||
q = p->to.u.branch;
|
||||
p->to.u.branch = P;
|
||||
p->to.offset = 0;
|
||||
return q;
|
||||
}
|
||||
|
||||
/*
|
||||
* start a new Prog list.
|
||||
*/
|
||||
Plist*
|
||||
newplist(void)
|
||||
{
|
||||
Plist *pl;
|
||||
|
||||
pl = linknewplist(ctxt);
|
||||
|
||||
pc = mal(sizeof(*pc));
|
||||
clearp(pc);
|
||||
pl->firstpc = pc;
|
||||
|
||||
return pl;
|
||||
}
|
||||
|
||||
void
|
||||
gused(Node *n)
|
||||
{
|
||||
gins(ANOP, n, N); // used
|
||||
}
|
||||
|
||||
Prog*
|
||||
gjmp(Prog *to)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gbranch(AJMP, T, 0);
|
||||
if(to != P)
|
||||
patch(p, to);
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
ggloblnod(Node *nam)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(AGLOBL, nam, N);
|
||||
p->lineno = nam->lineno;
|
||||
p->from.sym->gotype = linksym(ngotype(nam));
|
||||
p->to.sym = nil;
|
||||
p->to.type = TYPE_CONST;
|
||||
p->to.offset = nam->type->width;
|
||||
if(nam->readonly)
|
||||
p->from3.offset = RODATA;
|
||||
if(nam->type != T && !haspointers(nam->type))
|
||||
p->from3.offset |= NOPTR;
|
||||
}
|
||||
|
||||
void
|
||||
gtrack(Sym *s)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(AUSEFIELD, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
}
|
||||
|
||||
void
|
||||
ggloblsym(Sym *s, int32 width, int8 flags)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(AGLOBL, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->to.type = TYPE_CONST;
|
||||
p->to.offset = width;
|
||||
p->from3.offset = flags;
|
||||
}
|
||||
|
||||
int
|
||||
isfat(Type *t)
|
||||
{
|
||||
if(t != T)
|
||||
switch(t->etype) {
|
||||
case TSTRUCT:
|
||||
case TARRAY:
|
||||
case TSTRING:
|
||||
case TINTER: // maybe remove later
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* naddr of func generates code for address of func.
|
||||
* if using opcode that can take address implicitly,
|
||||
* call afunclit to fix up the argument.
|
||||
*/
|
||||
void
|
||||
afunclit(Addr *a, Node *n)
|
||||
{
|
||||
if(a->type == TYPE_ADDR && a->name == NAME_EXTERN) {
|
||||
a->type = TYPE_MEM;
|
||||
a->sym = linksym(n->sym);
|
||||
}
|
||||
}
|
||||
|
||||
static int resvd[] =
|
||||
{
|
||||
REG_DI, // for movstring
|
||||
@ -421,105 +202,6 @@ regfree(Node *n)
|
||||
regpc[i - REG_AX] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize n to be register r of type t.
|
||||
*/
|
||||
void
|
||||
nodreg(Node *n, Type *t, int r)
|
||||
{
|
||||
if(t == T)
|
||||
fatal("nodreg: t nil");
|
||||
|
||||
memset(n, 0, sizeof(*n));
|
||||
n->op = OREGISTER;
|
||||
n->addable = 1;
|
||||
ullmancalc(n);
|
||||
n->val.u.reg = r;
|
||||
n->type = t;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize n to be indirect of register r; n is type t.
|
||||
*/
|
||||
void
|
||||
nodindreg(Node *n, Type *t, int r)
|
||||
{
|
||||
nodreg(n, t, r);
|
||||
n->op = OINDREG;
|
||||
}
|
||||
|
||||
Node*
|
||||
nodarg(Type *t, int fp)
|
||||
{
|
||||
Node *n;
|
||||
NodeList *l;
|
||||
Type *first;
|
||||
Iter savet;
|
||||
|
||||
// entire argument struct, not just one arg
|
||||
if(t->etype == TSTRUCT && t->funarg) {
|
||||
n = nod(ONAME, N, N);
|
||||
n->sym = lookup(".args");
|
||||
n->type = t;
|
||||
first = structfirst(&savet, &t);
|
||||
if(first == nil)
|
||||
fatal("nodarg: bad struct");
|
||||
if(first->width == BADWIDTH)
|
||||
fatal("nodarg: offset not computed for %T", t);
|
||||
n->xoffset = first->width;
|
||||
n->addable = 1;
|
||||
goto fp;
|
||||
}
|
||||
|
||||
if(t->etype != TFIELD)
|
||||
fatal("nodarg: not field %T", t);
|
||||
|
||||
if(fp == 1) {
|
||||
for(l=curfn->dcl; l; l=l->next) {
|
||||
n = l->n;
|
||||
if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
n = nod(ONAME, N, N);
|
||||
n->type = t->type;
|
||||
n->sym = t->sym;
|
||||
|
||||
if(t->width == BADWIDTH)
|
||||
fatal("nodarg: offset not computed for %T", t);
|
||||
n->xoffset = t->width;
|
||||
n->addable = 1;
|
||||
n->orig = t->nname;
|
||||
|
||||
fp:
|
||||
// Rewrite argument named _ to __,
|
||||
// or else the assignment to _ will be
|
||||
// discarded during code generation.
|
||||
if(isblank(n))
|
||||
n->sym = lookup("__");
|
||||
|
||||
switch(fp) {
|
||||
case 0: // output arg
|
||||
n->op = OINDREG;
|
||||
n->val.u.reg = REG_SP;
|
||||
break;
|
||||
|
||||
case 1: // input arg
|
||||
n->class = PPARAM;
|
||||
break;
|
||||
|
||||
case 2: // offset output arg
|
||||
fatal("shouldn't be used");
|
||||
n->op = OINDREG;
|
||||
n->val.u.reg = REG_SP;
|
||||
n->xoffset += types[tptr]->width;
|
||||
break;
|
||||
}
|
||||
n->typecheck = 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate
|
||||
* as $c, reg
|
||||
@ -576,27 +258,6 @@ ginscon(int as, vlong c, Node *n2)
|
||||
#define CASE(a,b) (((a)<<16)|((b)<<0))
|
||||
/*c2go int CASE(int, int); */
|
||||
|
||||
/*
|
||||
* Is this node a memory operand?
|
||||
*/
|
||||
int
|
||||
ismem(Node *n)
|
||||
{
|
||||
switch(n->op) {
|
||||
case OITAB:
|
||||
case OSPTR:
|
||||
case OLEN:
|
||||
case OCAP:
|
||||
case OINDREG:
|
||||
case ONAME:
|
||||
case OPARAM:
|
||||
case OCLOSUREVAR:
|
||||
case OADDR:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* set up nodes representing 2^63
|
||||
*/
|
||||
@ -1111,213 +772,6 @@ fixlargeoffset(Node *n)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* generate code to compute n;
|
||||
* make a refer to result.
|
||||
*/
|
||||
void
|
||||
naddr(Node *n, Addr *a, int canemitcode)
|
||||
{
|
||||
Sym *s;
|
||||
|
||||
a->scale = 0;
|
||||
a->reg = REG_NONE;
|
||||
a->index = REG_NONE;
|
||||
a->type = TYPE_NONE;
|
||||
a->name = NAME_NONE;
|
||||
a->gotype = nil;
|
||||
a->node = N;
|
||||
a->width = 0;
|
||||
if(n == N)
|
||||
return;
|
||||
|
||||
if(n->type != T && n->type->etype != TIDEAL) {
|
||||
dowidth(n->type);
|
||||
a->width = n->type->width;
|
||||
}
|
||||
|
||||
switch(n->op) {
|
||||
default:
|
||||
fatal("naddr: bad %O %D", n->op, a);
|
||||
break;
|
||||
|
||||
case OREGISTER:
|
||||
a->type = TYPE_REG;
|
||||
a->reg = n->val.u.reg;
|
||||
a->sym = nil;
|
||||
break;
|
||||
|
||||
case OINDREG:
|
||||
a->type = TYPE_MEM;
|
||||
a->reg = n->val.u.reg;
|
||||
a->sym = linksym(n->sym);
|
||||
a->offset = n->xoffset;
|
||||
if(a->offset != (int32)a->offset)
|
||||
yyerror("offset %lld too large for OINDREG", a->offset);
|
||||
break;
|
||||
|
||||
case OPARAM:
|
||||
// n->left is PHEAP ONAME for stack parameter.
|
||||
// compute address of actual parameter on stack.
|
||||
a->etype = simtype[n->left->type->etype];
|
||||
a->width = n->left->type->width;
|
||||
a->offset = n->xoffset;
|
||||
a->sym = linksym(n->left->sym);
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_PARAM;
|
||||
a->node = n->left->orig;
|
||||
break;
|
||||
|
||||
case OCLOSUREVAR:
|
||||
if(!curfn->needctxt)
|
||||
fatal("closurevar without needctxt");
|
||||
a->type = TYPE_MEM;
|
||||
a->reg = REG_DX;
|
||||
a->sym = nil;
|
||||
a->offset = n->xoffset;
|
||||
break;
|
||||
|
||||
case OCFUNC:
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->sym = linksym(n->left->sym);
|
||||
break;
|
||||
|
||||
case ONAME:
|
||||
a->etype = 0;
|
||||
if(n->type != T)
|
||||
a->etype = simtype[n->type->etype];
|
||||
a->offset = n->xoffset;
|
||||
s = n->sym;
|
||||
a->node = n->orig;
|
||||
//if(a->node >= (Node*)&n)
|
||||
// fatal("stack node");
|
||||
if(s == S)
|
||||
s = lookup(".noname");
|
||||
if(n->method) {
|
||||
if(n->type != T)
|
||||
if(n->type->sym != S)
|
||||
if(n->type->sym->pkg != nil)
|
||||
s = pkglookup(s->name, n->type->sym->pkg);
|
||||
}
|
||||
|
||||
a->type = TYPE_MEM;
|
||||
switch(n->class) {
|
||||
default:
|
||||
fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
|
||||
case PEXTERN:
|
||||
a->name = NAME_EXTERN;
|
||||
break;
|
||||
case PAUTO:
|
||||
a->name = NAME_AUTO;
|
||||
break;
|
||||
case PPARAM:
|
||||
case PPARAMOUT:
|
||||
a->name = NAME_PARAM;
|
||||
break;
|
||||
case PFUNC:
|
||||
a->name = NAME_EXTERN;
|
||||
a->type = TYPE_ADDR;
|
||||
a->width = widthptr;
|
||||
s = funcsym(s);
|
||||
break;
|
||||
}
|
||||
a->sym = linksym(s);
|
||||
break;
|
||||
|
||||
case OLITERAL:
|
||||
switch(n->val.ctype) {
|
||||
default:
|
||||
fatal("naddr: const %lT", n->type);
|
||||
break;
|
||||
case CTFLT:
|
||||
a->type = TYPE_FCONST;
|
||||
a->u.dval = mpgetflt(n->val.u.fval);
|
||||
break;
|
||||
case CTINT:
|
||||
case CTRUNE:
|
||||
a->sym = nil;
|
||||
a->type = TYPE_CONST;
|
||||
a->offset = mpgetfix(n->val.u.xval);
|
||||
break;
|
||||
case CTSTR:
|
||||
datagostring(n->val.u.sval, a);
|
||||
break;
|
||||
case CTBOOL:
|
||||
a->sym = nil;
|
||||
a->type = TYPE_CONST;
|
||||
a->offset = n->val.u.bval;
|
||||
break;
|
||||
case CTNIL:
|
||||
a->sym = nil;
|
||||
a->type = TYPE_CONST;
|
||||
a->offset = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case OADDR:
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->width = widthptr;
|
||||
if(a->type != TYPE_MEM)
|
||||
fatal("naddr: OADDR %D", a);
|
||||
a->type = TYPE_ADDR;
|
||||
break;
|
||||
|
||||
case OITAB:
|
||||
// itable of interface value
|
||||
naddr(n->left, a, canemitcode);
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // itab(nil)
|
||||
a->etype = tptr;
|
||||
a->width = widthptr;
|
||||
break;
|
||||
|
||||
case OSPTR:
|
||||
// pointer in a string or slice
|
||||
naddr(n->left, a, canemitcode);
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // ptr(nil)
|
||||
a->etype = simtype[tptr];
|
||||
a->offset += Array_array;
|
||||
a->width = widthptr;
|
||||
break;
|
||||
|
||||
case OLEN:
|
||||
// len of string or slice
|
||||
naddr(n->left, a, canemitcode);
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // len(nil)
|
||||
a->etype = simtype[TUINT];
|
||||
a->offset += Array_nel;
|
||||
a->width = widthint;
|
||||
break;
|
||||
|
||||
case OCAP:
|
||||
// cap of string or slice
|
||||
naddr(n->left, a, canemitcode);
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // cap(nil)
|
||||
a->etype = simtype[TUINT];
|
||||
a->offset += Array_cap;
|
||||
a->width = widthint;
|
||||
break;
|
||||
|
||||
// case OADD:
|
||||
// if(n->right->op == OLITERAL) {
|
||||
// v = n->right->vconst;
|
||||
// naddr(n->left, a, canemitcode);
|
||||
// } else
|
||||
// if(n->left->op == OLITERAL) {
|
||||
// v = n->left->vconst;
|
||||
// naddr(n->right, a, canemitcode);
|
||||
// } else
|
||||
// goto bad;
|
||||
// a->offset += v;
|
||||
// break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* return Axxx for Oxxx on type t.
|
||||
*/
|
||||
|
@ -834,6 +834,7 @@ enum
|
||||
FREGRET = REG_X0,
|
||||
REGSP = REG_SP,
|
||||
REGTMP = REG_DI,
|
||||
REGCTXT = REG_DX,
|
||||
REGEXT = REG_R15, /* compiler allocates external registers R15 down */
|
||||
FREGMIN = REG_X0+5, /* first register variable */
|
||||
FREGEXT = REG_X0+15, /* first external register */
|
||||
|
@ -46,8 +46,9 @@ main(int argc, char **argv)
|
||||
arch.thestring = thestring;
|
||||
arch.thelinkarch = thelinkarch;
|
||||
arch.typedefs = typedefs;
|
||||
arch.REGSP = REGSP;
|
||||
arch.REGCTXT = REGCTXT;
|
||||
arch.MAXWIDTH = MAXWIDTH;
|
||||
arch.afunclit = afunclit;
|
||||
arch.anyregalloc = anyregalloc;
|
||||
arch.betypeinit = betypeinit;
|
||||
arch.bgen = bgen;
|
||||
@ -57,37 +58,15 @@ main(int argc, char **argv)
|
||||
arch.cgen_callinter = cgen_callinter;
|
||||
arch.cgen_ret = cgen_ret;
|
||||
arch.clearfat = clearfat;
|
||||
arch.clearp = clearp;
|
||||
arch.defframe = defframe;
|
||||
arch.dgostringptr = dgostringptr;
|
||||
arch.dgostrlitptr = dgostrlitptr;
|
||||
arch.dsname = dsname;
|
||||
arch.dsymptr = dsymptr;
|
||||
arch.dumpdata = dumpdata;
|
||||
arch.dumpit = dumpit;
|
||||
arch.excise = excise;
|
||||
arch.expandchecks = expandchecks;
|
||||
arch.fixautoused = fixautoused;
|
||||
arch.gclean = gclean;
|
||||
arch.gdata = gdata;
|
||||
arch.gdatacomplex = gdatacomplex;
|
||||
arch.gdatastring = gdatastring;
|
||||
arch.ggloblnod = ggloblnod;
|
||||
arch.ggloblsym = ggloblsym;
|
||||
arch.ginit = ginit;
|
||||
arch.gins = gins;
|
||||
arch.ginscall = ginscall;
|
||||
arch.gjmp = gjmp;
|
||||
arch.gtrack = gtrack;
|
||||
arch.gused = gused;
|
||||
arch.igen = igen;
|
||||
arch.isfat = isfat;
|
||||
arch.linkarchinit = linkarchinit;
|
||||
arch.markautoused = markautoused;
|
||||
arch.naddr = naddr;
|
||||
arch.newplist = newplist;
|
||||
arch.nodarg = nodarg;
|
||||
arch.patch = patch;
|
||||
arch.proginfo = proginfo;
|
||||
arch.regalloc = regalloc;
|
||||
arch.regfree = regfree;
|
||||
@ -96,7 +75,6 @@ main(int argc, char **argv)
|
||||
arch.sameaddr = sameaddr;
|
||||
arch.smallindir = smallindir;
|
||||
arch.stackaddr = stackaddr;
|
||||
arch.unpatch = unpatch;
|
||||
|
||||
gcmain(argc, argv);
|
||||
}
|
||||
|
@ -17,10 +17,7 @@ enum
|
||||
Fpop2 = 1<<2,
|
||||
};
|
||||
|
||||
EXTERN int32 dynloc;
|
||||
EXTERN uchar reg[MAXREG];
|
||||
EXTERN int32 pcloc; // instruction counter
|
||||
EXTERN Strlit emptystring;
|
||||
EXTERN Node* panicdiv;
|
||||
extern uint32 unmappedzero;
|
||||
|
||||
|
@ -106,52 +106,6 @@ appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int tre
|
||||
return q;
|
||||
}
|
||||
|
||||
// Sweep the prog list to mark any used nodes.
|
||||
void
|
||||
markautoused(Prog* p)
|
||||
{
|
||||
for (; p; p = p->link) {
|
||||
if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
|
||||
continue;
|
||||
|
||||
if (p->from.node)
|
||||
((Node*)(p->from.node))->used = 1;
|
||||
|
||||
if (p->to.node)
|
||||
((Node*)(p->to.node))->used = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
|
||||
void
|
||||
fixautoused(Prog* p)
|
||||
{
|
||||
Prog **lp;
|
||||
|
||||
for (lp=&p; (p=*lp) != P; ) {
|
||||
if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
|
||||
*lp = p->link;
|
||||
continue;
|
||||
}
|
||||
if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
|
||||
// Cannot remove VARDEF instruction, because - unlike TYPE handled above -
|
||||
// VARDEFs are interspersed with other code, and a jump might be using the
|
||||
// VARDEF as a target. Replace with a no-op instead. A later pass will remove
|
||||
// the no-ops.
|
||||
nopout(p);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p->from.type == TYPE_MEM && p->from.name == NAME_AUTO && p->from.node)
|
||||
p->from.offset += ((Node*)(p->from.node))->stkdelta;
|
||||
|
||||
if (p->to.type == TYPE_MEM && p->to.name == NAME_AUTO && p->to.node)
|
||||
p->to.offset += ((Node*)(p->to.node))->stkdelta;
|
||||
|
||||
lp = &p->link;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
clearfat(Node *nl)
|
||||
{
|
||||
@ -660,18 +614,6 @@ 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate division.
|
||||
* caller must set:
|
||||
|
@ -1,257 +0,0 @@
|
||||
// Derived from Inferno utils/8c/swt.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/8c/swt.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 <u.h>
|
||||
#include <libc.h>
|
||||
#include "gg.h"
|
||||
|
||||
int
|
||||
dsname(Sym *s, int off, char *t, int n)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = n;
|
||||
p->from.sym = linksym(s);
|
||||
|
||||
p->to.type = TYPE_SCONST;
|
||||
memmove(p->to.u.sval, t, n);
|
||||
return off + n;
|
||||
}
|
||||
|
||||
/*
|
||||
* make a refer to the data s, s+len
|
||||
* emitting DATA if needed.
|
||||
*/
|
||||
void
|
||||
datastring(char *s, int len, Addr *a)
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
sym = stringsym(s, len);
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_EXTERN;
|
||||
a->sym = linksym(sym);
|
||||
a->node = sym->def;
|
||||
a->offset = widthptr+4; // skip header
|
||||
a->etype = TINT32;
|
||||
}
|
||||
|
||||
/*
|
||||
* make a refer to the string sval,
|
||||
* emitting DATA if needed.
|
||||
*/
|
||||
void
|
||||
datagostring(Strlit *sval, Addr *a)
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
sym = stringsym(sval->s, sval->len);
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_EXTERN;
|
||||
a->sym = linksym(sym);
|
||||
a->node = sym->def;
|
||||
a->offset = 0; // header
|
||||
a->etype = TSTRING;
|
||||
}
|
||||
|
||||
void
|
||||
gdata(Node *nam, Node *nr, int wid)
|
||||
{
|
||||
Prog *p;
|
||||
vlong v;
|
||||
|
||||
if(nr->op == OLITERAL) {
|
||||
switch(nr->val.ctype) {
|
||||
case CTCPLX:
|
||||
gdatacomplex(nam, nr->val.u.cval);
|
||||
return;
|
||||
case CTSTR:
|
||||
gdatastring(nam, nr->val.u.sval);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(wid == 8 && is64(nr->type)) {
|
||||
v = mpgetfix(nr->val.u.xval);
|
||||
p = gins(ADATA, nam, nodintconst(v));
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = 4;
|
||||
p = gins(ADATA, nam, nodintconst(v>>32));
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = 4;
|
||||
p->from.offset += 4;
|
||||
return;
|
||||
}
|
||||
p = gins(ADATA, nam, nr);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = wid;
|
||||
}
|
||||
|
||||
void
|
||||
gdatacomplex(Node *nam, Mpcplx *cval)
|
||||
{
|
||||
Prog *p;
|
||||
int w;
|
||||
|
||||
w = cplxsubtype(nam->type->etype);
|
||||
w = types[w]->width;
|
||||
|
||||
p = gins(ADATA, nam, N);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = w;
|
||||
p->to.type = TYPE_FCONST;
|
||||
p->to.u.dval = mpgetflt(&cval->real);
|
||||
|
||||
p = gins(ADATA, nam, N);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = w;
|
||||
p->from.offset += w;
|
||||
p->to.type = TYPE_FCONST;
|
||||
p->to.u.dval = mpgetflt(&cval->imag);
|
||||
}
|
||||
|
||||
void
|
||||
gdatastring(Node *nam, Strlit *sval)
|
||||
{
|
||||
Prog *p;
|
||||
Node nod1;
|
||||
|
||||
p = gins(ADATA, nam, N);
|
||||
datastring(sval->s, sval->len, &p->to);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = types[tptr]->width;
|
||||
p->to.type = TYPE_ADDR;
|
||||
//print("%P\n", p);
|
||||
|
||||
nodconst(&nod1, types[TINT32], sval->len);
|
||||
p = gins(ADATA, nam, &nod1);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = types[TINT32]->width;
|
||||
p->from.offset += types[tptr]->width;
|
||||
}
|
||||
|
||||
int
|
||||
dstringptr(Sym *s, int off, char *str)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
off = rnd(off, widthptr);
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthptr;
|
||||
|
||||
datastring(str, strlen(str)+1, &p->to);
|
||||
p->to.type = TYPE_ADDR;
|
||||
p->to.etype = TINT32;
|
||||
off += widthptr;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
int
|
||||
dgostrlitptr(Sym *s, int off, Strlit *lit)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
if(lit == nil)
|
||||
return duintptr(s, off, 0);
|
||||
|
||||
off = rnd(off, widthptr);
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthptr;
|
||||
datagostring(lit, &p->to);
|
||||
p->to.type = TYPE_ADDR;
|
||||
p->to.etype = TINT32;
|
||||
off += widthptr;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
int
|
||||
dgostringptr(Sym *s, int off, char *str)
|
||||
{
|
||||
int n;
|
||||
Strlit *lit;
|
||||
|
||||
if(str == nil)
|
||||
return duintptr(s, off, 0);
|
||||
|
||||
n = strlen(str);
|
||||
lit = mal(sizeof *lit + n);
|
||||
strcpy(lit->s, str);
|
||||
lit->len = n;
|
||||
return dgostrlitptr(s, off, lit);
|
||||
}
|
||||
|
||||
int
|
||||
dsymptr(Sym *s, int off, Sym *x, int xoff)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
off = rnd(off, widthptr);
|
||||
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthptr;
|
||||
p->to.type = TYPE_ADDR;
|
||||
p->to.name = NAME_EXTERN;
|
||||
p->to.sym = linksym(x);
|
||||
p->to.offset = xoff;
|
||||
off += widthptr;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
void
|
||||
nopout(Prog *p)
|
||||
{
|
||||
p->as = ANOP;
|
||||
p->from = zprog.from;
|
||||
p->to = zprog.to;
|
||||
}
|
||||
|
@ -41,225 +41,6 @@ uint32 unmappedzero = 4096;
|
||||
#define CASE(a,b) (((a)<<16)|((b)<<0))
|
||||
/*c2go int CASE(int, int);*/
|
||||
|
||||
void
|
||||
clearp(Prog *p)
|
||||
{
|
||||
p->as = AEND;
|
||||
p->from.type = TYPE_NONE;
|
||||
p->from.index = TYPE_NONE;
|
||||
p->to.type = TYPE_NONE;
|
||||
p->to.index = TYPE_NONE;
|
||||
p->pc = pcloc;
|
||||
pcloc++;
|
||||
}
|
||||
|
||||
static int ddumped;
|
||||
static Prog *dfirst;
|
||||
static Prog *dpc;
|
||||
|
||||
/*
|
||||
* generate and return proc with p->as = as,
|
||||
* linked into program. pc is next instruction.
|
||||
*/
|
||||
Prog*
|
||||
prog(int as)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
if(as == ADATA || as == AGLOBL) {
|
||||
if(ddumped)
|
||||
fatal("already dumped data");
|
||||
if(dpc == nil) {
|
||||
dpc = mal(sizeof(*dpc));
|
||||
dfirst = dpc;
|
||||
}
|
||||
p = dpc;
|
||||
dpc = mal(sizeof(*dpc));
|
||||
p->link = dpc;
|
||||
} else {
|
||||
p = pc;
|
||||
pc = mal(sizeof(*pc));
|
||||
clearp(pc);
|
||||
p->link = pc;
|
||||
}
|
||||
|
||||
if(lineno == 0) {
|
||||
if(debug['K'])
|
||||
warn("prog: line 0");
|
||||
}
|
||||
|
||||
p->as = as;
|
||||
p->lineno = lineno;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
dumpdata(void)
|
||||
{
|
||||
ddumped = 1;
|
||||
if(dfirst == nil)
|
||||
return;
|
||||
newplist();
|
||||
*pc = *dfirst;
|
||||
pc = dpc;
|
||||
clearp(pc);
|
||||
}
|
||||
|
||||
/*
|
||||
* generate a branch.
|
||||
* t is ignored.
|
||||
* likely values are for branch prediction:
|
||||
* -1 unlikely
|
||||
* 0 no opinion
|
||||
* +1 likely
|
||||
*/
|
||||
Prog*
|
||||
gbranch(int as, Type *t, int likely)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
USED(t);
|
||||
p = prog(as);
|
||||
p->to.type = TYPE_BRANCH;
|
||||
p->to.u.branch = P;
|
||||
if(likely != 0) {
|
||||
p->from.type = TYPE_CONST;
|
||||
p->from.offset = likely > 0;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* patch previous branch to jump to to.
|
||||
*/
|
||||
void
|
||||
patch(Prog *p, Prog *to)
|
||||
{
|
||||
if(p->to.type != TYPE_BRANCH)
|
||||
fatal("patch: not a branch");
|
||||
p->to.u.branch = to;
|
||||
p->to.offset = to->pc;
|
||||
}
|
||||
|
||||
Prog*
|
||||
unpatch(Prog *p)
|
||||
{
|
||||
Prog *q;
|
||||
|
||||
if(p->to.type != TYPE_BRANCH)
|
||||
fatal("unpatch: not a branch");
|
||||
q = p->to.u.branch;
|
||||
p->to.u.branch = P;
|
||||
p->to.offset = 0;
|
||||
return q;
|
||||
}
|
||||
|
||||
/*
|
||||
* start a new Prog list.
|
||||
*/
|
||||
Plist*
|
||||
newplist(void)
|
||||
{
|
||||
Plist *pl;
|
||||
|
||||
pl = linknewplist(ctxt);
|
||||
|
||||
pc = mal(sizeof(*pc));
|
||||
clearp(pc);
|
||||
pl->firstpc = pc;
|
||||
|
||||
return pl;
|
||||
}
|
||||
|
||||
void
|
||||
gused(Node *n)
|
||||
{
|
||||
gins(ANOP, n, N); // used
|
||||
}
|
||||
|
||||
Prog*
|
||||
gjmp(Prog *to)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gbranch(AJMP, T, 0);
|
||||
if(to != P)
|
||||
patch(p, to);
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
ggloblnod(Node *nam)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(AGLOBL, nam, N);
|
||||
p->lineno = nam->lineno;
|
||||
p->from.sym->gotype = linksym(ngotype(nam));
|
||||
p->to.sym = nil;
|
||||
p->to.type = TYPE_CONST;
|
||||
p->to.offset = nam->type->width;
|
||||
if(nam->readonly)
|
||||
p->from3.offset = RODATA;
|
||||
if(nam->type != T && !haspointers(nam->type))
|
||||
p->from3.offset |= NOPTR;
|
||||
}
|
||||
|
||||
void
|
||||
ggloblsym(Sym *s, int32 width, int8 flags)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(AGLOBL, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.index = REG_NONE;
|
||||
p->from.sym = linksym(s);
|
||||
p->to.type = TYPE_CONST;
|
||||
p->to.index = REG_NONE;
|
||||
p->to.offset = width;
|
||||
p->from3.offset = flags;
|
||||
}
|
||||
|
||||
void
|
||||
gtrack(Sym *s)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(AUSEFIELD, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
}
|
||||
|
||||
int
|
||||
isfat(Type *t)
|
||||
{
|
||||
if(t != T)
|
||||
switch(t->etype) {
|
||||
case TSTRUCT:
|
||||
case TARRAY:
|
||||
case TSTRING:
|
||||
case TINTER: // maybe remove later
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* naddr of func generates code for address of func.
|
||||
* if using opcode that can take address implicitly,
|
||||
* call afunclit to fix up the argument.
|
||||
*/
|
||||
void
|
||||
afunclit(Addr *a, Node *n)
|
||||
{
|
||||
if(a->type == TYPE_ADDR && a->name == NAME_EXTERN) {
|
||||
a->type = TYPE_MEM;
|
||||
a->sym = linksym(n->sym);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* return Axxx for Oxxx on type t.
|
||||
*/
|
||||
@ -1001,105 +782,6 @@ regfree(Node *n)
|
||||
fatal("regfree %R", i);
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize n to be register r of type t.
|
||||
*/
|
||||
void
|
||||
nodreg(Node *n, Type *t, int r)
|
||||
{
|
||||
if(t == T)
|
||||
fatal("nodreg: t nil");
|
||||
|
||||
memset(n, 0, sizeof(*n));
|
||||
n->op = OREGISTER;
|
||||
n->addable = 1;
|
||||
ullmancalc(n);
|
||||
n->val.u.reg = r;
|
||||
n->type = t;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize n to be indirect of register r; n is type t.
|
||||
*/
|
||||
void
|
||||
nodindreg(Node *n, Type *t, int r)
|
||||
{
|
||||
nodreg(n, t, r);
|
||||
n->op = OINDREG;
|
||||
}
|
||||
|
||||
Node*
|
||||
nodarg(Type *t, int fp)
|
||||
{
|
||||
Node *n;
|
||||
NodeList *l;
|
||||
Type *first;
|
||||
Iter savet;
|
||||
|
||||
// entire argument struct, not just one arg
|
||||
switch(t->etype) {
|
||||
default:
|
||||
fatal("nodarg %T", t);
|
||||
|
||||
case TSTRUCT:
|
||||
if(!t->funarg)
|
||||
fatal("nodarg: TSTRUCT but not funarg");
|
||||
n = nod(ONAME, N, N);
|
||||
n->sym = lookup(".args");
|
||||
n->type = t;
|
||||
first = structfirst(&savet, &t);
|
||||
if(first == nil)
|
||||
fatal("nodarg: bad struct");
|
||||
if(first->width == BADWIDTH)
|
||||
fatal("nodarg: offset not computed for %T", t);
|
||||
n->xoffset = first->width;
|
||||
n->addable = 1;
|
||||
break;
|
||||
|
||||
case TFIELD:
|
||||
if(fp == 1 && t->sym != S && !isblanksym(t->sym)) {
|
||||
for(l=curfn->dcl; l; l=l->next) {
|
||||
n = l->n;
|
||||
if((n->class == PPARAM || n->class == PPARAMOUT) && n->sym == t->sym)
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
n = nod(ONAME, N, N);
|
||||
n->type = t->type;
|
||||
n->sym = t->sym;
|
||||
if(t->width == BADWIDTH)
|
||||
fatal("nodarg: offset not computed for %T", t);
|
||||
n->xoffset = t->width;
|
||||
n->addable = 1;
|
||||
n->orig = t->nname;
|
||||
break;
|
||||
}
|
||||
|
||||
// Rewrite argument named _ to __,
|
||||
// or else the assignment to _ will be
|
||||
// discarded during code generation.
|
||||
if(isblank(n))
|
||||
n->sym = lookup("__");
|
||||
|
||||
switch(fp) {
|
||||
default:
|
||||
fatal("nodarg %T %d", t, fp);
|
||||
|
||||
case 0: // output arg
|
||||
n->op = OINDREG;
|
||||
n->val.u.reg = REG_SP;
|
||||
break;
|
||||
|
||||
case 1: // input arg
|
||||
n->class = PPARAM;
|
||||
break;
|
||||
}
|
||||
|
||||
n->typecheck = 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate
|
||||
* as $c, reg
|
||||
@ -1142,26 +824,6 @@ ncon(uint32 i)
|
||||
return &n;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this node a memory operand?
|
||||
*/
|
||||
int
|
||||
ismem(Node *n)
|
||||
{
|
||||
switch(n->op) {
|
||||
case OITAB:
|
||||
case OSPTR:
|
||||
case OLEN:
|
||||
case OCAP:
|
||||
case OINDREG:
|
||||
case ONAME:
|
||||
case OPARAM:
|
||||
case OCLOSUREVAR:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
Node sclean[10];
|
||||
int nsclean;
|
||||
|
||||
@ -1408,8 +1070,8 @@ gmove(Node *f, Node *t)
|
||||
gins(AMOVL, &flo, &tlo);
|
||||
gins(AMOVL, &fhi, &thi);
|
||||
} else {
|
||||
nodreg(&r1, t->type, REG_AX);
|
||||
nodreg(&r2, t->type, REG_DX);
|
||||
nodreg(&r1, types[TUINT32], REG_AX);
|
||||
nodreg(&r2, types[TUINT32], REG_DX);
|
||||
gins(AMOVL, &flo, &r1);
|
||||
gins(AMOVL, &fhi, &r2);
|
||||
gins(AMOVL, &r1, &tlo);
|
||||
@ -2165,209 +1827,6 @@ gins(int as, Node *f, Node *t)
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate code to compute n;
|
||||
* make a refer to result.
|
||||
*/
|
||||
void
|
||||
naddr(Node *n, Addr *a, int canemitcode)
|
||||
{
|
||||
Sym *s;
|
||||
|
||||
a->scale = 0;
|
||||
a->reg = REG_NONE;
|
||||
a->index = REG_NONE;
|
||||
a->type = TYPE_NONE;
|
||||
a->name = NAME_NONE;
|
||||
a->gotype = nil;
|
||||
a->node = N;
|
||||
if(n == N)
|
||||
return;
|
||||
|
||||
switch(n->op) {
|
||||
default:
|
||||
fatal("naddr: bad %O %D", n->op, a);
|
||||
break;
|
||||
|
||||
case OREGISTER:
|
||||
a->type = TYPE_REG;
|
||||
a->reg = n->val.u.reg;
|
||||
a->sym = nil;
|
||||
break;
|
||||
|
||||
case OINDREG:
|
||||
a->type = TYPE_MEM;
|
||||
a->reg = n->val.u.reg;
|
||||
a->sym = linksym(n->sym);
|
||||
a->offset = n->xoffset;
|
||||
break;
|
||||
|
||||
case OPARAM:
|
||||
// n->left is PHEAP ONAME for stack parameter.
|
||||
// compute address of actual parameter on stack.
|
||||
a->etype = n->left->type->etype;
|
||||
a->width = n->left->type->width;
|
||||
a->offset = n->xoffset;
|
||||
a->sym = linksym(n->left->sym);
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_PARAM;
|
||||
a->node = n->left->orig;
|
||||
break;
|
||||
|
||||
case OCLOSUREVAR:
|
||||
if(!curfn->needctxt)
|
||||
fatal("closurevar without needctxt");
|
||||
a->type = TYPE_MEM;
|
||||
a->reg = REG_DX;
|
||||
a->offset = n->xoffset;
|
||||
a->sym = nil;
|
||||
break;
|
||||
|
||||
case OCFUNC:
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->sym = linksym(n->left->sym);
|
||||
break;
|
||||
|
||||
case ONAME:
|
||||
a->etype = 0;
|
||||
a->width = 0;
|
||||
if(n->type != T) {
|
||||
a->etype = simtype[n->type->etype];
|
||||
dowidth(n->type);
|
||||
a->width = n->type->width;
|
||||
}
|
||||
a->offset = n->xoffset;
|
||||
s = n->sym;
|
||||
a->node = n->orig;
|
||||
//if(a->node >= (Node*)&n)
|
||||
// fatal("stack node");
|
||||
if(s == S)
|
||||
s = lookup(".noname");
|
||||
if(n->method) {
|
||||
if(n->type != T)
|
||||
if(n->type->sym != S)
|
||||
if(n->type->sym->pkg != nil)
|
||||
s = pkglookup(s->name, n->type->sym->pkg);
|
||||
}
|
||||
|
||||
switch(n->class) {
|
||||
default:
|
||||
fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
|
||||
case PEXTERN:
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_EXTERN;
|
||||
break;
|
||||
case PAUTO:
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_AUTO;
|
||||
break;
|
||||
case PPARAM:
|
||||
case PPARAMOUT:
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_PARAM;
|
||||
break;
|
||||
case PFUNC:
|
||||
a->type = TYPE_ADDR;
|
||||
a->name = NAME_EXTERN;
|
||||
s = funcsym(s);
|
||||
break;
|
||||
}
|
||||
a->sym = linksym(s);
|
||||
break;
|
||||
|
||||
case OLITERAL:
|
||||
switch(n->val.ctype) {
|
||||
default:
|
||||
fatal("naddr: const %lT", n->type);
|
||||
break;
|
||||
case CTFLT:
|
||||
a->type = TYPE_FCONST;
|
||||
a->u.dval = mpgetflt(n->val.u.fval);
|
||||
break;
|
||||
case CTINT:
|
||||
case CTRUNE:
|
||||
a->sym = nil;
|
||||
a->type = TYPE_CONST;
|
||||
a->offset = mpgetfix(n->val.u.xval);
|
||||
break;
|
||||
case CTSTR:
|
||||
datagostring(n->val.u.sval, a);
|
||||
break;
|
||||
case CTBOOL:
|
||||
a->sym = nil;
|
||||
a->type = TYPE_CONST;
|
||||
a->offset = n->val.u.bval;
|
||||
break;
|
||||
case CTNIL:
|
||||
a->sym = nil;
|
||||
a->type = TYPE_CONST;
|
||||
a->offset = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case OADDR:
|
||||
naddr(n->left, a, canemitcode);
|
||||
if(a->type != TYPE_MEM)
|
||||
fatal("naddr: OADDR %D", a);
|
||||
a->type = TYPE_ADDR;
|
||||
break;
|
||||
|
||||
case OITAB:
|
||||
// itable of interface value
|
||||
naddr(n->left, a, canemitcode);
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // len(nil)
|
||||
a->etype = tptr;
|
||||
a->width = widthptr;
|
||||
break;
|
||||
|
||||
case OSPTR:
|
||||
// pointer in a string or slice
|
||||
naddr(n->left, a, canemitcode);
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // ptr(nil)
|
||||
a->etype = simtype[tptr];
|
||||
a->offset += Array_array;
|
||||
a->width = widthptr;
|
||||
break;
|
||||
|
||||
case OLEN:
|
||||
// len of string or slice
|
||||
naddr(n->left, a, canemitcode);
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // len(nil)
|
||||
a->etype = TUINT32;
|
||||
a->offset += Array_nel;
|
||||
a->width = 4;
|
||||
break;
|
||||
|
||||
case OCAP:
|
||||
// cap of string or slice
|
||||
naddr(n->left, a, canemitcode);
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // cap(nil)
|
||||
a->etype = TUINT32;
|
||||
a->offset += Array_cap;
|
||||
a->width = 4;
|
||||
break;
|
||||
|
||||
// case OADD:
|
||||
// if(n->right->op == OLITERAL) {
|
||||
// v = n->right->vconst;
|
||||
// naddr(n->left, a, canemitcode);
|
||||
// } else
|
||||
// if(n->left->op == OLITERAL) {
|
||||
// v = n->left->vconst;
|
||||
// naddr(n->right, a, canemitcode);
|
||||
// } else
|
||||
// goto bad;
|
||||
// a->offset += v;
|
||||
// break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
dotaddable(Node *n, Node *n1)
|
||||
{
|
||||
|
@ -634,6 +634,7 @@ enum
|
||||
FREGRET = REG_F0,
|
||||
REGSP = REG_SP,
|
||||
REGTMP = REG_DI,
|
||||
REGCTXT = REG_DX,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -53,8 +53,9 @@ main(int argc, char **argv)
|
||||
arch.thestring = thestring;
|
||||
arch.thelinkarch = thelinkarch;
|
||||
arch.typedefs = typedefs;
|
||||
arch.REGSP = REGSP;
|
||||
arch.REGCTXT = REGCTXT;
|
||||
arch.MAXWIDTH = MAXWIDTH;
|
||||
arch.afunclit = afunclit;
|
||||
arch.anyregalloc = anyregalloc;
|
||||
arch.betypeinit = betypeinit;
|
||||
arch.bgen = bgen;
|
||||
@ -64,37 +65,15 @@ main(int argc, char **argv)
|
||||
arch.cgen_callinter = cgen_callinter;
|
||||
arch.cgen_ret = cgen_ret;
|
||||
arch.clearfat = clearfat;
|
||||
arch.clearp = clearp;
|
||||
arch.defframe = defframe;
|
||||
arch.dgostringptr = dgostringptr;
|
||||
arch.dgostrlitptr = dgostrlitptr;
|
||||
arch.dsname = dsname;
|
||||
arch.dsymptr = dsymptr;
|
||||
arch.dumpdata = dumpdata;
|
||||
arch.dumpit = dumpit;
|
||||
arch.excise = excise;
|
||||
arch.expandchecks = expandchecks;
|
||||
arch.fixautoused = fixautoused;
|
||||
arch.gclean = gclean;
|
||||
arch.gdata = gdata;
|
||||
arch.gdatacomplex = gdatacomplex;
|
||||
arch.gdatastring = gdatastring;
|
||||
arch.ggloblnod = ggloblnod;
|
||||
arch.ggloblsym = ggloblsym;
|
||||
arch.ginit = ginit;
|
||||
arch.gins = gins;
|
||||
arch.ginscall = ginscall;
|
||||
arch.gjmp = gjmp;
|
||||
arch.gtrack = gtrack;
|
||||
arch.gused = gused;
|
||||
arch.igen = igen;
|
||||
arch.isfat = isfat;
|
||||
arch.linkarchinit = linkarchinit;
|
||||
arch.markautoused = markautoused;
|
||||
arch.naddr = naddr;
|
||||
arch.newplist = newplist;
|
||||
arch.nodarg = nodarg;
|
||||
arch.patch = patch;
|
||||
arch.proginfo = proginfo;
|
||||
arch.regalloc = regalloc;
|
||||
arch.regfree = regfree;
|
||||
@ -103,7 +82,6 @@ main(int argc, char **argv)
|
||||
arch.sameaddr = sameaddr;
|
||||
arch.smallindir = smallindir;
|
||||
arch.stackaddr = stackaddr;
|
||||
arch.unpatch = unpatch;
|
||||
|
||||
gcmain(argc, argv);
|
||||
}
|
||||
|
@ -12,10 +12,7 @@
|
||||
// TODO(minux): Remove when no longer used.
|
||||
#define noimpl sysfatal("%s not implemented (%s:%d).", __func__, __FILE__, __LINE__)
|
||||
|
||||
EXTERN int32 dynloc;
|
||||
EXTERN uchar reg[NREG+NFREG];
|
||||
EXTERN int32 pcloc; // instruction counter
|
||||
EXTERN Strlit emptystring;
|
||||
EXTERN Node* panicdiv;
|
||||
extern vlong unmappedzero;
|
||||
|
||||
|
@ -113,51 +113,6 @@ appendpp(Prog *p, int as, int ftype, int freg, vlong foffset, int ttype, int tre
|
||||
return q;
|
||||
}
|
||||
|
||||
// Sweep the prog list to mark any used nodes.
|
||||
void
|
||||
markautoused(Prog *p)
|
||||
{
|
||||
for (; p; p = p->link) {
|
||||
if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
|
||||
continue;
|
||||
|
||||
if (p->from.node)
|
||||
((Node*)(p->from.node))->used = 1;
|
||||
|
||||
if (p->to.node)
|
||||
((Node*)(p->to.node))->used = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
|
||||
void
|
||||
fixautoused(Prog *p)
|
||||
{
|
||||
Prog **lp;
|
||||
|
||||
for (lp=&p; (p=*lp) != P; ) {
|
||||
if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
|
||||
*lp = p->link;
|
||||
continue;
|
||||
}
|
||||
if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
|
||||
// Cannot remove VARDEF instruction, because - unlike TYPE handled above -
|
||||
// VARDEFs are interspersed with other code, and a jump might be using the
|
||||
// VARDEF as a target. Replace with a no-op instead. A later pass will remove
|
||||
// the no-ops.
|
||||
nopout(p);
|
||||
continue;
|
||||
}
|
||||
if (p->from.name == NAME_AUTO && p->from.node)
|
||||
p->from.offset += ((Node*)(p->from.node))->stkdelta;
|
||||
|
||||
if (p->to.name == NAME_AUTO && p->to.node)
|
||||
p->to.offset += ((Node*)(p->to.node))->stkdelta;
|
||||
|
||||
lp = &p->link;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* generate: BL reg, f
|
||||
* where both reg and f are registers.
|
||||
@ -226,7 +181,7 @@ ginscall(Node *f, int proc)
|
||||
gins(AUNDEF, N, N);
|
||||
break;
|
||||
}
|
||||
nodreg(®, types[tptr], REGENV);
|
||||
nodreg(®, types[tptr], REGCTXT);
|
||||
nodreg(&r1, types[tptr], REG_R3);
|
||||
gmove(f, ®);
|
||||
reg.op = OINDREG;
|
||||
@ -494,20 +449,6 @@ cgen_asop(Node *n)
|
||||
fatal("cgen_asop"); // no longer used
|
||||
}
|
||||
|
||||
int
|
||||
samereg(Node *a, Node *b)
|
||||
{
|
||||
if(a == N || b == N)
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate division.
|
||||
* generates one of:
|
||||
|
@ -1,250 +0,0 @@
|
||||
// Derived from Inferno utils/6c/swt.c
|
||||
// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.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 <u.h>
|
||||
#include <libc.h>
|
||||
#include "gg.h"
|
||||
|
||||
int
|
||||
dsname(Sym *s, int off, char *t, int n)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.offset = off;
|
||||
p->from.sym = linksym(s);
|
||||
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = n;
|
||||
|
||||
p->to.type = TYPE_SCONST;
|
||||
p->to.name = NAME_NONE;
|
||||
p->to.offset = 0;
|
||||
memmove(p->to.u.sval, t, n);
|
||||
return off + n;
|
||||
}
|
||||
|
||||
/*
|
||||
* make a refer to the data s, s+len
|
||||
* emitting DATA if needed.
|
||||
*/
|
||||
void
|
||||
datastring(char *s, int len, Addr *a)
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
sym = stringsym(s, len);
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_EXTERN;
|
||||
a->etype = simtype[TINT];
|
||||
a->offset = widthptr+widthint; // skip header
|
||||
a->reg = 0;
|
||||
a->sym = linksym(sym);
|
||||
a->node = sym->def;
|
||||
}
|
||||
|
||||
/*
|
||||
* make a refer to the string sval,
|
||||
* emitting DATA if needed.
|
||||
*/
|
||||
void
|
||||
datagostring(Strlit *sval, Addr *a)
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
sym = stringsym(sval->s, sval->len);
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_EXTERN;
|
||||
a->sym = linksym(sym);
|
||||
a->reg = 0;
|
||||
a->node = sym->def;
|
||||
a->offset = 0; // header
|
||||
a->etype = TSTRING;
|
||||
}
|
||||
|
||||
void
|
||||
gdata(Node *nam, Node *nr, int wid)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
if(nr->op == OLITERAL) {
|
||||
switch(nr->val.ctype) {
|
||||
case CTCPLX:
|
||||
gdatacomplex(nam, nr->val.u.cval);
|
||||
return;
|
||||
case CTSTR:
|
||||
gdatastring(nam, nr->val.u.sval);
|
||||
return;
|
||||
}
|
||||
}
|
||||
p = gins(ADATA, nam, nr);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = wid;
|
||||
}
|
||||
|
||||
void
|
||||
gdatacomplex(Node *nam, Mpcplx *cval)
|
||||
{
|
||||
Prog *p;
|
||||
int w;
|
||||
|
||||
w = cplxsubtype(nam->type->etype);
|
||||
w = types[w]->width;
|
||||
|
||||
p = gins(ADATA, nam, N);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = w;
|
||||
p->to.type = TYPE_FCONST;
|
||||
p->to.u.dval = mpgetflt(&cval->real);
|
||||
|
||||
p = gins(ADATA, nam, N);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = w;
|
||||
p->from.offset += w;
|
||||
p->to.type = TYPE_FCONST;
|
||||
p->to.u.dval = mpgetflt(&cval->imag);
|
||||
}
|
||||
|
||||
void
|
||||
gdatastring(Node *nam, Strlit *sval)
|
||||
{
|
||||
Prog *p;
|
||||
Node nod1;
|
||||
|
||||
p = gins(ADATA, nam, N);
|
||||
datastring(sval->s, sval->len, &p->to);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = types[tptr]->width;
|
||||
p->to.type = TYPE_ADDR;
|
||||
p->to.etype = simtype[tptr];
|
||||
|
||||
nodconst(&nod1, types[TINT], sval->len);
|
||||
p = gins(ADATA, nam, &nod1);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthint;
|
||||
p->from.offset += widthptr;
|
||||
}
|
||||
|
||||
int
|
||||
dstringptr(Sym *s, int off, char *str)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
off = rnd(off, widthptr);
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthptr;
|
||||
|
||||
datastring(str, strlen(str)+1, &p->to);
|
||||
p->to.type = TYPE_CONST;
|
||||
p->to.etype = simtype[TINT];
|
||||
off += widthptr;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
int
|
||||
dgostrlitptr(Sym *s, int off, Strlit *lit)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
if(lit == nil)
|
||||
return duintptr(s, off, 0);
|
||||
|
||||
off = rnd(off, widthptr);
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthptr;
|
||||
datagostring(lit, &p->to);
|
||||
p->to.type = TYPE_ADDR;
|
||||
p->to.etype = simtype[TINT];
|
||||
off += widthptr;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
int
|
||||
dgostringptr(Sym *s, int off, char *str)
|
||||
{
|
||||
int n;
|
||||
Strlit *lit;
|
||||
|
||||
if(str == nil)
|
||||
return duintptr(s, off, 0);
|
||||
|
||||
n = strlen(str);
|
||||
lit = mal(sizeof *lit + n);
|
||||
strcpy(lit->s, str);
|
||||
lit->len = n;
|
||||
return dgostrlitptr(s, off, lit);
|
||||
}
|
||||
|
||||
int
|
||||
dsymptr(Sym *s, int off, Sym *x, int xoff)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
off = rnd(off, widthptr);
|
||||
|
||||
p = gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthptr;
|
||||
p->to.type = TYPE_ADDR;
|
||||
p->to.name = NAME_EXTERN;
|
||||
p->to.sym = linksym(x);
|
||||
p->to.offset = xoff;
|
||||
off += widthptr;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
void
|
||||
nopout(Prog *p)
|
||||
{
|
||||
p->as = ANOP;
|
||||
p->from = zprog.from;
|
||||
p->from3 = zprog.from3;
|
||||
p->reg = zprog.reg;
|
||||
p->to = zprog.to;
|
||||
}
|
@ -38,227 +38,6 @@
|
||||
// At the same time, can raise StackBig in ../../runtime/stack.h.
|
||||
vlong unmappedzero = 4096;
|
||||
|
||||
void
|
||||
clearp(Prog *p)
|
||||
{
|
||||
*p = zprog;
|
||||
p->as = AEND;
|
||||
p->pc = pcloc;
|
||||
pcloc++;
|
||||
}
|
||||
|
||||
static int ddumped;
|
||||
static Prog *dfirst;
|
||||
static Prog *dpc;
|
||||
|
||||
/*
|
||||
* generate and return proc with p->as = as,
|
||||
* linked into program. pc is next instruction.
|
||||
*/
|
||||
Prog*
|
||||
prog(int as)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
if(as == ADATA || as == AGLOBL) {
|
||||
if(ddumped)
|
||||
fatal("already dumped data");
|
||||
if(dpc == nil) {
|
||||
dpc = mal(sizeof(*dpc));
|
||||
dfirst = dpc;
|
||||
}
|
||||
p = dpc;
|
||||
dpc = mal(sizeof(*dpc));
|
||||
p->link = dpc;
|
||||
p->reg = 0; // used for flags
|
||||
} else {
|
||||
p = pc;
|
||||
pc = mal(sizeof(*pc));
|
||||
clearp(pc);
|
||||
p->link = pc;
|
||||
}
|
||||
|
||||
if(lineno == 0) {
|
||||
if(debug['K'])
|
||||
warn("prog: line 0");
|
||||
}
|
||||
|
||||
p->as = as;
|
||||
p->lineno = lineno;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
dumpdata(void)
|
||||
{
|
||||
ddumped = 1;
|
||||
if(dfirst == nil)
|
||||
return;
|
||||
newplist();
|
||||
*pc = *dfirst;
|
||||
pc = dpc;
|
||||
clearp(pc);
|
||||
}
|
||||
|
||||
/*
|
||||
* generate a branch.
|
||||
* t is ignored.
|
||||
* likely values are for branch prediction:
|
||||
* -1 unlikely
|
||||
* 0 no opinion
|
||||
* +1 likely
|
||||
*/
|
||||
Prog*
|
||||
gbranch(int as, Type *t, int likely)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
USED(t);
|
||||
|
||||
p = prog(as);
|
||||
p->to.type = TYPE_BRANCH;
|
||||
p->to.u.branch = P;
|
||||
// TODO(minux): Enable this code.
|
||||
// Note: liblink used Bcc CR0, label form, so we need another way
|
||||
// to set likely/unlikely flag. Also note the y bit is not exactly
|
||||
// likely/unlikely bit.
|
||||
if(0 && as != ABR && likely != 0) {
|
||||
p->from.type = TYPE_CONST;
|
||||
p->from.offset = likely > 0;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* patch previous branch to jump to to.
|
||||
*/
|
||||
void
|
||||
patch(Prog *p, Prog *to)
|
||||
{
|
||||
if(p->to.type != TYPE_BRANCH)
|
||||
fatal("patch: not a branch");
|
||||
p->to.u.branch = to;
|
||||
p->to.offset = to->pc;
|
||||
}
|
||||
|
||||
Prog*
|
||||
unpatch(Prog *p)
|
||||
{
|
||||
Prog *q;
|
||||
|
||||
if(p->to.type != TYPE_BRANCH)
|
||||
fatal("unpatch: not a branch");
|
||||
q = p->to.u.branch;
|
||||
p->to.u.branch = P;
|
||||
p->to.offset = 0;
|
||||
return q;
|
||||
}
|
||||
|
||||
/*
|
||||
* start a new Prog list.
|
||||
*/
|
||||
Plist*
|
||||
newplist(void)
|
||||
{
|
||||
Plist *pl;
|
||||
|
||||
pl = linknewplist(ctxt);
|
||||
|
||||
pc = mal(sizeof(*pc));
|
||||
clearp(pc);
|
||||
pl->firstpc = pc;
|
||||
|
||||
return pl;
|
||||
}
|
||||
|
||||
void
|
||||
gused(Node *n)
|
||||
{
|
||||
gins(ANOP, n, N); // used
|
||||
}
|
||||
|
||||
Prog*
|
||||
gjmp(Prog *to)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gbranch(ABR, T, 0);
|
||||
if(to != P)
|
||||
patch(p, to);
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
ggloblnod(Node *nam)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(AGLOBL, nam, N);
|
||||
p->lineno = nam->lineno;
|
||||
p->from.sym->gotype = linksym(ngotype(nam));
|
||||
p->to.sym = nil;
|
||||
p->to.type = TYPE_CONST;
|
||||
p->to.offset = nam->type->width;
|
||||
if(nam->readonly)
|
||||
p->from3.offset = RODATA;
|
||||
if(nam->type != T && !haspointers(nam->type))
|
||||
p->from3.offset |= NOPTR;
|
||||
}
|
||||
|
||||
void
|
||||
gtrack(Sym *s)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(AUSEFIELD, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
}
|
||||
|
||||
void
|
||||
ggloblsym(Sym *s, int32 width, int8 flags)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gins(AGLOBL, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->to.type = TYPE_CONST;
|
||||
p->to.name = NAME_NONE;
|
||||
p->to.offset = width;
|
||||
p->from3.offset = flags;
|
||||
}
|
||||
|
||||
int
|
||||
isfat(Type *t)
|
||||
{
|
||||
if(t != T)
|
||||
switch(t->etype) {
|
||||
case TSTRUCT:
|
||||
case TARRAY:
|
||||
case TSTRING:
|
||||
case TINTER: // maybe remove later
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* naddr of func generates code for address of func.
|
||||
* if using opcode that can take address implicitly,
|
||||
* call afunclit to fix up the argument.
|
||||
*/
|
||||
void
|
||||
afunclit(Addr *a, Node *n)
|
||||
{
|
||||
if(a->type == TYPE_ADDR && a->name == NAME_EXTERN) {
|
||||
a->type = TYPE_MEM;
|
||||
a->sym = linksym(n->sym);
|
||||
}
|
||||
}
|
||||
|
||||
static int resvd[] =
|
||||
{
|
||||
REGZERO,
|
||||
@ -431,109 +210,6 @@ regfree(Node *n)
|
||||
regpc[i] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize n to be register r of type t.
|
||||
*/
|
||||
void
|
||||
nodreg(Node *n, Type *t, int r)
|
||||
{
|
||||
if(t == T)
|
||||
fatal("nodreg: t nil");
|
||||
|
||||
memset(n, 0, sizeof(*n));
|
||||
n->op = OREGISTER;
|
||||
n->addable = 1;
|
||||
ullmancalc(n);
|
||||
n->val.u.reg = r;
|
||||
n->type = t;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize n to be indirect of register r; n is type t.
|
||||
*/
|
||||
void
|
||||
nodindreg(Node *n, Type *t, int r)
|
||||
{
|
||||
nodreg(n, t, r);
|
||||
n->op = OINDREG;
|
||||
}
|
||||
|
||||
Node*
|
||||
nodarg(Type *t, int fp)
|
||||
{
|
||||
Node *n;
|
||||
NodeList *l;
|
||||
Type *first;
|
||||
Iter savet;
|
||||
|
||||
// entire argument struct, not just one arg
|
||||
if(t->etype == TSTRUCT && t->funarg) {
|
||||
n = nod(ONAME, N, N);
|
||||
n->sym = lookup(".args");
|
||||
n->type = t;
|
||||
first = structfirst(&savet, &t);
|
||||
if(first == nil)
|
||||
fatal("nodarg: bad struct");
|
||||
if(first->width == BADWIDTH)
|
||||
fatal("nodarg: offset not computed for %T", t);
|
||||
n->xoffset = first->width;
|
||||
n->addable = 1;
|
||||
goto fp;
|
||||
}
|
||||
|
||||
if(t->etype != TFIELD)
|
||||
fatal("nodarg: not field %T", t);
|
||||
|
||||
if(fp == 1) {
|
||||
for(l=curfn->dcl; l; l=l->next) {
|
||||
n = l->n;
|
||||
if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
n = nod(ONAME, N, N);
|
||||
n->type = t->type;
|
||||
n->sym = t->sym;
|
||||
|
||||
if(t->width == BADWIDTH)
|
||||
fatal("nodarg: offset not computed for %T", t);
|
||||
n->xoffset = t->width;
|
||||
n->addable = 1;
|
||||
n->orig = t->nname;
|
||||
|
||||
fp:
|
||||
// Rewrite argument named _ to __,
|
||||
// or else the assignment to _ will be
|
||||
// discarded during code generation.
|
||||
if(isblank(n))
|
||||
n->sym = lookup("__");
|
||||
|
||||
switch(fp) {
|
||||
default:
|
||||
fatal("nodarg %T %d", t, fp);
|
||||
|
||||
case 0: // output arg for calling another function
|
||||
n->op = OINDREG;
|
||||
n->val.u.reg = REGSP;
|
||||
n->xoffset += 8;
|
||||
break;
|
||||
|
||||
case 1: // input arg to current function
|
||||
n->class = PPARAM;
|
||||
break;
|
||||
|
||||
case 2: // offset output arg
|
||||
fatal("shouldn't be used");
|
||||
n->op = OINDREG;
|
||||
n->val.u.reg = REGSP;
|
||||
n->xoffset += types[tptr]->width;
|
||||
break;
|
||||
}
|
||||
n->typecheck = 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate
|
||||
* as $c, n
|
||||
@ -594,27 +270,6 @@ ginscon2(int as, Node *n2, vlong c)
|
||||
#define CASE(a,b) (((a)<<16)|((b)<<0))
|
||||
/*c2go int CASE(int, int); */
|
||||
|
||||
/*
|
||||
* Is this node a memory operand?
|
||||
*/
|
||||
int
|
||||
ismem(Node *n)
|
||||
{
|
||||
switch(n->op) {
|
||||
case OITAB:
|
||||
case OSPTR:
|
||||
case OLEN:
|
||||
case OCAP:
|
||||
case OINDREG:
|
||||
case ONAME:
|
||||
case OPARAM:
|
||||
case OCLOSUREVAR:
|
||||
case OADDR:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* set up nodes representing 2^63
|
||||
*/
|
||||
@ -1089,208 +744,6 @@ fixlargeoffset(Node *n)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* generate code to compute n;
|
||||
* make a refer to result.
|
||||
*/
|
||||
void
|
||||
naddr(Node *n, Addr *a, int canemitcode)
|
||||
{
|
||||
Sym *s;
|
||||
|
||||
a->type = TYPE_NONE;
|
||||
a->name = NAME_NONE;
|
||||
a->reg = 0;
|
||||
a->gotype = nil;
|
||||
a->node = N;
|
||||
a->etype = 0;
|
||||
a->width = 0;
|
||||
if(n == N)
|
||||
return;
|
||||
|
||||
if(n->type != T && n->type->etype != TIDEAL) {
|
||||
dowidth(n->type);
|
||||
a->width = n->type->width;
|
||||
}
|
||||
|
||||
switch(n->op) {
|
||||
default:
|
||||
fatal("naddr: bad %O %D", n->op, a);
|
||||
break;
|
||||
|
||||
case ONAME:
|
||||
a->etype = 0;
|
||||
a->reg = 0;
|
||||
if(n->type != T)
|
||||
a->etype = simtype[n->type->etype];
|
||||
a->offset = n->xoffset;
|
||||
s = n->sym;
|
||||
a->node = n->orig;
|
||||
//if(a->node >= (Node*)&n)
|
||||
// fatal("stack node");
|
||||
if(s == S)
|
||||
s = lookup(".noname");
|
||||
if(n->method) {
|
||||
if(n->type != T)
|
||||
if(n->type->sym != S)
|
||||
if(n->type->sym->pkg != nil)
|
||||
s = pkglookup(s->name, n->type->sym->pkg);
|
||||
}
|
||||
|
||||
a->type = TYPE_MEM;
|
||||
switch(n->class) {
|
||||
default:
|
||||
fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
|
||||
case PEXTERN:
|
||||
a->name = NAME_EXTERN;
|
||||
break;
|
||||
case PAUTO:
|
||||
a->name = NAME_AUTO;
|
||||
break;
|
||||
case PPARAM:
|
||||
case PPARAMOUT:
|
||||
a->name = NAME_PARAM;
|
||||
break;
|
||||
case PFUNC:
|
||||
a->name = NAME_EXTERN;
|
||||
a->type = TYPE_ADDR;
|
||||
a->width = widthptr;
|
||||
s = funcsym(s);
|
||||
break;
|
||||
}
|
||||
a->sym = linksym(s);
|
||||
break;
|
||||
|
||||
case OLITERAL:
|
||||
switch(n->val.ctype) {
|
||||
default:
|
||||
fatal("naddr: const %lT", n->type);
|
||||
break;
|
||||
case CTFLT:
|
||||
a->type = TYPE_FCONST;
|
||||
a->u.dval = mpgetflt(n->val.u.fval);
|
||||
break;
|
||||
case CTINT:
|
||||
case CTRUNE:
|
||||
a->sym = nil;
|
||||
a->type = TYPE_CONST;
|
||||
a->offset = mpgetfix(n->val.u.xval);
|
||||
break;
|
||||
case CTSTR:
|
||||
datagostring(n->val.u.sval, a);
|
||||
break;
|
||||
case CTBOOL:
|
||||
a->sym = nil;
|
||||
a->type = TYPE_CONST;
|
||||
a->offset = n->val.u.bval;
|
||||
break;
|
||||
case CTNIL:
|
||||
a->sym = nil;
|
||||
a->type = TYPE_CONST;
|
||||
a->offset = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case OREGISTER:
|
||||
a->type = TYPE_REG;
|
||||
a->reg = n->val.u.reg;
|
||||
a->sym = nil;
|
||||
break;
|
||||
|
||||
case OINDREG:
|
||||
a->type = TYPE_MEM;
|
||||
a->reg = n->val.u.reg;
|
||||
a->sym = linksym(n->sym);
|
||||
a->offset = n->xoffset;
|
||||
if(a->offset != (int32)a->offset)
|
||||
yyerror("offset %lld too large for OINDREG", a->offset);
|
||||
break;
|
||||
|
||||
case OPARAM:
|
||||
// n->left is PHEAP ONAME for stack parameter.
|
||||
// compute address of actual parameter on stack.
|
||||
a->etype = simtype[n->left->type->etype];
|
||||
a->width = n->left->type->width;
|
||||
a->offset = n->xoffset;
|
||||
a->sym = linksym(n->left->sym);
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_PARAM;
|
||||
a->node = n->left->orig;
|
||||
break;
|
||||
|
||||
case OCLOSUREVAR:
|
||||
if(!curfn->needctxt)
|
||||
fatal("closurevar without needctxt");
|
||||
a->type = TYPE_MEM;
|
||||
a->reg = REGENV;
|
||||
a->offset = n->xoffset;
|
||||
a->sym = nil;
|
||||
break;
|
||||
|
||||
case OCFUNC:
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->sym = linksym(n->left->sym);
|
||||
break;
|
||||
|
||||
case OITAB:
|
||||
// itable of interface value
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->etype = simtype[tptr];
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // itab(nil)
|
||||
a->width = widthptr;
|
||||
break;
|
||||
|
||||
case OSPTR:
|
||||
// pointer in a string or slice
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->etype = simtype[tptr];
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // ptr(nil)
|
||||
a->offset += Array_array;
|
||||
a->width = widthptr;
|
||||
break;
|
||||
|
||||
case OLEN:
|
||||
// len of string or slice
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->etype = simtype[TINT];
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // len(nil)
|
||||
a->offset += Array_nel;
|
||||
a->width = widthint;
|
||||
break;
|
||||
|
||||
case OCAP:
|
||||
// cap of string or slice
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->etype = simtype[TINT];
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // cap(nil)
|
||||
a->offset += Array_cap;
|
||||
a->width = widthint;
|
||||
break;
|
||||
|
||||
case OADDR:
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->etype = tptr;
|
||||
switch(a->type) {
|
||||
case TYPE_MEM:
|
||||
a->type = TYPE_ADDR;
|
||||
break;
|
||||
|
||||
case TYPE_REG:
|
||||
case TYPE_CONST:
|
||||
break;
|
||||
|
||||
default:
|
||||
fatal("naddr: OADDR %d\n", a->type);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* return Axxx for Oxxx on type t.
|
||||
*/
|
||||
|
@ -204,7 +204,7 @@ enum
|
||||
REGRT1 = REG_R3, /* reserved for runtime, duffzero and duffcopy */
|
||||
REGRT2 = REG_R4, /* reserved for runtime, duffcopy */
|
||||
REGMIN = REG_R7, /* register variables allocated from here to REGMAX */
|
||||
REGENV = REG_R11, /* environment for closures */
|
||||
REGCTXT = REG_R11, /* context for closures */
|
||||
REGTLS = REG_R13, /* C ABI TLS base pointer */
|
||||
REGMAX = REG_R27,
|
||||
REGEXT = REG_R30, /* external registers allocated from here down */
|
||||
|
@ -304,8 +304,8 @@ gen(Node *n)
|
||||
|
||||
// if there are pending gotos, resolve them all to the current pc.
|
||||
for(p1=lab->gotopc; p1; p1=p2) {
|
||||
p2 = arch.unpatch(p1);
|
||||
arch.patch(p1, pc);
|
||||
p2 = unpatch(p1);
|
||||
patch(p1, pc);
|
||||
}
|
||||
lab->gotopc = P;
|
||||
if(lab->labelpc == P)
|
||||
@ -332,9 +332,9 @@ gen(Node *n)
|
||||
// of the label in the OLABEL case above.)
|
||||
lab = newlab(n);
|
||||
if(lab->labelpc != P)
|
||||
arch.gjmp(lab->labelpc);
|
||||
gjmp(lab->labelpc);
|
||||
else
|
||||
lab->gotopc = arch.gjmp(lab->gotopc);
|
||||
lab->gotopc = gjmp(lab->gotopc);
|
||||
break;
|
||||
|
||||
case OBREAK:
|
||||
@ -349,14 +349,14 @@ gen(Node *n)
|
||||
yyerror("invalid break label %S", n->left->sym);
|
||||
break;
|
||||
}
|
||||
arch.gjmp(lab->breakpc);
|
||||
gjmp(lab->breakpc);
|
||||
break;
|
||||
}
|
||||
if(breakpc == P) {
|
||||
yyerror("break is not in a loop");
|
||||
break;
|
||||
}
|
||||
arch.gjmp(breakpc);
|
||||
gjmp(breakpc);
|
||||
break;
|
||||
|
||||
case OCONTINUE:
|
||||
@ -371,20 +371,20 @@ gen(Node *n)
|
||||
yyerror("invalid continue label %S", n->left->sym);
|
||||
break;
|
||||
}
|
||||
arch.gjmp(lab->continpc);
|
||||
gjmp(lab->continpc);
|
||||
break;
|
||||
}
|
||||
if(continpc == P) {
|
||||
yyerror("continue is not in a loop");
|
||||
break;
|
||||
}
|
||||
arch.gjmp(continpc);
|
||||
gjmp(continpc);
|
||||
break;
|
||||
|
||||
case OFOR:
|
||||
sbreak = breakpc;
|
||||
p1 = arch.gjmp(P); // goto test
|
||||
breakpc = arch.gjmp(P); // break: goto done
|
||||
p1 = gjmp(P); // goto test
|
||||
breakpc = gjmp(P); // break: goto done
|
||||
scontin = continpc;
|
||||
continpc = pc;
|
||||
|
||||
@ -394,11 +394,11 @@ gen(Node *n)
|
||||
lab->continpc = continpc;
|
||||
}
|
||||
gen(n->nincr); // contin: incr
|
||||
arch.patch(p1, pc); // test:
|
||||
patch(p1, pc); // test:
|
||||
arch.bgen(n->ntest, 0, -1, breakpc); // if(!test) goto break
|
||||
genlist(n->nbody); // body
|
||||
arch.gjmp(continpc);
|
||||
arch.patch(breakpc, pc); // done:
|
||||
gjmp(continpc);
|
||||
patch(breakpc, pc); // done:
|
||||
continpc = scontin;
|
||||
breakpc = sbreak;
|
||||
if(lab) {
|
||||
@ -408,29 +408,29 @@ gen(Node *n)
|
||||
break;
|
||||
|
||||
case OIF:
|
||||
p1 = arch.gjmp(P); // goto test
|
||||
p2 = arch.gjmp(P); // p2: goto else
|
||||
arch.patch(p1, pc); // test:
|
||||
p1 = gjmp(P); // goto test
|
||||
p2 = gjmp(P); // p2: goto else
|
||||
patch(p1, pc); // test:
|
||||
arch.bgen(n->ntest, 0, -n->likely, p2); // if(!test) goto p2
|
||||
genlist(n->nbody); // then
|
||||
p3 = arch.gjmp(P); // goto done
|
||||
arch.patch(p2, pc); // else:
|
||||
p3 = gjmp(P); // goto done
|
||||
patch(p2, pc); // else:
|
||||
genlist(n->nelse); // else
|
||||
arch.patch(p3, pc); // done:
|
||||
patch(p3, pc); // done:
|
||||
break;
|
||||
|
||||
case OSWITCH:
|
||||
sbreak = breakpc;
|
||||
p1 = arch.gjmp(P); // goto test
|
||||
breakpc = arch.gjmp(P); // break: goto done
|
||||
p1 = gjmp(P); // goto test
|
||||
breakpc = gjmp(P); // break: goto done
|
||||
|
||||
// define break label
|
||||
if((lab = stmtlabel(n)) != L)
|
||||
lab->breakpc = breakpc;
|
||||
|
||||
arch.patch(p1, pc); // test:
|
||||
patch(p1, pc); // test:
|
||||
genlist(n->nbody); // switch(test) body
|
||||
arch.patch(breakpc, pc); // done:
|
||||
patch(breakpc, pc); // done:
|
||||
breakpc = sbreak;
|
||||
if(lab != L)
|
||||
lab->breakpc = P;
|
||||
@ -438,16 +438,16 @@ gen(Node *n)
|
||||
|
||||
case OSELECT:
|
||||
sbreak = breakpc;
|
||||
p1 = arch.gjmp(P); // goto test
|
||||
breakpc = arch.gjmp(P); // break: goto done
|
||||
p1 = gjmp(P); // goto test
|
||||
breakpc = gjmp(P); // break: goto done
|
||||
|
||||
// define break label
|
||||
if((lab = stmtlabel(n)) != L)
|
||||
lab->breakpc = breakpc;
|
||||
|
||||
arch.patch(p1, pc); // test:
|
||||
patch(p1, pc); // test:
|
||||
genlist(n->nbody); // select() body
|
||||
arch.patch(breakpc, pc); // done:
|
||||
patch(breakpc, pc); // done:
|
||||
breakpc = sbreak;
|
||||
if(lab != L)
|
||||
lab->breakpc = P;
|
||||
@ -601,7 +601,7 @@ cgen_discard(Node *nr)
|
||||
switch(nr->op) {
|
||||
case ONAME:
|
||||
if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF)
|
||||
arch.gused(nr);
|
||||
gused(nr);
|
||||
break;
|
||||
|
||||
// unary
|
||||
@ -643,7 +643,7 @@ cgen_discard(Node *nr)
|
||||
default:
|
||||
tempname(&tmp, nr->type);
|
||||
cgen_as(&tmp, nr);
|
||||
arch.gused(&tmp);
|
||||
gused(&tmp);
|
||||
}
|
||||
}
|
||||
|
||||
@ -739,7 +739,7 @@ cgen_as(Node *nl, Node *nr)
|
||||
tl = nl->type;
|
||||
if(tl == T)
|
||||
return;
|
||||
if(arch.isfat(tl)) {
|
||||
if(isfat(tl)) {
|
||||
if(nl->op == ONAME)
|
||||
gvardef(nl);
|
||||
arch.clearfat(nl);
|
||||
@ -857,9 +857,9 @@ cgen_slice(Node *n, Node *res)
|
||||
// In essence we are replacing x[i:j:k] where i == j == k
|
||||
// or x[i:j] where i == j == cap(x) with x[0:0:0].
|
||||
if(offs != N) {
|
||||
p1 = arch.gjmp(P);
|
||||
p2 = arch.gjmp(P);
|
||||
arch.patch(p1, pc);
|
||||
p1 = gjmp(P);
|
||||
p2 = gjmp(P);
|
||||
patch(p1, pc);
|
||||
|
||||
nodconst(&con, tmpcap->type, 0);
|
||||
cmp = nod(OEQ, tmpcap, &con);
|
||||
@ -870,7 +870,7 @@ cgen_slice(Node *n, Node *res)
|
||||
typecheck(&add, Erv);
|
||||
arch.cgen(add, base);
|
||||
|
||||
arch.patch(p2, pc);
|
||||
patch(p2, pc);
|
||||
}
|
||||
|
||||
// dst.array = src.array [ + lo *width ]
|
||||
|
@ -1514,7 +1514,6 @@ void gvarkill(Node*);
|
||||
void movelarge(NodeList*);
|
||||
void liveness(Node*, Prog*, Sym*, Sym*);
|
||||
void twobitwalktype1(Type*, vlong*, Bvec*);
|
||||
void nopout(Prog*);
|
||||
|
||||
#pragma varargck type "B" Mpint*
|
||||
#pragma varargck type "E" int
|
||||
@ -1659,9 +1658,10 @@ struct Arch
|
||||
LinkArch *thelinkarch;
|
||||
Typedef *typedefs;
|
||||
|
||||
int REGSP;
|
||||
int REGCTXT;
|
||||
vlong MAXWIDTH;
|
||||
|
||||
void (*afunclit)(Addr*, Node*);
|
||||
int (*anyregalloc)(void);
|
||||
void (*betypeinit)(void);
|
||||
void (*bgen)(Node*, int, int, Prog*);
|
||||
@ -1671,37 +1671,15 @@ struct Arch
|
||||
void (*cgen_callinter)(Node*, Node*, int);
|
||||
void (*cgen_ret)(Node*);
|
||||
void (*clearfat)(Node*);
|
||||
void (*clearp)(Prog*);
|
||||
void (*defframe)(Prog*);
|
||||
int (*dgostringptr)(Sym*, int, char*);
|
||||
int (*dgostrlitptr)(Sym*, int, Strlit*);
|
||||
int (*dsname)(Sym*, int, char*, int);
|
||||
int (*dsymptr)(Sym*, int, Sym*, int);
|
||||
void (*dumpdata)(void);
|
||||
void (*dumpit)(char*, Flow*, int);
|
||||
void (*excise)(Flow*);
|
||||
void (*expandchecks)(Prog*);
|
||||
void (*fixautoused)(Prog*);
|
||||
void (*gclean)(void);
|
||||
void (*gdata)(Node*, Node*, int);
|
||||
void (*gdatacomplex)(Node*, Mpcplx*);
|
||||
void (*gdatastring)(Node*, Strlit*);
|
||||
void (*ggloblnod)(Node*);
|
||||
void (*ggloblsym)(Sym*, int32, int8);
|
||||
void (*ginit)(void);
|
||||
Prog* (*gins)(int, Node*, Node*);
|
||||
void (*ginscall)(Node*, int);
|
||||
Prog* (*gjmp)(Prog*);
|
||||
void (*gtrack)(Sym*);
|
||||
void (*gused)(Node*);
|
||||
void (*igen)(Node*, Node*, Node*);
|
||||
int (*isfat)(Type*);
|
||||
void (*linkarchinit)(void);
|
||||
void (*markautoused)(Prog*);
|
||||
void (*naddr)(Node*, Addr*, int);
|
||||
Plist* (*newplist)(void);
|
||||
Node* (*nodarg)(Type*, int);
|
||||
void (*patch)(Prog*, Prog*);
|
||||
void (*proginfo)(ProgInfo*, Prog*);
|
||||
void (*regalloc)(Node*, Type*, Node*);
|
||||
void (*regfree)(Node*);
|
||||
@ -1710,9 +1688,38 @@ struct Arch
|
||||
int (*sameaddr)(Addr*, Addr*);
|
||||
int (*smallindir)(Addr*, Addr*);
|
||||
int (*stackaddr)(Addr*);
|
||||
Prog* (*unpatch)(Prog*);
|
||||
};
|
||||
|
||||
void afunclit(Addr*, Node*);
|
||||
void clearp(Prog*);
|
||||
void defframe(Prog*);
|
||||
int dgostringptr(Sym*, int, char*);
|
||||
int dgostrlitptr(Sym*, int, Strlit*);
|
||||
int dsname(Sym*, int, char*, int);
|
||||
int dsymptr(Sym*, int, Sym*, int);
|
||||
void dumpdata(void);
|
||||
void fixautoused(Prog*);
|
||||
void gdata(Node*, Node*, int);
|
||||
void gdatacomplex(Node*, Mpcplx*);
|
||||
void gdatastring(Node*, Strlit*);
|
||||
void ggloblnod(Node*);
|
||||
void ggloblsym(Sym*, int32, int8);
|
||||
Prog* gjmp(Prog*);
|
||||
void gtrack(Sym*);
|
||||
void gused(Node*);
|
||||
int isfat(Type*);
|
||||
void markautoused(Prog*);
|
||||
void naddr(Node*, Addr*, int);
|
||||
Plist* newplist(void);
|
||||
Node* nodarg(Type*, int);
|
||||
void patch(Prog*, Prog*);
|
||||
Prog* unpatch(Prog*);
|
||||
void datagostring(Strlit *sval, Addr *a);
|
||||
int ismem(Node*);
|
||||
int samereg(Node*, Node*);
|
||||
|
||||
EXTERN int32 pcloc;
|
||||
|
||||
EXTERN Arch arch;
|
||||
|
||||
EXTERN Node *newproc;
|
||||
|
654
src/cmd/gc/gsubr.c
Normal file
654
src/cmd/gc/gsubr.c
Normal file
@ -0,0 +1,654 @@
|
||||
// Derived from 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 <u.h>
|
||||
#include <libc.h>
|
||||
#include "go.h"
|
||||
#include "../../runtime/funcdata.h"
|
||||
#include "../ld/textflag.h"
|
||||
|
||||
void
|
||||
ggloblnod(Node *nam)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = arch.gins(AGLOBL, nam, N);
|
||||
p->lineno = nam->lineno;
|
||||
p->from.sym->gotype = linksym(ngotype(nam));
|
||||
p->to.sym = nil;
|
||||
p->to.type = TYPE_CONST;
|
||||
p->to.offset = nam->type->width;
|
||||
if(nam->readonly)
|
||||
p->from3.offset = RODATA;
|
||||
if(nam->type != T && !haspointers(nam->type))
|
||||
p->from3.offset |= NOPTR;
|
||||
}
|
||||
|
||||
void
|
||||
gtrack(Sym *s)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = arch.gins(AUSEFIELD, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
}
|
||||
|
||||
void
|
||||
ggloblsym(Sym *s, int32 width, int8 flags)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = arch.gins(AGLOBL, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->to.type = TYPE_CONST;
|
||||
p->to.offset = width;
|
||||
p->from3.offset = flags;
|
||||
}
|
||||
|
||||
void
|
||||
clearp(Prog *p)
|
||||
{
|
||||
nopout(p);
|
||||
p->as = AEND;
|
||||
p->pc = pcloc;
|
||||
pcloc++;
|
||||
}
|
||||
|
||||
static int ddumped;
|
||||
static Prog *dfirst;
|
||||
static Prog *dpc;
|
||||
|
||||
/*
|
||||
* generate and return proc with p->as = as,
|
||||
* linked into program. pc is next instruction.
|
||||
*/
|
||||
Prog*
|
||||
prog(int as)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
if(as == ADATA || as == AGLOBL) {
|
||||
if(ddumped)
|
||||
fatal("already dumped data");
|
||||
if(dpc == nil) {
|
||||
dpc = mal(sizeof(*dpc));
|
||||
dfirst = dpc;
|
||||
}
|
||||
p = dpc;
|
||||
dpc = mal(sizeof(*dpc));
|
||||
p->link = dpc;
|
||||
} else {
|
||||
p = pc;
|
||||
pc = mal(sizeof(*pc));
|
||||
clearp(pc);
|
||||
p->link = pc;
|
||||
}
|
||||
|
||||
if(lineno == 0) {
|
||||
if(debug['K'])
|
||||
warn("prog: line 0");
|
||||
}
|
||||
|
||||
p->as = as;
|
||||
p->lineno = lineno;
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
dumpdata(void)
|
||||
{
|
||||
ddumped = 1;
|
||||
if(dfirst == nil)
|
||||
return;
|
||||
newplist();
|
||||
*pc = *dfirst;
|
||||
pc = dpc;
|
||||
clearp(pc);
|
||||
}
|
||||
|
||||
/*
|
||||
* generate a branch.
|
||||
* t is ignored.
|
||||
* likely values are for branch prediction:
|
||||
* -1 unlikely
|
||||
* 0 no opinion
|
||||
* +1 likely
|
||||
*/
|
||||
Prog*
|
||||
gbranch(int as, Type *t, int likely)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
USED(t);
|
||||
|
||||
p = prog(as);
|
||||
p->to.type = TYPE_BRANCH;
|
||||
p->to.u.branch = P;
|
||||
if(as != AJMP && likely != 0 && arch.thechar != '9') {
|
||||
p->from.type = TYPE_CONST;
|
||||
p->from.offset = likely > 0;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* patch previous branch to jump to to.
|
||||
*/
|
||||
void
|
||||
patch(Prog *p, Prog *to)
|
||||
{
|
||||
if(p->to.type != TYPE_BRANCH)
|
||||
fatal("patch: not a branch");
|
||||
p->to.u.branch = to;
|
||||
p->to.offset = to->pc;
|
||||
}
|
||||
|
||||
Prog*
|
||||
unpatch(Prog *p)
|
||||
{
|
||||
Prog *q;
|
||||
|
||||
if(p->to.type != TYPE_BRANCH)
|
||||
fatal("unpatch: not a branch");
|
||||
q = p->to.u.branch;
|
||||
p->to.u.branch = P;
|
||||
p->to.offset = 0;
|
||||
return q;
|
||||
}
|
||||
|
||||
/*
|
||||
* start a new Prog list.
|
||||
*/
|
||||
Plist*
|
||||
newplist(void)
|
||||
{
|
||||
Plist *pl;
|
||||
|
||||
pl = linknewplist(ctxt);
|
||||
|
||||
pc = mal(sizeof(*pc));
|
||||
clearp(pc);
|
||||
pl->firstpc = pc;
|
||||
|
||||
return pl;
|
||||
}
|
||||
|
||||
void
|
||||
gused(Node *n)
|
||||
{
|
||||
arch.gins(ANOP, n, N); // used
|
||||
}
|
||||
|
||||
Prog*
|
||||
gjmp(Prog *to)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = gbranch(AJMP, T, 0);
|
||||
if(to != P)
|
||||
patch(p, to);
|
||||
return p;
|
||||
}
|
||||
|
||||
int
|
||||
isfat(Type *t)
|
||||
{
|
||||
if(t != T)
|
||||
switch(t->etype) {
|
||||
case TSTRUCT:
|
||||
case TARRAY:
|
||||
case TSTRING:
|
||||
case TINTER: // maybe remove later
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* naddr of func generates code for address of func.
|
||||
* if using opcode that can take address implicitly,
|
||||
* call afunclit to fix up the argument.
|
||||
*/
|
||||
void
|
||||
afunclit(Addr *a, Node *n)
|
||||
{
|
||||
if(a->type == TYPE_ADDR && a->name == NAME_EXTERN) {
|
||||
a->type = TYPE_MEM;
|
||||
a->sym = linksym(n->sym);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize n to be register r of type t.
|
||||
*/
|
||||
void
|
||||
nodreg(Node *n, Type *t, int r)
|
||||
{
|
||||
if(t == T)
|
||||
fatal("nodreg: t nil");
|
||||
|
||||
memset(n, 0, sizeof(*n));
|
||||
n->op = OREGISTER;
|
||||
n->addable = 1;
|
||||
ullmancalc(n);
|
||||
n->val.u.reg = r;
|
||||
n->type = t;
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize n to be indirect of register r; n is type t.
|
||||
*/
|
||||
void
|
||||
nodindreg(Node *n, Type *t, int r)
|
||||
{
|
||||
nodreg(n, t, r);
|
||||
n->op = OINDREG;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this node a memory operand?
|
||||
*/
|
||||
int
|
||||
ismem(Node *n)
|
||||
{
|
||||
switch(n->op) {
|
||||
case OITAB:
|
||||
case OSPTR:
|
||||
case OLEN:
|
||||
case OCAP:
|
||||
case OINDREG:
|
||||
case ONAME:
|
||||
case OPARAM:
|
||||
case OCLOSUREVAR:
|
||||
return 1;
|
||||
case OADDR:
|
||||
return arch.thechar == '6' || arch.thechar == '9'; // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sweep the prog list to mark any used nodes.
|
||||
void
|
||||
markautoused(Prog* p)
|
||||
{
|
||||
for (; p; p = p->link) {
|
||||
if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
|
||||
continue;
|
||||
|
||||
if (p->from.node)
|
||||
((Node*)(p->from.node))->used = 1;
|
||||
|
||||
if (p->to.node)
|
||||
((Node*)(p->to.node))->used = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
|
||||
void
|
||||
fixautoused(Prog *p)
|
||||
{
|
||||
Prog **lp;
|
||||
|
||||
for (lp=&p; (p=*lp) != P; ) {
|
||||
if (p->as == ATYPE && p->from.node && p->from.name == NAME_AUTO && !((Node*)(p->from.node))->used) {
|
||||
*lp = p->link;
|
||||
continue;
|
||||
}
|
||||
if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !((Node*)(p->to.node))->used) {
|
||||
// Cannot remove VARDEF instruction, because - unlike TYPE handled above -
|
||||
// VARDEFs are interspersed with other code, and a jump might be using the
|
||||
// VARDEF as a target. Replace with a no-op instead. A later pass will remove
|
||||
// the no-ops.
|
||||
nopout(p);
|
||||
continue;
|
||||
}
|
||||
if (p->from.name == NAME_AUTO && p->from.node)
|
||||
p->from.offset += ((Node*)(p->from.node))->stkdelta;
|
||||
|
||||
if (p->to.name == NAME_AUTO && p->to.node)
|
||||
p->to.offset += ((Node*)(p->to.node))->stkdelta;
|
||||
|
||||
lp = &p->link;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
samereg(Node *a, Node *b)
|
||||
{
|
||||
if(a == N || b == N)
|
||||
return 0;
|
||||
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;
|
||||
}
|
||||
|
||||
Node*
|
||||
nodarg(Type *t, int fp)
|
||||
{
|
||||
Node *n;
|
||||
NodeList *l;
|
||||
Type *first;
|
||||
Iter savet;
|
||||
|
||||
// entire argument struct, not just one arg
|
||||
if(t->etype == TSTRUCT && t->funarg) {
|
||||
n = nod(ONAME, N, N);
|
||||
n->sym = lookup(".args");
|
||||
n->type = t;
|
||||
first = structfirst(&savet, &t);
|
||||
if(first == nil)
|
||||
fatal("nodarg: bad struct");
|
||||
if(first->width == BADWIDTH)
|
||||
fatal("nodarg: offset not computed for %T", t);
|
||||
n->xoffset = first->width;
|
||||
n->addable = 1;
|
||||
goto fp;
|
||||
}
|
||||
|
||||
if(t->etype != TFIELD)
|
||||
fatal("nodarg: not field %T", t);
|
||||
|
||||
if(fp == 1) {
|
||||
for(l=curfn->dcl; l; l=l->next) {
|
||||
n = l->n;
|
||||
if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
n = nod(ONAME, N, N);
|
||||
n->type = t->type;
|
||||
n->sym = t->sym;
|
||||
|
||||
if(t->width == BADWIDTH)
|
||||
fatal("nodarg: offset not computed for %T", t);
|
||||
n->xoffset = t->width;
|
||||
n->addable = 1;
|
||||
n->orig = t->nname;
|
||||
|
||||
fp:
|
||||
// Rewrite argument named _ to __,
|
||||
// or else the assignment to _ will be
|
||||
// discarded during code generation.
|
||||
if(isblank(n))
|
||||
n->sym = lookup("__");
|
||||
|
||||
switch(fp) {
|
||||
case 0: // output arg
|
||||
n->op = OINDREG;
|
||||
n->val.u.reg = arch.REGSP;
|
||||
if(arch.thechar == '5')
|
||||
n->xoffset += 4;
|
||||
if(arch.thechar == '9')
|
||||
n->xoffset += 8;
|
||||
break;
|
||||
|
||||
case 1: // input arg
|
||||
n->class = PPARAM;
|
||||
break;
|
||||
|
||||
case 2: // offset output arg
|
||||
fatal("shouldn't be used");
|
||||
n->op = OINDREG;
|
||||
n->val.u.reg = arch.REGSP;
|
||||
n->xoffset += types[tptr]->width;
|
||||
break;
|
||||
}
|
||||
n->typecheck = 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* generate code to compute n;
|
||||
* make a refer to result.
|
||||
*/
|
||||
void
|
||||
naddr(Node *n, Addr *a, int canemitcode)
|
||||
{
|
||||
Sym *s;
|
||||
|
||||
*a = zprog.from;
|
||||
if(n == N)
|
||||
return;
|
||||
|
||||
if(n->type != T && n->type->etype != TIDEAL) {
|
||||
// TODO(rsc): This is undone by the selective clearing of width below,
|
||||
// to match architectures that were not as aggressive in setting width
|
||||
// during naddr. Those widths must be cleared to avoid triggering
|
||||
// failures in gins when it detects real but heretofore latent (and one
|
||||
// hopes innocuous) type mismatches.
|
||||
// The type mismatches should be fixed and the clearing below removed.
|
||||
dowidth(n->type);
|
||||
a->width = n->type->width;
|
||||
}
|
||||
|
||||
switch(n->op) {
|
||||
default:
|
||||
fatal("naddr: bad %O %D", n->op, a);
|
||||
break;
|
||||
|
||||
case OREGISTER:
|
||||
a->type = TYPE_REG;
|
||||
a->reg = n->val.u.reg;
|
||||
a->sym = nil;
|
||||
if(arch.thechar == '8') // TODO(rsc): Never clear a->width.
|
||||
a->width = 0;
|
||||
break;
|
||||
|
||||
case OINDREG:
|
||||
a->type = TYPE_MEM;
|
||||
a->reg = n->val.u.reg;
|
||||
a->sym = linksym(n->sym);
|
||||
a->offset = n->xoffset;
|
||||
if(a->offset != (int32)a->offset)
|
||||
yyerror("offset %lld too large for OINDREG", a->offset);
|
||||
if(arch.thechar == '8') // TODO(rsc): Never clear a->width.
|
||||
a->width = 0;
|
||||
break;
|
||||
|
||||
case OPARAM:
|
||||
// n->left is PHEAP ONAME for stack parameter.
|
||||
// compute address of actual parameter on stack.
|
||||
a->etype = simtype[n->left->type->etype];
|
||||
a->width = n->left->type->width;
|
||||
a->offset = n->xoffset;
|
||||
a->sym = linksym(n->left->sym);
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_PARAM;
|
||||
a->node = n->left->orig;
|
||||
break;
|
||||
|
||||
case OCLOSUREVAR:
|
||||
if(!curfn->needctxt)
|
||||
fatal("closurevar without needctxt");
|
||||
a->type = TYPE_MEM;
|
||||
a->reg = arch.REGCTXT;
|
||||
a->sym = nil;
|
||||
a->offset = n->xoffset;
|
||||
break;
|
||||
|
||||
case OCFUNC:
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->sym = linksym(n->left->sym);
|
||||
break;
|
||||
|
||||
case ONAME:
|
||||
a->etype = 0;
|
||||
if(n->type != T)
|
||||
a->etype = simtype[n->type->etype];
|
||||
a->offset = n->xoffset;
|
||||
s = n->sym;
|
||||
a->node = n->orig;
|
||||
//if(a->node >= (Node*)&n)
|
||||
// fatal("stack node");
|
||||
if(s == S)
|
||||
s = lookup(".noname");
|
||||
if(n->method) {
|
||||
if(n->type != T)
|
||||
if(n->type->sym != S)
|
||||
if(n->type->sym->pkg != nil)
|
||||
s = pkglookup(s->name, n->type->sym->pkg);
|
||||
}
|
||||
|
||||
a->type = TYPE_MEM;
|
||||
switch(n->class) {
|
||||
default:
|
||||
fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
|
||||
case PEXTERN:
|
||||
a->name = NAME_EXTERN;
|
||||
break;
|
||||
case PAUTO:
|
||||
a->name = NAME_AUTO;
|
||||
break;
|
||||
case PPARAM:
|
||||
case PPARAMOUT:
|
||||
a->name = NAME_PARAM;
|
||||
break;
|
||||
case PFUNC:
|
||||
a->name = NAME_EXTERN;
|
||||
a->type = TYPE_ADDR;
|
||||
a->width = widthptr;
|
||||
s = funcsym(s);
|
||||
break;
|
||||
}
|
||||
a->sym = linksym(s);
|
||||
break;
|
||||
|
||||
case OLITERAL:
|
||||
if(arch.thechar == '8')
|
||||
a->width = 0;
|
||||
switch(n->val.ctype) {
|
||||
default:
|
||||
fatal("naddr: const %lT", n->type);
|
||||
break;
|
||||
case CTFLT:
|
||||
a->type = TYPE_FCONST;
|
||||
a->u.dval = mpgetflt(n->val.u.fval);
|
||||
break;
|
||||
case CTINT:
|
||||
case CTRUNE:
|
||||
a->sym = nil;
|
||||
a->type = TYPE_CONST;
|
||||
a->offset = mpgetfix(n->val.u.xval);
|
||||
break;
|
||||
case CTSTR:
|
||||
datagostring(n->val.u.sval, a);
|
||||
break;
|
||||
case CTBOOL:
|
||||
a->sym = nil;
|
||||
a->type = TYPE_CONST;
|
||||
a->offset = n->val.u.bval;
|
||||
break;
|
||||
case CTNIL:
|
||||
a->sym = nil;
|
||||
a->type = TYPE_CONST;
|
||||
a->offset = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case OADDR:
|
||||
naddr(n->left, a, canemitcode);
|
||||
a->etype = tptr;
|
||||
if(arch.thechar != '5' && arch.thechar != '9') // TODO(rsc): Do this even for arm, ppc64.
|
||||
a->width = widthptr;
|
||||
if(a->type != TYPE_MEM)
|
||||
fatal("naddr: OADDR %D (from %O)", a, n->left->op);
|
||||
a->type = TYPE_ADDR;
|
||||
break;
|
||||
|
||||
case OITAB:
|
||||
// itable of interface value
|
||||
naddr(n->left, a, canemitcode);
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // itab(nil)
|
||||
a->etype = tptr;
|
||||
a->width = widthptr;
|
||||
break;
|
||||
|
||||
case OSPTR:
|
||||
// pointer in a string or slice
|
||||
naddr(n->left, a, canemitcode);
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // ptr(nil)
|
||||
a->etype = simtype[tptr];
|
||||
a->offset += Array_array;
|
||||
a->width = widthptr;
|
||||
break;
|
||||
|
||||
case OLEN:
|
||||
// len of string or slice
|
||||
naddr(n->left, a, canemitcode);
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // len(nil)
|
||||
a->etype = simtype[TUINT];
|
||||
if(arch.thechar == '9')
|
||||
a->etype = simtype[TINT];
|
||||
a->offset += Array_nel;
|
||||
if(arch.thechar != '5') // TODO(rsc): Do this even on arm.
|
||||
a->width = widthint;
|
||||
break;
|
||||
|
||||
case OCAP:
|
||||
// cap of string or slice
|
||||
naddr(n->left, a, canemitcode);
|
||||
if(a->type == TYPE_CONST && a->offset == 0)
|
||||
break; // cap(nil)
|
||||
a->etype = simtype[TUINT];
|
||||
if(arch.thechar == '9')
|
||||
a->etype = simtype[TINT];
|
||||
a->offset += Array_cap;
|
||||
if(arch.thechar != '5') // TODO(rsc): Do this even on arm.
|
||||
a->width = widthint;
|
||||
break;
|
||||
|
||||
// case OADD:
|
||||
// if(n->right->op == OLITERAL) {
|
||||
// v = n->right->vconst;
|
||||
// naddr(n->left, a, canemitcode);
|
||||
// } else
|
||||
// if(n->left->op == OLITERAL) {
|
||||
// v = n->left->vconst;
|
||||
// naddr(n->right, a, canemitcode);
|
||||
// } else
|
||||
// goto bad;
|
||||
// a->offset += v;
|
||||
// break;
|
||||
|
||||
}
|
||||
}
|
224
src/cmd/gc/obj.c
224
src/cmd/gc/obj.c
@ -95,9 +95,9 @@ dumpobj(void)
|
||||
externdcl = tmp;
|
||||
|
||||
zero = pkglookup("zerovalue", runtimepkg);
|
||||
arch.ggloblsym(zero, zerosize, DUPOK|RODATA);
|
||||
ggloblsym(zero, zerosize, DUPOK|RODATA);
|
||||
|
||||
arch.dumpdata();
|
||||
dumpdata();
|
||||
writeobj(ctxt, bout);
|
||||
|
||||
if(writearchive) {
|
||||
@ -133,13 +133,13 @@ dumpglobls(void)
|
||||
continue;
|
||||
dowidth(n->type);
|
||||
|
||||
arch.ggloblnod(n);
|
||||
ggloblnod(n);
|
||||
}
|
||||
|
||||
for(l=funcsyms; l; l=l->next) {
|
||||
n = l->n;
|
||||
arch.dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0);
|
||||
arch.ggloblsym(n->sym, widthptr, DUPOK|RODATA);
|
||||
dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0);
|
||||
ggloblsym(n->sym, widthptr, DUPOK|RODATA);
|
||||
}
|
||||
|
||||
// Do not reprocess funcsyms on next dumpglobls call.
|
||||
@ -250,7 +250,7 @@ stringsym(char *s, int len)
|
||||
off = 0;
|
||||
|
||||
// string header
|
||||
off = arch.dsymptr(sym, off, sym, widthptr+widthint);
|
||||
off = dsymptr(sym, off, sym, widthptr+widthint);
|
||||
off = duintxx(sym, off, len, widthint);
|
||||
|
||||
// string data
|
||||
@ -258,11 +258,11 @@ stringsym(char *s, int len)
|
||||
m = 8;
|
||||
if(m > len-n)
|
||||
m = len-n;
|
||||
off = arch.dsname(sym, off, s+n, m);
|
||||
off = dsname(sym, off, s+n, m);
|
||||
}
|
||||
off = duint8(sym, off, 0); // terminating NUL for runtime
|
||||
off = (off+widthptr-1)&~(widthptr-1); // round to pointer alignment
|
||||
arch.ggloblsym(sym, off, DUPOK|RODATA);
|
||||
ggloblsym(sym, off, DUPOK|RODATA);
|
||||
|
||||
return sym;
|
||||
}
|
||||
@ -283,14 +283,216 @@ slicebytes(Node *nam, char *s, int len)
|
||||
m = 8;
|
||||
if(m > len-n)
|
||||
m = len-n;
|
||||
off = arch.dsname(sym, off, s+n, m);
|
||||
off = dsname(sym, off, s+n, m);
|
||||
}
|
||||
arch.ggloblsym(sym, off, NOPTR);
|
||||
ggloblsym(sym, off, NOPTR);
|
||||
|
||||
if(nam->op != ONAME)
|
||||
fatal("slicebytes %N", nam);
|
||||
off = nam->xoffset;
|
||||
off = arch.dsymptr(nam->sym, off, sym, 0);
|
||||
off = dsymptr(nam->sym, off, sym, 0);
|
||||
off = duintxx(nam->sym, off, len, widthint);
|
||||
duintxx(nam->sym, off, len, widthint);
|
||||
}
|
||||
|
||||
int
|
||||
dsname(Sym *s, int off, char *t, int n)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
p = arch.gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.offset = off;
|
||||
p->from.sym = linksym(s);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = n;
|
||||
|
||||
p->to.type = TYPE_SCONST;
|
||||
memmove(p->to.u.sval, t, n);
|
||||
return off + n;
|
||||
}
|
||||
|
||||
/*
|
||||
* make a refer to the data s, s+len
|
||||
* emitting DATA if needed.
|
||||
*/
|
||||
void
|
||||
datastring(char *s, int len, Addr *a)
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
sym = stringsym(s, len);
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_EXTERN;
|
||||
a->sym = linksym(sym);
|
||||
a->node = sym->def;
|
||||
a->offset = widthptr+widthint; // skip header
|
||||
a->etype = simtype[TINT];
|
||||
}
|
||||
|
||||
/*
|
||||
* make a refer to the string sval,
|
||||
* emitting DATA if needed.
|
||||
*/
|
||||
void
|
||||
datagostring(Strlit *sval, Addr *a)
|
||||
{
|
||||
Sym *sym;
|
||||
|
||||
sym = stringsym(sval->s, sval->len);
|
||||
a->type = TYPE_MEM;
|
||||
a->name = NAME_EXTERN;
|
||||
a->sym = linksym(sym);
|
||||
a->node = sym->def;
|
||||
a->offset = 0; // header
|
||||
a->etype = TSTRING;
|
||||
}
|
||||
|
||||
void
|
||||
gdata(Node *nam, Node *nr, int wid)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
if(nr->op == OLITERAL) {
|
||||
switch(nr->val.ctype) {
|
||||
case CTCPLX:
|
||||
gdatacomplex(nam, nr->val.u.cval);
|
||||
return;
|
||||
case CTSTR:
|
||||
gdatastring(nam, nr->val.u.sval);
|
||||
return;
|
||||
}
|
||||
}
|
||||
p = arch.gins(ADATA, nam, nr);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = wid;
|
||||
}
|
||||
|
||||
void
|
||||
gdatacomplex(Node *nam, Mpcplx *cval)
|
||||
{
|
||||
Prog *p;
|
||||
int w;
|
||||
|
||||
w = cplxsubtype(nam->type->etype);
|
||||
w = types[w]->width;
|
||||
|
||||
p = arch.gins(ADATA, nam, N);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = w;
|
||||
p->to.type = TYPE_FCONST;
|
||||
p->to.u.dval = mpgetflt(&cval->real);
|
||||
|
||||
p = arch.gins(ADATA, nam, N);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = w;
|
||||
p->from.offset += w;
|
||||
p->to.type = TYPE_FCONST;
|
||||
p->to.u.dval = mpgetflt(&cval->imag);
|
||||
}
|
||||
|
||||
void
|
||||
gdatastring(Node *nam, Strlit *sval)
|
||||
{
|
||||
Prog *p;
|
||||
Node nod1;
|
||||
|
||||
p = arch.gins(ADATA, nam, N);
|
||||
datastring(sval->s, sval->len, &p->to);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = types[tptr]->width;
|
||||
p->to.type = TYPE_ADDR;
|
||||
//print("%P\n", p);
|
||||
|
||||
nodconst(&nod1, types[TINT], sval->len);
|
||||
p = arch.gins(ADATA, nam, &nod1);
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthint;
|
||||
p->from.offset += widthptr;
|
||||
}
|
||||
|
||||
int
|
||||
dstringptr(Sym *s, int off, char *str)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
off = rnd(off, widthptr);
|
||||
p = arch.gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthptr;
|
||||
|
||||
datastring(str, strlen(str)+1, &p->to);
|
||||
p->to.type = TYPE_ADDR;
|
||||
p->to.etype = simtype[TINT];
|
||||
off += widthptr;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
int
|
||||
dgostrlitptr(Sym *s, int off, Strlit *lit)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
if(lit == nil)
|
||||
return duintptr(s, off, 0);
|
||||
|
||||
off = rnd(off, widthptr);
|
||||
p = arch.gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthptr;
|
||||
datagostring(lit, &p->to);
|
||||
p->to.type = TYPE_ADDR;
|
||||
p->to.etype = simtype[TINT];
|
||||
off += widthptr;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
int
|
||||
dgostringptr(Sym *s, int off, char *str)
|
||||
{
|
||||
int n;
|
||||
Strlit *lit;
|
||||
|
||||
if(str == nil)
|
||||
return duintptr(s, off, 0);
|
||||
|
||||
n = strlen(str);
|
||||
lit = mal(sizeof *lit + n);
|
||||
strcpy(lit->s, str);
|
||||
lit->len = n;
|
||||
return dgostrlitptr(s, off, lit);
|
||||
}
|
||||
|
||||
int
|
||||
dsymptr(Sym *s, int off, Sym *x, int xoff)
|
||||
{
|
||||
Prog *p;
|
||||
|
||||
off = rnd(off, widthptr);
|
||||
|
||||
p = arch.gins(ADATA, N, N);
|
||||
p->from.type = TYPE_MEM;
|
||||
p->from.name = NAME_EXTERN;
|
||||
p->from.sym = linksym(s);
|
||||
p->from.offset = off;
|
||||
p->from3.type = TYPE_CONST;
|
||||
p->from3.offset = widthptr;
|
||||
p->to.type = TYPE_ADDR;
|
||||
p->to.name = NAME_EXTERN;
|
||||
p->to.sym = linksym(x);
|
||||
p->to.offset = xoff;
|
||||
off += widthptr;
|
||||
|
||||
return off;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ makefuncdatasym(char *namefmt, int64 funcdatakind)
|
||||
// where a complete initialization (definition) of a variable begins.
|
||||
// Since the liveness analysis can see initialization of single-word
|
||||
// variables quite easy, gvardef is usually only called for multi-word
|
||||
// or 'fat' variables, those satisfying arch.isfat(n->type).
|
||||
// or 'fat' variables, those satisfying isfat(n->type).
|
||||
// However, gvardef is also called when a non-fat variable is initialized
|
||||
// via a block move; the only time this happens is when you have
|
||||
// return f()
|
||||
@ -223,7 +223,7 @@ compile(Node *fn)
|
||||
continpc = P;
|
||||
breakpc = P;
|
||||
|
||||
pl = arch.newplist();
|
||||
pl = newplist();
|
||||
pl->name = linksym(curfn->nname->sym);
|
||||
|
||||
setlineno(curfn);
|
||||
@ -247,7 +247,7 @@ compile(Node *fn)
|
||||
ptxt->from3.offset |= WRAPPER;
|
||||
}
|
||||
|
||||
arch.afunclit(&ptxt->from, curfn->nname);
|
||||
afunclit(&ptxt->from, curfn->nname);
|
||||
|
||||
arch.ginit();
|
||||
|
||||
@ -255,7 +255,7 @@ compile(Node *fn)
|
||||
gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps);
|
||||
|
||||
for(t=curfn->paramfld; t; t=t->down)
|
||||
arch.gtrack(tracksym(t->type));
|
||||
gtrack(tracksym(t->type));
|
||||
|
||||
for(l=fn->dcl; l; l=l->next) {
|
||||
n = l->n;
|
||||
@ -325,7 +325,7 @@ compile(Node *fn)
|
||||
gcsymdup(gcargs);
|
||||
gcsymdup(gclocals);
|
||||
|
||||
arch.defframe(ptxt);
|
||||
defframe(ptxt);
|
||||
|
||||
if(0)
|
||||
frame(0);
|
||||
@ -369,7 +369,7 @@ emitptrargsmap(void)
|
||||
for(j = 0; j < bv->n; j += 32)
|
||||
off = duint32(sym, off, bv->b[j/32]);
|
||||
}
|
||||
arch.ggloblsym(sym, off, RODATA);
|
||||
ggloblsym(sym, off, RODATA);
|
||||
free(bv);
|
||||
}
|
||||
|
||||
@ -438,7 +438,7 @@ allocauto(Prog* ptxt)
|
||||
if (ll->n->class == PAUTO)
|
||||
ll->n->used = 0;
|
||||
|
||||
arch.markautoused(ptxt);
|
||||
markautoused(ptxt);
|
||||
|
||||
listsort(&curfn->dcl, cmpstackvar);
|
||||
|
||||
@ -448,7 +448,7 @@ allocauto(Prog* ptxt)
|
||||
if (n->class == PAUTO && n->op == ONAME && !n->used) {
|
||||
// No locals used at all
|
||||
curfn->dcl = nil;
|
||||
arch.fixautoused(ptxt);
|
||||
fixautoused(ptxt);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -486,7 +486,7 @@ allocauto(Prog* ptxt)
|
||||
stksize = rnd(stksize, widthreg);
|
||||
stkptrsize = rnd(stkptrsize, widthreg);
|
||||
|
||||
arch.fixautoused(ptxt);
|
||||
fixautoused(ptxt);
|
||||
|
||||
// The debug information needs accurate offsets on the symbols.
|
||||
for(ll = curfn->dcl; ll != nil; ll=ll->next) {
|
||||
|
@ -744,7 +744,7 @@ progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
|
||||
if(info.flags & (LeftRead | LeftAddr))
|
||||
bvset(uevar, pos);
|
||||
if(info.flags & LeftWrite)
|
||||
if(from->node != nil && !arch.isfat(((Node*)(from->node))->type))
|
||||
if(from->node != nil && !isfat(((Node*)(from->node))->type))
|
||||
bvset(varkill, pos);
|
||||
}
|
||||
}
|
||||
@ -780,7 +780,7 @@ Next:
|
||||
if((info.flags & RightRead) || (info.flags & (RightAddr|RightWrite)) == RightAddr)
|
||||
bvset(uevar, pos);
|
||||
if(info.flags & RightWrite)
|
||||
if(to->node != nil && (!arch.isfat(((Node*)(to->node))->type) || prog->as == AVARDEF))
|
||||
if(to->node != nil && (!isfat(((Node*)(to->node))->type) || prog->as == AVARDEF))
|
||||
bvset(varkill, pos);
|
||||
}
|
||||
}
|
||||
@ -1218,7 +1218,7 @@ unlinkedprog(int as)
|
||||
Prog *p;
|
||||
|
||||
p = mal(sizeof(*p));
|
||||
arch.clearp(p);
|
||||
clearp(p);
|
||||
p->as = as;
|
||||
return p;
|
||||
}
|
||||
@ -1235,8 +1235,8 @@ newpcdataprog(Prog *prog, int32 index)
|
||||
nodconst(&to, types[TINT32], index);
|
||||
pcdata = unlinkedprog(APCDATA);
|
||||
pcdata->lineno = prog->lineno;
|
||||
arch.naddr(&from, &pcdata->from, 0);
|
||||
arch.naddr(&to, &pcdata->to, 0);
|
||||
naddr(&from, &pcdata->from, 0);
|
||||
naddr(&to, &pcdata->to, 0);
|
||||
return pcdata;
|
||||
}
|
||||
|
||||
@ -1932,7 +1932,7 @@ twobitwritesymbol(Array *arr, Sym *sym)
|
||||
}
|
||||
}
|
||||
duint32(sym, 0, i); // number of bitmaps
|
||||
arch.ggloblsym(sym, off, RODATA);
|
||||
ggloblsym(sym, off, RODATA);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -547,15 +547,15 @@ dimportpath(Pkg *p)
|
||||
n->xoffset = 0;
|
||||
p->pathsym = n->sym;
|
||||
|
||||
arch.gdatastring(n, p->path);
|
||||
arch.ggloblsym(n->sym, types[TSTRING]->width, DUPOK|RODATA);
|
||||
gdatastring(n, p->path);
|
||||
ggloblsym(n->sym, types[TSTRING]->width, DUPOK|RODATA);
|
||||
}
|
||||
|
||||
static int
|
||||
dgopkgpath(Sym *s, int ot, Pkg *pkg)
|
||||
{
|
||||
if(pkg == nil)
|
||||
return arch.dgostringptr(s, ot, nil);
|
||||
return dgostringptr(s, ot, nil);
|
||||
|
||||
// Emit reference to go.importpath.""., which 6l will
|
||||
// rewrite using the correct import path. Every package
|
||||
@ -565,11 +565,11 @@ dgopkgpath(Sym *s, int ot, Pkg *pkg)
|
||||
|
||||
if(ns == nil)
|
||||
ns = pkglookup("importpath.\"\".", mkpkg(newstrlit("go")));
|
||||
return arch.dsymptr(s, ot, ns, 0);
|
||||
return dsymptr(s, ot, ns, 0);
|
||||
}
|
||||
|
||||
dimportpath(pkg);
|
||||
return arch.dsymptr(s, ot, pkg->pathsym, 0);
|
||||
return dsymptr(s, ot, pkg->pathsym, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -589,7 +589,7 @@ dextratype(Sym *sym, int off, Type *t, int ptroff)
|
||||
|
||||
// fill in *extraType pointer in header
|
||||
off = rnd(off, widthptr);
|
||||
arch.dsymptr(sym, ptroff, sym, off);
|
||||
dsymptr(sym, ptroff, sym, off);
|
||||
|
||||
n = 0;
|
||||
for(a=m; a; a=a->link) {
|
||||
@ -600,18 +600,18 @@ dextratype(Sym *sym, int off, Type *t, int ptroff)
|
||||
ot = off;
|
||||
s = sym;
|
||||
if(t->sym) {
|
||||
ot = arch.dgostringptr(s, ot, t->sym->name);
|
||||
ot = dgostringptr(s, ot, t->sym->name);
|
||||
if(t != types[t->etype] && t != errortype)
|
||||
ot = dgopkgpath(s, ot, t->sym->pkg);
|
||||
else
|
||||
ot = arch.dgostringptr(s, ot, nil);
|
||||
ot = dgostringptr(s, ot, nil);
|
||||
} else {
|
||||
ot = arch.dgostringptr(s, ot, nil);
|
||||
ot = arch.dgostringptr(s, ot, nil);
|
||||
ot = dgostringptr(s, ot, nil);
|
||||
ot = dgostringptr(s, ot, nil);
|
||||
}
|
||||
|
||||
// slice header
|
||||
ot = arch.dsymptr(s, ot, s, ot + widthptr + 2*widthint);
|
||||
ot = dsymptr(s, ot, s, ot + widthptr + 2*widthint);
|
||||
ot = duintxx(s, ot, n, widthint);
|
||||
ot = duintxx(s, ot, n, widthint);
|
||||
|
||||
@ -619,16 +619,16 @@ dextratype(Sym *sym, int off, Type *t, int ptroff)
|
||||
for(a=m; a; a=a->link) {
|
||||
// method
|
||||
// ../../runtime/type.go:/method
|
||||
ot = arch.dgostringptr(s, ot, a->name);
|
||||
ot = dgostringptr(s, ot, a->name);
|
||||
ot = dgopkgpath(s, ot, a->pkg);
|
||||
ot = arch.dsymptr(s, ot, dtypesym(a->mtype), 0);
|
||||
ot = arch.dsymptr(s, ot, dtypesym(a->type), 0);
|
||||
ot = dsymptr(s, ot, dtypesym(a->mtype), 0);
|
||||
ot = dsymptr(s, ot, dtypesym(a->type), 0);
|
||||
if(a->isym)
|
||||
ot = arch.dsymptr(s, ot, a->isym, 0);
|
||||
ot = dsymptr(s, ot, a->isym, 0);
|
||||
else
|
||||
ot = duintptr(s, ot, 0);
|
||||
if(a->tsym)
|
||||
ot = arch.dsymptr(s, ot, a->tsym, 0);
|
||||
ot = dsymptr(s, ot, a->tsym, 0);
|
||||
else
|
||||
ot = duintptr(s, ot, 0);
|
||||
}
|
||||
@ -816,17 +816,17 @@ dcommontype(Sym *s, int ot, Type *t)
|
||||
i |= KindGCProg;
|
||||
ot = duint8(s, ot, i); // kind
|
||||
if(algsym == S)
|
||||
ot = arch.dsymptr(s, ot, algarray, alg*sizeofAlg);
|
||||
ot = dsymptr(s, ot, algarray, alg*sizeofAlg);
|
||||
else
|
||||
ot = arch.dsymptr(s, ot, algsym, 0);
|
||||
ot = dsymptr(s, ot, algsym, 0);
|
||||
// gc
|
||||
if(gcprog) {
|
||||
gengcprog(t, &gcprog0, &gcprog1);
|
||||
if(gcprog0 != S)
|
||||
ot = arch.dsymptr(s, ot, gcprog0, 0);
|
||||
ot = dsymptr(s, ot, gcprog0, 0);
|
||||
else
|
||||
ot = duintptr(s, ot, 0);
|
||||
ot = arch.dsymptr(s, ot, gcprog1, 0);
|
||||
ot = dsymptr(s, ot, gcprog1, 0);
|
||||
} else {
|
||||
gengcmask(t, gcmask);
|
||||
x1 = 0;
|
||||
@ -845,14 +845,14 @@ dcommontype(Sym *s, int ot, Type *t)
|
||||
sbits->flags |= SymUniq;
|
||||
for(i = 0; i < 2*widthptr; i++)
|
||||
duint8(sbits, i, gcmask[i]);
|
||||
arch.ggloblsym(sbits, 2*widthptr, DUPOK|RODATA);
|
||||
ggloblsym(sbits, 2*widthptr, DUPOK|RODATA);
|
||||
}
|
||||
ot = arch.dsymptr(s, ot, sbits, 0);
|
||||
ot = dsymptr(s, ot, sbits, 0);
|
||||
ot = duintptr(s, ot, 0);
|
||||
}
|
||||
p = smprint("%-uT", t);
|
||||
//print("dcommontype: %s\n", p);
|
||||
ot = arch.dgostringptr(s, ot, p); // string
|
||||
ot = dgostringptr(s, ot, p); // string
|
||||
free(p);
|
||||
|
||||
// skip pointer to extraType,
|
||||
@ -861,8 +861,8 @@ dcommontype(Sym *s, int ot, Type *t)
|
||||
// otherwise linker will assume 0.
|
||||
ot += widthptr;
|
||||
|
||||
ot = arch.dsymptr(s, ot, sptr, 0); // ptrto type
|
||||
ot = arch.dsymptr(s, ot, zero, 0); // ptr to zero value
|
||||
ot = dsymptr(s, ot, sptr, 0); // ptrto type
|
||||
ot = dsymptr(s, ot, zero, 0); // ptr to zero value
|
||||
return ot;
|
||||
}
|
||||
|
||||
@ -1092,15 +1092,15 @@ ok:
|
||||
s2 = dtypesym(t2);
|
||||
ot = dcommontype(s, ot, t);
|
||||
xt = ot - 3*widthptr;
|
||||
ot = arch.dsymptr(s, ot, s1, 0);
|
||||
ot = arch.dsymptr(s, ot, s2, 0);
|
||||
ot = dsymptr(s, ot, s1, 0);
|
||||
ot = dsymptr(s, ot, s2, 0);
|
||||
ot = duintptr(s, ot, t->bound);
|
||||
} else {
|
||||
// ../../runtime/type.go:/SliceType
|
||||
s1 = dtypesym(t->type);
|
||||
ot = dcommontype(s, ot, t);
|
||||
xt = ot - 3*widthptr;
|
||||
ot = arch.dsymptr(s, ot, s1, 0);
|
||||
ot = dsymptr(s, ot, s1, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1109,7 +1109,7 @@ ok:
|
||||
s1 = dtypesym(t->type);
|
||||
ot = dcommontype(s, ot, t);
|
||||
xt = ot - 3*widthptr;
|
||||
ot = arch.dsymptr(s, ot, s1, 0);
|
||||
ot = dsymptr(s, ot, s1, 0);
|
||||
ot = duintptr(s, ot, t->chan);
|
||||
break;
|
||||
|
||||
@ -1130,21 +1130,21 @@ ok:
|
||||
|
||||
// two slice headers: in and out.
|
||||
ot = rnd(ot, widthptr);
|
||||
ot = arch.dsymptr(s, ot, s, ot+2*(widthptr+2*widthint));
|
||||
ot = dsymptr(s, ot, s, ot+2*(widthptr+2*widthint));
|
||||
n = t->thistuple + t->intuple;
|
||||
ot = duintxx(s, ot, n, widthint);
|
||||
ot = duintxx(s, ot, n, widthint);
|
||||
ot = arch.dsymptr(s, ot, s, ot+1*(widthptr+2*widthint)+n*widthptr);
|
||||
ot = dsymptr(s, ot, s, ot+1*(widthptr+2*widthint)+n*widthptr);
|
||||
ot = duintxx(s, ot, t->outtuple, widthint);
|
||||
ot = duintxx(s, ot, t->outtuple, widthint);
|
||||
|
||||
// slice data
|
||||
for(t1=getthisx(t)->type; t1; t1=t1->down, n++)
|
||||
ot = arch.dsymptr(s, ot, dtypesym(t1->type), 0);
|
||||
ot = dsymptr(s, ot, dtypesym(t1->type), 0);
|
||||
for(t1=getinargx(t)->type; t1; t1=t1->down, n++)
|
||||
ot = arch.dsymptr(s, ot, dtypesym(t1->type), 0);
|
||||
ot = dsymptr(s, ot, dtypesym(t1->type), 0);
|
||||
for(t1=getoutargx(t)->type; t1; t1=t1->down, n++)
|
||||
ot = arch.dsymptr(s, ot, dtypesym(t1->type), 0);
|
||||
ot = dsymptr(s, ot, dtypesym(t1->type), 0);
|
||||
break;
|
||||
|
||||
case TINTER:
|
||||
@ -1158,14 +1158,14 @@ ok:
|
||||
// ../../runtime/type.go:/InterfaceType
|
||||
ot = dcommontype(s, ot, t);
|
||||
xt = ot - 3*widthptr;
|
||||
ot = arch.dsymptr(s, ot, s, ot+widthptr+2*widthint);
|
||||
ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
|
||||
ot = duintxx(s, ot, n, widthint);
|
||||
ot = duintxx(s, ot, n, widthint);
|
||||
for(a=m; a; a=a->link) {
|
||||
// ../../runtime/type.go:/imethod
|
||||
ot = arch.dgostringptr(s, ot, a->name);
|
||||
ot = dgostringptr(s, ot, a->name);
|
||||
ot = dgopkgpath(s, ot, a->pkg);
|
||||
ot = arch.dsymptr(s, ot, dtypesym(a->type), 0);
|
||||
ot = dsymptr(s, ot, dtypesym(a->type), 0);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1177,10 +1177,10 @@ ok:
|
||||
s4 = dtypesym(hmap(t));
|
||||
ot = dcommontype(s, ot, t);
|
||||
xt = ot - 3*widthptr;
|
||||
ot = arch.dsymptr(s, ot, s1, 0);
|
||||
ot = arch.dsymptr(s, ot, s2, 0);
|
||||
ot = arch.dsymptr(s, ot, s3, 0);
|
||||
ot = arch.dsymptr(s, ot, s4, 0);
|
||||
ot = dsymptr(s, ot, s1, 0);
|
||||
ot = dsymptr(s, ot, s2, 0);
|
||||
ot = dsymptr(s, ot, s3, 0);
|
||||
ot = dsymptr(s, ot, s4, 0);
|
||||
if(t->down->width > MAXKEYSIZE) {
|
||||
ot = duint8(s, ot, widthptr);
|
||||
ot = duint8(s, ot, 1); // indirect
|
||||
@ -1210,7 +1210,7 @@ ok:
|
||||
s1 = dtypesym(t->type);
|
||||
ot = dcommontype(s, ot, t);
|
||||
xt = ot - 3*widthptr;
|
||||
ot = arch.dsymptr(s, ot, s1, 0);
|
||||
ot = dsymptr(s, ot, s1, 0);
|
||||
break;
|
||||
|
||||
case TSTRUCT:
|
||||
@ -1223,32 +1223,32 @@ ok:
|
||||
}
|
||||
ot = dcommontype(s, ot, t);
|
||||
xt = ot - 3*widthptr;
|
||||
ot = arch.dsymptr(s, ot, s, ot+widthptr+2*widthint);
|
||||
ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
|
||||
ot = duintxx(s, ot, n, widthint);
|
||||
ot = duintxx(s, ot, n, widthint);
|
||||
for(t1=t->type; t1!=T; t1=t1->down) {
|
||||
// ../../runtime/type.go:/structField
|
||||
if(t1->sym && !t1->embedded) {
|
||||
ot = arch.dgostringptr(s, ot, t1->sym->name);
|
||||
ot = dgostringptr(s, ot, t1->sym->name);
|
||||
if(exportname(t1->sym->name))
|
||||
ot = arch.dgostringptr(s, ot, nil);
|
||||
ot = dgostringptr(s, ot, nil);
|
||||
else
|
||||
ot = dgopkgpath(s, ot, t1->sym->pkg);
|
||||
} else {
|
||||
ot = arch.dgostringptr(s, ot, nil);
|
||||
ot = dgostringptr(s, ot, nil);
|
||||
if(t1->type->sym != S && t1->type->sym->pkg == builtinpkg)
|
||||
ot = dgopkgpath(s, ot, localpkg);
|
||||
else
|
||||
ot = arch.dgostringptr(s, ot, nil);
|
||||
ot = dgostringptr(s, ot, nil);
|
||||
}
|
||||
ot = arch.dsymptr(s, ot, dtypesym(t1->type), 0);
|
||||
ot = arch.dgostrlitptr(s, ot, t1->note);
|
||||
ot = dsymptr(s, ot, dtypesym(t1->type), 0);
|
||||
ot = dgostrlitptr(s, ot, t1->note);
|
||||
ot = duintptr(s, ot, t1->width); // field offset
|
||||
}
|
||||
break;
|
||||
}
|
||||
ot = dextratype(s, ot, t, xt);
|
||||
arch.ggloblsym(s, ot, dupok|RODATA);
|
||||
ggloblsym(s, ot, dupok|RODATA);
|
||||
|
||||
// generate typelink.foo pointing at s = type.foo.
|
||||
// The linker will leave a table of all the typelinks for
|
||||
@ -1261,8 +1261,8 @@ ok:
|
||||
case TCHAN:
|
||||
case TMAP:
|
||||
slink = typelinksym(t);
|
||||
arch.dsymptr(slink, 0, s, 0);
|
||||
arch.ggloblsym(slink, widthptr, dupok|RODATA);
|
||||
dsymptr(slink, 0, s, 0);
|
||||
ggloblsym(slink, widthptr, dupok|RODATA);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1354,18 +1354,18 @@ dalgsym(Type *t)
|
||||
hashfunc = pkglookup(p, typepkg);
|
||||
free(p);
|
||||
ot = 0;
|
||||
ot = arch.dsymptr(hashfunc, ot, pkglookup("memhash_varlen", runtimepkg), 0);
|
||||
ot = dsymptr(hashfunc, ot, pkglookup("memhash_varlen", runtimepkg), 0);
|
||||
ot = duintxx(hashfunc, ot, t->width, widthptr); // size encoded in closure
|
||||
arch.ggloblsym(hashfunc, ot, DUPOK|RODATA);
|
||||
ggloblsym(hashfunc, ot, DUPOK|RODATA);
|
||||
|
||||
// make equality closure
|
||||
p = smprint(".eqfunc%lld", t->width);
|
||||
eqfunc = pkglookup(p, typepkg);
|
||||
free(p);
|
||||
ot = 0;
|
||||
ot = arch.dsymptr(eqfunc, ot, pkglookup("memequal_varlen", runtimepkg), 0);
|
||||
ot = dsymptr(eqfunc, ot, pkglookup("memequal_varlen", runtimepkg), 0);
|
||||
ot = duintxx(eqfunc, ot, t->width, widthptr);
|
||||
arch.ggloblsym(eqfunc, ot, DUPOK|RODATA);
|
||||
ggloblsym(eqfunc, ot, DUPOK|RODATA);
|
||||
} else {
|
||||
// generate an alg table specific to this type
|
||||
s = typesymprefix(".alg", t);
|
||||
@ -1378,16 +1378,16 @@ dalgsym(Type *t)
|
||||
geneq(eq, t);
|
||||
|
||||
// make Go funcs (closures) for calling hash and equal from Go
|
||||
arch.dsymptr(hashfunc, 0, hash, 0);
|
||||
arch.ggloblsym(hashfunc, widthptr, DUPOK|RODATA);
|
||||
arch.dsymptr(eqfunc, 0, eq, 0);
|
||||
arch.ggloblsym(eqfunc, widthptr, DUPOK|RODATA);
|
||||
dsymptr(hashfunc, 0, hash, 0);
|
||||
ggloblsym(hashfunc, widthptr, DUPOK|RODATA);
|
||||
dsymptr(eqfunc, 0, eq, 0);
|
||||
ggloblsym(eqfunc, widthptr, DUPOK|RODATA);
|
||||
}
|
||||
// ../../runtime/alg.go:/typeAlg
|
||||
ot = 0;
|
||||
ot = arch.dsymptr(s, ot, hashfunc, 0);
|
||||
ot = arch.dsymptr(s, ot, eqfunc, 0);
|
||||
arch.ggloblsym(s, ot, DUPOK|RODATA);
|
||||
ot = dsymptr(s, ot, hashfunc, 0);
|
||||
ot = dsymptr(s, ot, eqfunc, 0);
|
||||
ggloblsym(s, ot, DUPOK|RODATA);
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -1570,7 +1570,7 @@ gengcprog(Type *t, Sym **pgc0, Sym **pgc1)
|
||||
// Don't generate it if it's too large, runtime will unroll directly into GC bitmap.
|
||||
if(size <= MaxGCMask) {
|
||||
gc0 = typesymprefix(".gc", t);
|
||||
arch.ggloblsym(gc0, size, DUPOK|NOPTR);
|
||||
ggloblsym(gc0, size, DUPOK|NOPTR);
|
||||
*pgc0 = gc0;
|
||||
}
|
||||
|
||||
@ -1580,7 +1580,7 @@ gengcprog(Type *t, Sym **pgc0, Sym **pgc1)
|
||||
xoffset = 0;
|
||||
gengcprog1(&g, t, &xoffset);
|
||||
ot = proggenfini(&g);
|
||||
arch.ggloblsym(gc1, ot, DUPOK|RODATA);
|
||||
ggloblsym(gc1, ot, DUPOK|RODATA);
|
||||
*pgc1 = gc1;
|
||||
}
|
||||
|
||||
|
@ -302,13 +302,13 @@ staticcopy(Node *l, Node *r, NodeList **out)
|
||||
case OLITERAL:
|
||||
if(iszero(r))
|
||||
return 1;
|
||||
arch.gdata(l, r, l->type->width);
|
||||
gdata(l, r, l->type->width);
|
||||
return 1;
|
||||
|
||||
case OADDR:
|
||||
switch(r->left->op) {
|
||||
case ONAME:
|
||||
arch.gdata(l, r, l->type->width);
|
||||
gdata(l, r, l->type->width);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
@ -322,7 +322,7 @@ staticcopy(Node *l, Node *r, NodeList **out)
|
||||
case OSTRUCTLIT:
|
||||
case OMAPLIT:
|
||||
// copy pointer
|
||||
arch.gdata(l, nod(OADDR, r->nname, N), l->type->width);
|
||||
gdata(l, nod(OADDR, r->nname, N), l->type->width);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
@ -333,11 +333,11 @@ staticcopy(Node *l, Node *r, NodeList **out)
|
||||
a = r->nname;
|
||||
n1 = *l;
|
||||
n1.xoffset = l->xoffset + Array_array;
|
||||
arch.gdata(&n1, nod(OADDR, a, N), widthptr);
|
||||
gdata(&n1, nod(OADDR, a, N), widthptr);
|
||||
n1.xoffset = l->xoffset + Array_nel;
|
||||
arch.gdata(&n1, r->right, widthint);
|
||||
gdata(&n1, r->right, widthint);
|
||||
n1.xoffset = l->xoffset + Array_cap;
|
||||
arch.gdata(&n1, r->right, widthint);
|
||||
gdata(&n1, r->right, widthint);
|
||||
return 1;
|
||||
}
|
||||
// fall through
|
||||
@ -349,7 +349,7 @@ staticcopy(Node *l, Node *r, NodeList **out)
|
||||
n1.xoffset = l->xoffset + e->xoffset;
|
||||
n1.type = e->expr->type;
|
||||
if(e->expr->op == OLITERAL)
|
||||
arch.gdata(&n1, e->expr, n1.type->width);
|
||||
gdata(&n1, e->expr, n1.type->width);
|
||||
else {
|
||||
ll = nod(OXXX, N, N);
|
||||
*ll = n1;
|
||||
@ -394,14 +394,14 @@ staticassign(Node *l, Node *r, NodeList **out)
|
||||
case OLITERAL:
|
||||
if(iszero(r))
|
||||
return 1;
|
||||
arch.gdata(l, r, l->type->width);
|
||||
gdata(l, r, l->type->width);
|
||||
return 1;
|
||||
|
||||
case OADDR:
|
||||
if(stataddr(&nam, r->left)) {
|
||||
n1 = *r;
|
||||
n1.left = &nam;
|
||||
arch.gdata(l, &n1, l->type->width);
|
||||
gdata(l, &n1, l->type->width);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -417,7 +417,7 @@ staticassign(Node *l, Node *r, NodeList **out)
|
||||
// Init pointer.
|
||||
a = staticname(r->left->type, 1);
|
||||
r->nname = a;
|
||||
arch.gdata(l, nod(OADDR, a, N), l->type->width);
|
||||
gdata(l, nod(OADDR, a, N), l->type->width);
|
||||
// Init underlying literal.
|
||||
if(!staticassign(a, r->left, out))
|
||||
*out = list(*out, nod(OAS, a, r->left));
|
||||
@ -444,11 +444,11 @@ staticassign(Node *l, Node *r, NodeList **out)
|
||||
r->nname = a;
|
||||
n1 = *l;
|
||||
n1.xoffset = l->xoffset + Array_array;
|
||||
arch.gdata(&n1, nod(OADDR, a, N), widthptr);
|
||||
gdata(&n1, nod(OADDR, a, N), widthptr);
|
||||
n1.xoffset = l->xoffset + Array_nel;
|
||||
arch.gdata(&n1, r->right, widthint);
|
||||
gdata(&n1, r->right, widthint);
|
||||
n1.xoffset = l->xoffset + Array_cap;
|
||||
arch.gdata(&n1, r->right, widthint);
|
||||
gdata(&n1, r->right, widthint);
|
||||
// Fall through to init underlying array.
|
||||
l = a;
|
||||
}
|
||||
@ -462,7 +462,7 @@ staticassign(Node *l, Node *r, NodeList **out)
|
||||
n1.xoffset = l->xoffset + e->xoffset;
|
||||
n1.type = e->expr->type;
|
||||
if(e->expr->op == OLITERAL)
|
||||
arch.gdata(&n1, e->expr, n1.type->width);
|
||||
gdata(&n1, e->expr, n1.type->width);
|
||||
else {
|
||||
a = nod(OXXX, N, N);
|
||||
*a = n1;
|
||||
@ -1303,16 +1303,16 @@ gen_as_init(Node *n)
|
||||
case TPTR64:
|
||||
case TFLOAT32:
|
||||
case TFLOAT64:
|
||||
arch.gdata(&nam, nr, nr->type->width);
|
||||
gdata(&nam, nr, nr->type->width);
|
||||
break;
|
||||
|
||||
case TCOMPLEX64:
|
||||
case TCOMPLEX128:
|
||||
arch.gdatacomplex(&nam, nr->val.u.cval);
|
||||
gdatacomplex(&nam, nr->val.u.cval);
|
||||
break;
|
||||
|
||||
case TSTRING:
|
||||
arch.gdatastring(&nam, nr->val.u.sval);
|
||||
gdatastring(&nam, nr->val.u.sval);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -1320,7 +1320,7 @@ yes:
|
||||
return 1;
|
||||
|
||||
slice:
|
||||
arch.gused(N); // in case the data is the dest of a goto
|
||||
gused(N); // in case the data is the dest of a goto
|
||||
nl = nr;
|
||||
if(nr == N || nr->op != OADDR)
|
||||
goto no;
|
||||
@ -1333,14 +1333,14 @@ slice:
|
||||
goto no;
|
||||
|
||||
nam.xoffset += Array_array;
|
||||
arch.gdata(&nam, nl, types[tptr]->width);
|
||||
gdata(&nam, nl, types[tptr]->width);
|
||||
|
||||
nam.xoffset += Array_nel-Array_array;
|
||||
nodconst(&nod1, types[TINT], nr->type->bound);
|
||||
arch.gdata(&nam, &nod1, widthint);
|
||||
gdata(&nam, &nod1, widthint);
|
||||
|
||||
nam.xoffset += Array_cap-Array_nel;
|
||||
arch.gdata(&nam, &nod1, widthint);
|
||||
gdata(&nam, &nod1, widthint);
|
||||
|
||||
goto yes;
|
||||
|
||||
|
@ -927,7 +927,7 @@ walkexpr(Node **np, NodeList **init)
|
||||
l->class = PEXTERN;
|
||||
l->xoffset = 0;
|
||||
sym->def = l;
|
||||
arch.ggloblsym(sym, widthptr, DUPOK|NOPTR);
|
||||
ggloblsym(sym, widthptr, DUPOK|NOPTR);
|
||||
}
|
||||
l = nod(OADDR, sym->def, N);
|
||||
l->addable = 1;
|
||||
@ -1602,7 +1602,7 @@ ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
|
||||
l = tmp;
|
||||
}
|
||||
|
||||
a = nod(OAS, l, arch.nodarg(r, fp));
|
||||
a = nod(OAS, l, nodarg(r, fp));
|
||||
a = convas(a, init);
|
||||
ullmancalc(a);
|
||||
if(a->ullman >= UINF) {
|
||||
@ -1655,7 +1655,7 @@ mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, Nod
|
||||
walkexpr(&n, init);
|
||||
}
|
||||
|
||||
a = nod(OAS, arch.nodarg(l, fp), n);
|
||||
a = nod(OAS, nodarg(l, fp), n);
|
||||
nn = list(nn, convas(a, init));
|
||||
return nn;
|
||||
}
|
||||
@ -1735,7 +1735,7 @@ ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeL
|
||||
if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) {
|
||||
// optimization - can do block copy
|
||||
if(eqtypenoname(r->type, *nl)) {
|
||||
a = arch.nodarg(*nl, fp);
|
||||
a = nodarg(*nl, fp);
|
||||
r = nod(OCONVNOP, r, N);
|
||||
r->type = a->type;
|
||||
nn = list1(convas(nod(OAS, a, r), init));
|
||||
@ -1772,7 +1772,7 @@ loop:
|
||||
// argument to a ddd parameter then it is
|
||||
// passed thru unencapsulated
|
||||
if(r != N && lr->next == nil && isddd && eqtype(l->type, r->type)) {
|
||||
a = nod(OAS, arch.nodarg(l, fp), r);
|
||||
a = nod(OAS, nodarg(l, fp), r);
|
||||
a = convas(a, init);
|
||||
nn = list(nn, a);
|
||||
goto ret;
|
||||
@ -1797,7 +1797,7 @@ loop:
|
||||
goto ret;
|
||||
}
|
||||
|
||||
a = nod(OAS, arch.nodarg(l, fp), r);
|
||||
a = nod(OAS, nodarg(l, fp), r);
|
||||
a = convas(a, init);
|
||||
nn = list(nn, a);
|
||||
|
||||
@ -2560,7 +2560,7 @@ paramstoheap(Type **argin, int out)
|
||||
// Defer might stop a panic and show the
|
||||
// return values as they exist at the time of panic.
|
||||
// Make sure to zero them on entry to the function.
|
||||
nn = list(nn, nod(OAS, arch.nodarg(t, 1), N));
|
||||
nn = list(nn, nod(OAS, nodarg(t, 1), N));
|
||||
}
|
||||
if(v == N || !(v->class & PHEAP))
|
||||
continue;
|
||||
|
@ -96,6 +96,7 @@ static Optab optab[] =
|
||||
{ ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
|
||||
{ ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0 },
|
||||
{ ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0 },
|
||||
{ ABEQ, C_RCON, C_NONE, C_SBRA, 5, 4, 0 }, // prediction hinted form, hint ignored
|
||||
|
||||
{ AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL },
|
||||
{ ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0 },
|
||||
@ -353,14 +354,6 @@ static uchar xcmp[C_GOK+1][C_GOK+1];
|
||||
|
||||
static LSym *deferreturn;
|
||||
|
||||
static void
|
||||
nocache(Prog *p)
|
||||
{
|
||||
p->optab = 0;
|
||||
p->from.class = 0;
|
||||
p->to.class = 0;
|
||||
}
|
||||
|
||||
/* size of a case statement including jump table */
|
||||
static int32
|
||||
casesz(Link *ctxt, Prog *p)
|
||||
|
@ -133,3 +133,24 @@ double2ieee(uint64 *ieee, float64 f)
|
||||
{
|
||||
memmove(ieee, &f, 8);
|
||||
}
|
||||
|
||||
void
|
||||
nopout(Prog *p)
|
||||
{
|
||||
p->as = ANOP;
|
||||
p->scond = zprog.scond;
|
||||
p->from = zprog.from;
|
||||
p->from3 = zprog.from3;
|
||||
p->reg = zprog.reg;
|
||||
p->to = zprog.to;
|
||||
}
|
||||
|
||||
void
|
||||
nocache(Prog *p)
|
||||
{
|
||||
p->optab = 0;
|
||||
p->from.class = 0;
|
||||
p->from3.class = 0;
|
||||
p->to.class = 0;
|
||||
}
|
||||
|
||||
|
@ -184,14 +184,6 @@ linkcase(Prog *casep)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nocache5(Prog *p)
|
||||
{
|
||||
p->optab = 0;
|
||||
p->from.class = 0;
|
||||
p->to.class = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
preprocess(Link *ctxt, LSym *cursym)
|
||||
{
|
||||
@ -478,7 +470,7 @@ preprocess(Link *ctxt, LSym *cursym)
|
||||
break;
|
||||
|
||||
case ARET:
|
||||
nocache5(p);
|
||||
nocache(p);
|
||||
if(cursym->text->mark & LEAF) {
|
||||
if(!autosize) {
|
||||
p->as = AB;
|
||||
|
@ -35,18 +35,6 @@
|
||||
#include "../cmd/6l/6.out.h"
|
||||
#include "../runtime/stack.h"
|
||||
|
||||
static void
|
||||
nopout(Prog *p)
|
||||
{
|
||||
p->as = ANOP;
|
||||
p->from.type = TYPE_NONE;
|
||||
p->from.reg = 0;
|
||||
p->from.name = 0;
|
||||
p->to.type = TYPE_NONE;
|
||||
p->to.reg = 0;
|
||||
p->to.name = 0;
|
||||
}
|
||||
|
||||
static void nacladdr(Link*, Prog*, Addr*);
|
||||
|
||||
static int
|
||||
|
Loading…
x
Reference in New Issue
Block a user