summaryrefslogtreecommitdiff
path: root/src/cmd/8g
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2012-04-06 15:14:11 +0200
committerOndřej Surý <ondrej@sury.org>2012-04-06 15:14:11 +0200
commit505c19580e0f43fe5224431459cacb7c21edd93d (patch)
tree79e2634c253d60afc0cc0b2f510dc7dcbb48497b /src/cmd/8g
parent1336a7c91e596c423a49d1194ea42d98bca0d958 (diff)
downloadgolang-505c19580e0f43fe5224431459cacb7c21edd93d.tar.gz
Imported Upstream version 1upstream/1
Diffstat (limited to 'src/cmd/8g')
-rw-r--r--src/cmd/8g/Makefile35
-rw-r--r--src/cmd/8g/cgen.c42
-rw-r--r--src/cmd/8g/cgen64.c2
-rw-r--r--src/cmd/8g/doc.go2
-rw-r--r--src/cmd/8g/galign.c2
-rw-r--r--src/cmd/8g/gg.h24
-rw-r--r--src/cmd/8g/ggen.c26
-rw-r--r--src/cmd/8g/gobj.c66
-rw-r--r--src/cmd/8g/gsubr.c83
-rw-r--r--src/cmd/8g/list.c4
-rw-r--r--src/cmd/8g/opt.h2
-rw-r--r--src/cmd/8g/peep.c5
-rw-r--r--src/cmd/8g/reg.c188
13 files changed, 320 insertions, 161 deletions
diff --git a/src/cmd/8g/Makefile b/src/cmd/8g/Makefile
index b459782a3..3f528d751 100644
--- a/src/cmd/8g/Makefile
+++ b/src/cmd/8g/Makefile
@@ -1,36 +1,5 @@
-# Copyright 2009 The Go Authors. All rights reserved.
+# Copyright 2012 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.inc
-O:=$(HOST_O)
-
-TARG=8g
-
-HFILES=\
- ../gc/go.h\
- ../8l/8.out.h\
- gg.h\
- opt.h\
-
-OFILES=\
- ../8l/enam.$O\
- cgen.$O\
- cgen64.$O\
- cplx.$O\
- galign.$O\
- ggen.$O\
- gobj.$O\
- gsubr.$O\
- list.$O\
- peep.$O\
- pgen.$O\
- reg.$O\
-
-LIB=\
- ../gc/gc.a\
-
-include ../../Make.ccmd
-
-%.$O: ../gc/%.c
- $(HOST_CC) $(HOST_CFLAGS) -c -I. -o $@ ../gc/$*.c
+include ../../Make.dist
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
index b316e6e34..48619ac73 100644
--- a/src/cmd/8g/cgen.c
+++ b/src/cmd/8g/cgen.c
@@ -5,6 +5,8 @@
// TODO(rsc):
// assume CLD?
+#include <u.h>
+#include <libc.h>
#include "gg.h"
void
@@ -96,6 +98,9 @@ cgen(Node *n, Node *res)
if(isslice(n->left->type))
n->addable = n->left->addable;
break;
+ case OITAB:
+ n->addable = n->left->addable;
+ break;
}
// if both are addressable, move
@@ -250,6 +255,13 @@ cgen(Node *n, Node *res)
regfree(&n1);
break;
+ case OITAB:
+ igen(nl, &n1, res);
+ n1.type = ptrto(types[TUINTPTR]);
+ gmove(&n1, res);
+ regfree(&n1);
+ break;
+
case OLEN:
if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
// map has len in the first 32-bit word.
@@ -680,7 +692,6 @@ agen(Node *n, Node *res)
break;
case ODOT:
- t = nl->type;
agen(nl, res);
if(n->xoffset != 0) {
nodconst(&n1, types[tptr], n->xoffset);
@@ -786,6 +797,7 @@ bgen(Node *n, int true, Prog *to)
int et, a;
Node *nl, *nr, *r;
Node n1, n2, tmp, t1, t2, ax;
+ NodeList *ll;
Prog *p1, *p2;
if(debug['g']) {
@@ -798,9 +810,6 @@ bgen(Node *n, int true, Prog *to)
if(n->ninit != nil)
genlist(n->ninit);
- nl = n->left;
- nr = n->right;
-
if(n->type == T) {
convlit(&n, types[TBOOL]);
if(n->type == T)
@@ -813,7 +822,6 @@ bgen(Node *n, int true, Prog *to)
patch(gins(AEND, N, N), to);
return;
}
- nl = N;
nr = N;
switch(n->op) {
@@ -905,7 +913,10 @@ bgen(Node *n, int true, Prog *to)
p1 = gbranch(AJMP, T);
p2 = gbranch(AJMP, T);
patch(p1, pc);
+ ll = n->ninit; // avoid re-genning ninit
+ n->ninit = nil;
bgen(n, 1, p2);
+ n->ninit = ll;
patch(gbranch(AJMP, T), to);
patch(p2, pc);
break;
@@ -1129,24 +1140,29 @@ stkof(Node *n)
* memmove(&res, &n, w);
*/
void
-sgen(Node *n, Node *res, int32 w)
+sgen(Node *n, Node *res, int64 w)
{
Node dst, src, tdst, tsrc;
int32 c, q, odst, osrc;
if(debug['g']) {
- print("\nsgen w=%d\n", w);
+ print("\nsgen w=%lld\n", w);
dump("r", n);
dump("res", res);
}
- if(w == 0)
- return;
- if(n->ullman >= UINF && res->ullman >= UINF) {
+ if(n->ullman >= UINF && res->ullman >= UINF)
fatal("sgen UINF");
- }
- if(w < 0)
- fatal("sgen copy %d", w);
+ if(w < 0 || (int32)w != w)
+ fatal("sgen copy %lld", w);
+
+ if(w == 0) {
+ // evaluate side effects only.
+ tempname(&tdst, types[tptr]);
+ agen(res, &tdst);
+ agen(n, &tdst);
+ return;
+ }
// offset on the stack
osrc = stkof(n);
diff --git a/src/cmd/8g/cgen64.c b/src/cmd/8g/cgen64.c
index ba99cec74..8e568a0f9 100644
--- a/src/cmd/8g/cgen64.c
+++ b/src/cmd/8g/cgen64.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
/*
diff --git a/src/cmd/8g/doc.go b/src/cmd/8g/doc.go
index 2d9ff9a42..6d678eac8 100644
--- a/src/cmd/8g/doc.go
+++ b/src/cmd/8g/doc.go
@@ -9,7 +9,5 @@ The $GOARCH for these tools is 386.
It reads .go files and outputs .8 files. The flags are documented in ../gc/doc.go.
-There is no instruction optimizer, so the -N flag is a no-op.
-
*/
package documentation
diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c
index 7734603c4..4526a2efb 100644
--- a/src/cmd/8g/galign.c
+++ b/src/cmd/8g/galign.c
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+#include <u.h>
+#include <libc.h>
#include "gg.h"
int thechar = '8';
diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h
index 9f7a66a29..0a4f0ad2d 100644
--- a/src/cmd/8g/gg.h
+++ b/src/cmd/8g/gg.h
@@ -2,16 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include <u.h>
-#include <libc.h>
-
-#include "../gc/go.h"
-#include "../8l/8.out.h"
-
#ifndef EXTERN
#define EXTERN extern
#endif
+#include "../gc/go.h"
+#include "../8l/8.out.h"
+
typedef struct Addr Addr;
struct Addr
@@ -46,6 +43,8 @@ struct Prog
void* reg; // pointer to containing Reg struct
};
+#define TEXTFLAG from.scale
+
// foptoas flags
enum
{
@@ -54,15 +53,12 @@ enum
Fpop2 = 1<<2,
};
-EXTERN Biobuf* bout;
EXTERN int32 dynloc;
EXTERN uchar reg[D_NONE];
EXTERN int32 pcloc; // instruction counter
EXTERN Strlit emptystring;
extern char* anames[];
-EXTERN Hist* hist;
EXTERN Prog zprog;
-EXTERN Node* curfn;
EXTERN Node* newproc;
EXTERN Node* deferproc;
EXTERN Node* deferreturn;
@@ -103,7 +99,7 @@ void agenr(Node *n, Node *a, Node *res);
void igen(Node*, Node*, Node*);
vlong fieldoffset(Type*, Node*);
void bgen(Node*, int, Prog*);
-void sgen(Node*, Node*, int32);
+void sgen(Node*, Node*, int64);
void gmove(Node*, Node*);
Prog* gins(int, Node*, Node*);
int samaddr(Node*, Node*);
@@ -168,12 +164,6 @@ void complexgen(Node*, Node*);
void complexbool(int, Node*, Node*, int, Prog*);
/*
- * gobj.c
- */
-void data(void);
-void text(void);
-
-/*
* list.c
*/
int Aconv(Fmt*);
@@ -185,3 +175,5 @@ void listinit(void);
void zaddr(Biobuf*, Addr*, int, int);
+#pragma varargck type "D" Addr*
+#pragma varargck type "lD" Addr*
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
index 108c493aa..6a4570199 100644
--- a/src/cmd/8g/ggen.c
+++ b/src/cmd/8g/ggen.c
@@ -4,6 +4,8 @@
#undef EXTERN
#define EXTERN
+#include <u.h>
+#include <libc.h>
#include "gg.h"
#include "opt.h"
@@ -26,10 +28,10 @@ markautoused(Prog* p)
{
for (; p; p = p->link) {
if (p->from.type == D_AUTO && p->from.node)
- p->from.node->used++;
+ p->from.node->used = 1;
if (p->to.type == D_AUTO && p->to.node)
- p->to.node->used++;
+ p->to.node->used = 1;
}
}
@@ -429,7 +431,6 @@ hard:
if(nr->ullman >= nl->ullman || nl->addable) {
mgen(nr, &n2, N);
nr = &n2;
- nr = &n2;
} else {
tempname(&n2, nr->type);
cgen(nr, &n2);
@@ -483,8 +484,8 @@ void
dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
{
int check;
- Node n1, t1, t2, n4, nz;
- Type *t;
+ Node n1, t1, t2, t3, t4, n4, nz;
+ Type *t, *t0;
Prog *p1, *p2, *p3;
// Have to be careful about handling
@@ -496,6 +497,7 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
// For int32 and int64, use explicit test.
// Could use int64 hw for int32.
t = nl->type;
+ t0 = t;
check = 0;
if(issigned[t->etype]) {
check = 1;
@@ -514,8 +516,18 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
tempname(&t1, t);
tempname(&t2, t);
- cgen(nl, &t1);
- cgen(nr, &t2);
+ if(t0 != t) {
+ tempname(&t3, t0);
+ tempname(&t4, t0);
+ cgen(nl, &t3);
+ cgen(nr, &t4);
+ // Convert.
+ gmove(&t3, &t1);
+ gmove(&t4, &t2);
+ } else {
+ cgen(nl, &t1);
+ cgen(nr, &t2);
+ }
if(!samereg(ax, res) && !samereg(dx, res))
regalloc(&n1, t, res);
diff --git a/src/cmd/8g/gobj.c b/src/cmd/8g/gobj.c
index 31c42a3f2..d8c8f5ab9 100644
--- a/src/cmd/8g/gobj.c
+++ b/src/cmd/8g/gobj.c
@@ -28,6 +28,8 @@
// 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"
void
@@ -276,54 +278,6 @@ dumpfuncs(void)
}
}
-/* deferred DATA output */
-static Prog *strdat;
-static Prog *estrdat;
-static int gflag;
-static Prog *savepc;
-
-void
-data(void)
-{
- gflag = debug['g'];
- debug['g'] = 0;
-
- if(estrdat == nil) {
- strdat = mal(sizeof(*pc));
- clearp(strdat);
- estrdat = strdat;
- }
- if(savepc)
- fatal("data phase error");
- savepc = pc;
- pc = estrdat;
-}
-
-void
-text(void)
-{
- if(!savepc)
- fatal("text phase error");
- debug['g'] = gflag;
- estrdat = pc;
- pc = savepc;
- savepc = nil;
-}
-
-void
-dumpdata(void)
-{
- Prog *p;
-
- if(estrdat == nil)
- return;
- *pc = *strdat;
- if(gflag)
- for(p=pc; p!=estrdat; p=p->link)
- print("%P\n", p);
- pc = estrdat;
-}
-
int
dsname(Sym *s, int off, char *t, int n)
{
@@ -354,6 +308,7 @@ datastring(char *s, int len, Addr *a)
sym = stringsym(s, len);
a->type = D_EXTERN;
a->sym = sym;
+ a->node = sym->def;
a->offset = widthptr+4; // skip header
a->etype = TINT32;
}
@@ -370,6 +325,7 @@ datagostring(Strlit *sval, Addr *a)
sym = stringsym(sval->s, sval->len);
a->type = D_EXTERN;
a->sym = sym;
+ a->node = sym->def;
a->offset = 0; // header
a->etype = TINT32;
}
@@ -380,6 +336,17 @@ 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));
@@ -547,6 +514,8 @@ genembedtramp(Type *rcvr, Type *method, Sym *newnam, int iface)
Prog *p;
Type *f;
+ USED(iface);
+
e = method->sym;
for(d=0; d<nelem(dotlist); d++) {
c = adddot1(e, rcvr, d, nil, 0);
@@ -626,7 +595,6 @@ out:
// but 6l has a bug, and it can't handle
// JMP instructions too close to the top of
// a new function.
- p = pc;
gins(ANOP, N, N);
}
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
index a35c81eb1..5e89af04a 100644
--- a/src/cmd/8g/gsubr.c
+++ b/src/cmd/8g/gsubr.c
@@ -28,6 +28,8 @@
// 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"
// TODO(rsc): Can make this bigger if we move
@@ -48,6 +50,10 @@ clearp(Prog *p)
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.
@@ -57,10 +63,22 @@ prog(int as)
{
Prog *p;
- p = pc;
- pc = mal(sizeof(*pc));
-
- clearp(pc);
+ 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'])
@@ -69,10 +87,21 @@ prog(int as)
p->as = as;
p->lineno = lineno;
- p->link = pc;
return p;
}
+void
+dumpdata(void)
+{
+ ddumped = 1;
+ if(dfirst == nil)
+ return;
+ newplist();
+ *pc = *dfirst;
+ pc = dpc;
+ clearp(pc);
+}
+
/*
* generate a branch.
* t is ignored.
@@ -82,6 +111,7 @@ gbranch(int as, Type *t)
{
Prog *p;
+ USED(t);
p = prog(as);
p->to.type = D_BRANCH;
p->to.branch = P;
@@ -202,6 +232,8 @@ ggloblnod(Node *nam, int32 width)
p->to.offset = width;
if(nam->readonly)
p->from.scale = RODATA;
+ if(nam->type != T && !haspointers(nam->type))
+ p->from.scale |= NOPTR;
}
void
@@ -753,7 +785,7 @@ ginit(void)
reg[resvd[i]]++;
}
-ulong regpc[D_NONE];
+uintptr regpc[D_NONE];
void
gclean(void)
@@ -822,7 +854,7 @@ regalloc(Node *n, Type *t, Node *o)
fprint(2, "registers allocated at\n");
for(i=D_AX; i<=D_DI; i++)
- fprint(2, "\t%R\t%#ux\n", i, regpc[i]);
+ fprint(2, "\t%R\t%#lux\n", i, regpc[i]);
yyerror("out of fixed registers");
goto err;
@@ -832,7 +864,6 @@ regalloc(Node *n, Type *t, Node *o)
goto out;
}
yyerror("regalloc: unknown type %T", t);
- i = 0;
err:
nodreg(n, t, 0);
@@ -842,7 +873,7 @@ out:
if (i == D_SP)
print("alloc SP\n");
if(reg[i] == 0) {
- regpc[i] = (ulong)__builtin_return_address(0);
+ regpc[i] = (uintptr)getcallerpc(&n);
if(i == D_AX || i == D_CX || i == D_DX || i == D_SP) {
dump("regalloc-o", o);
fatal("regalloc %R", i);
@@ -864,7 +895,7 @@ regfree(Node *n)
i = n->val.u.reg;
if(i == D_SP)
return;
- if(i < 0 || i >= sizeof(reg))
+ if(i < 0 || i >= nelem(reg))
fatal("regfree: reg out of range");
if(reg[i] <= 0)
fatal("regfree: reg not allocated");
@@ -935,8 +966,15 @@ nodarg(Type *t, int fp)
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:
@@ -1005,6 +1043,7 @@ int
ismem(Node *n)
{
switch(n->op) {
+ case OITAB:
case OLEN:
case OCAP:
case OINDREG:
@@ -1123,6 +1162,7 @@ memname(Node *n, Type *t)
strcpy(namebuf, n->sym->name);
namebuf[0] = '.'; // keep optimizer from registerizing
n->sym = lookup(namebuf);
+ n->orig->sym = n->sym;
}
void
@@ -1799,6 +1839,7 @@ naddr(Node *n, Addr *a, int canemitcode)
a->offset = n->xoffset;
a->sym = n->left->sym;
a->type = D_PARAM;
+ a->node = n->left->orig;
break;
case ONAME:
@@ -1809,9 +1850,11 @@ naddr(Node *n, Addr *a, int canemitcode)
a->width = n->type->width;
a->gotype = ngotype(n);
}
- a->pun = n->pun;
a->offset = n->xoffset;
a->sym = n->sym;
+ a->node = n->orig;
+ //if(a->node >= (Node*)&n)
+ // fatal("stack node");
if(a->sym == S)
a->sym = lookup(".noname");
if(n->method) {
@@ -1829,8 +1872,6 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case PAUTO:
a->type = D_AUTO;
- if (n->sym)
- a->node = n->orig;
break;
case PPARAM:
case PPARAMOUT:
@@ -1853,6 +1894,7 @@ naddr(Node *n, Addr *a, int canemitcode)
a->dval = mpgetflt(n->val.u.fval);
break;
case CTINT:
+ case CTRUNE:
a->sym = S;
a->type = D_CONST;
a->offset = mpgetfix(n->val.u.xval);
@@ -1887,6 +1929,17 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
}
fatal("naddr: OADDR\n");
+
+ case OITAB:
+ // itable of interface value
+ naddr(n->left, a, canemitcode);
+ if(a->type == D_CONST && a->offset == 0)
+ break; // len(nil)
+ a->etype = tptr;
+ a->width = widthptr;
+ if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
+ checkoffset(a, canemitcode);
+ break;
case OLEN:
// len of string or slice
@@ -1955,5 +2008,9 @@ sudoclean(void)
int
sudoaddable(int as, Node *n, Addr *a)
{
+ USED(as);
+ USED(n);
+ USED(a);
+
return 0;
}
diff --git a/src/cmd/8g/list.c b/src/cmd/8g/list.c
index edb1ece84..88d3d5f7e 100644
--- a/src/cmd/8g/list.c
+++ b/src/cmd/8g/list.c
@@ -28,6 +28,8 @@
// 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"
static int sconsize;
@@ -128,7 +130,7 @@ Dconv(Fmt *fp)
if(fp->flags & FmtLong) {
d1 = a->offset;
d2 = a->offset2;
- snprint(str, sizeof(str), "$%ud-%ud", (ulong)d1, (ulong)d2);
+ snprint(str, sizeof(str), "$%lud-%lud", (ulong)d1, (ulong)d2);
break;
}
snprint(str, sizeof(str), "$%d", a->offset);
diff --git a/src/cmd/8g/opt.h b/src/cmd/8g/opt.h
index 8f31dec3b..ed6eb15ab 100644
--- a/src/cmd/8g/opt.h
+++ b/src/cmd/8g/opt.h
@@ -162,3 +162,5 @@ int32 RtoB(int);
int32 FtoB(int);
int BtoR(int32);
int BtoF(int32);
+
+#pragma varargck type "D" Adr*
diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c
index 5ad29e1b2..b8a2825e5 100644
--- a/src/cmd/8g/peep.c
+++ b/src/cmd/8g/peep.c
@@ -28,6 +28,8 @@
// 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"
#include "opt.h"
@@ -876,13 +878,12 @@ loop:
case 3: // set
if(p->as == p0->as)
if(p->from.type == p0->from.type)
- if(p->from.sym == p0->from.sym)
+ if(p->from.node == p0->from.node)
if(p->from.offset == p0->from.offset)
if(p->from.scale == p0->from.scale)
if(p->from.dval == p0->from.dval)
if(p->from.index == p0->from.index) {
excise(r);
- t++;
goto loop;
}
break;
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
index 2b878f62a..29270c820 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -28,9 +28,9 @@
// 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"
-#undef EXTERN
-#define EXTERN
#include "opt.h"
#define NREGVAR 8
@@ -39,6 +39,8 @@
static int first = 1;
+static void fixjmp(Prog*);
+
Reg*
rega(void)
{
@@ -89,8 +91,8 @@ setoutvar(void)
ovar.b[z] |= bit.b[z];
t = structnext(&save);
}
-//if(bany(b))
-//print("ovars = %Q\n", &ovar);
+//if(bany(ovar))
+//print("ovars = %Q\n", ovar);
}
static void
@@ -98,19 +100,19 @@ setaddrs(Bits bit)
{
int i, n;
Var *v;
- Sym *s;
+ Node *node;
while(bany(&bit)) {
// convert each bit to a variable
i = bnum(bit);
- s = var[i].sym;
+ node = var[i].node;
n = var[i].name;
bit.b[i/32] &= ~(1L<<(i%32));
// disable all pieces of that variable
for(i=0; i<nvar; i++) {
v = var+i;
- if(v->sym == s && v->name == n)
+ if(v->node == node && v->name == n)
v->addr = 2;
}
}
@@ -132,6 +134,8 @@ regopt(Prog *firstp)
exregoffset = D_DI; // no externals
first = 0;
}
+
+ fixjmp(firstp);
// count instructions
nr = 0;
@@ -155,7 +159,7 @@ regopt(Prog *firstp)
nvar = NREGVAR;
memset(var, 0, NREGVAR*sizeof var[0]);
for(i=0; i<NREGVAR; i++)
- var[i].sym = lookup(regname[i]);
+ var[i].node = newname(lookup(regname[i]));
regbits = RtoB(D_SP);
for(z=0; z<BITS; z++) {
@@ -216,6 +220,9 @@ regopt(Prog *firstp)
* funny
*/
case ALEAL:
+ case AFMOVL:
+ case AFMOVW:
+ case AFMOVV:
setaddrs(bit);
break;
@@ -694,9 +701,9 @@ brk:
if(ostats.ndelmov)
print(" %4d delmov\n", ostats.ndelmov);
if(ostats.nvar)
- print(" %4d delmov\n", ostats.nvar);
+ print(" %4d var\n", ostats.nvar);
if(ostats.naddr)
- print(" %4d delmov\n", ostats.naddr);
+ print(" %4d addr\n", ostats.naddr);
memset(&ostats, 0, sizeof(ostats));
}
@@ -725,19 +732,19 @@ addmove(Reg *r, int bn, int rn, int f)
v = var + bn;
a = &p1->to;
- a->sym = v->sym;
a->offset = v->offset;
a->etype = v->etype;
a->type = v->name;
a->gotype = v->gotype;
a->node = v->node;
+ a->sym = v->node->sym;
// need to clean this up with wptr and
// some of the defaults
p1->as = AMOVL;
switch(v->etype) {
default:
- fatal("unknown type\n");
+ fatal("unknown type %E", v->etype);
case TINT8:
case TUINT8:
case TBOOL:
@@ -810,7 +817,7 @@ mkvar(Reg *r, Adr *a)
int i, t, n, et, z, w, flag, regu;
int32 o;
Bits bit;
- Sym *s;
+ Node *node;
/*
* mark registers used
@@ -847,10 +854,13 @@ mkvar(Reg *r, Adr *a)
break;
}
- s = a->sym;
- if(s == S)
+ node = a->node;
+ if(node == N || node->op != ONAME || node->orig == N)
goto none;
- if(s->name[0] == '.')
+ node = node->orig;
+ if(node->orig != node)
+ fatal("%D: bad node", a);
+ if(node->sym == S || node->sym->name[0] == '.')
goto none;
et = a->etype;
o = a->offset;
@@ -859,7 +869,7 @@ mkvar(Reg *r, Adr *a)
flag = 0;
for(i=0; i<nvar; i++) {
v = var+i;
- if(v->sym == s && v->name == n) {
+ if(v->node == node && v->name == n) {
if(v->offset == o)
if(v->etype == et)
if(v->width == w)
@@ -868,7 +878,7 @@ mkvar(Reg *r, Adr *a)
// if they overlap, disable both
if(overlap(v->offset, v->width, o, w)) {
if(debug['R'])
- print("disable %s\n", v->sym->name);
+ print("disable %s\n", node->sym->name);
v->addr = 1;
flag = 1;
}
@@ -882,7 +892,7 @@ mkvar(Reg *r, Adr *a)
}
if(nvar >= NVAR) {
- if(debug['w'] > 1 && s)
+ if(debug['w'] > 1 && node != N)
fatal("variable not optimized: %D", a);
goto none;
}
@@ -890,17 +900,16 @@ mkvar(Reg *r, Adr *a)
i = nvar;
nvar++;
v = var+i;
- v->sym = s;
v->offset = o;
v->name = n;
v->gotype = a->gotype;
v->etype = et;
v->width = w;
v->addr = flag; // funny punning
- v->node = a->node;
+ v->node = node;
if(debug['R'])
- print("bit=%2d et=%2d w=%d+%d %S %D flag=%d\n", i, et, o, w, s, a, v->addr);
+ print("bit=%2d et=%2d w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
ostats.nvar++;
bit = blsh(i);
@@ -959,6 +968,13 @@ prop(Reg *r, Bits ref, Bits cal)
ref.b[z] = 0;
}
break;
+
+ default:
+ // Work around for issue 1304:
+ // flush modified globals before each instruction.
+ for(z=0; z<BITS; z++)
+ cal.b[z] |= externs.b[z];
+ break;
}
for(z=0; z<BITS; z++) {
ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
@@ -1095,10 +1111,12 @@ loopit(Reg *r, int32 nr)
r1 = rpo2r[i];
me = r1->rpo;
d = -1;
- if(r1->p1 != R && r1->p1->rpo < me)
+ // rpo2r[r->rpo] == r protects against considering dead code,
+ // which has r->rpo == 0.
+ if(r1->p1 != R && rpo2r[r1->p1->rpo] == r1->p1 && r1->p1->rpo < me)
d = r1->p1->rpo;
for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
- if(r1->rpo < me)
+ if(rpo2r[r1->rpo] == r1 && r1->rpo < me)
d = rpolca(idom, d, r1->rpo);
idom[i] = d;
}
@@ -1482,7 +1500,7 @@ dumpone(Reg *r)
if(bany(&r->refahead))
print(" ra:%Q ", r->refahead);
if(bany(&r->calbehind))
- print("cb:%Q ", r->calbehind);
+ print(" cb:%Q ", r->calbehind);
if(bany(&r->calahead))
print(" ca:%Q ", r->calahead);
if(bany(&r->regdiff))
@@ -1542,3 +1560,123 @@ noreturn(Prog *p)
return 1;
return 0;
}
+
+/*
+ * the code generator depends on being able to write out JMP
+ * instructions that it can jump to now but fill in later.
+ * the linker will resolve them nicely, but they make the code
+ * longer and more difficult to follow during debugging.
+ * remove them.
+ */
+
+/* what instruction does a JMP to p eventually land on? */
+static Prog*
+chasejmp(Prog *p, int *jmploop)
+{
+ int n;
+
+ n = 0;
+ while(p != P && p->as == AJMP && p->to.type == D_BRANCH) {
+ if(++n > 10) {
+ *jmploop = 1;
+ break;
+ }
+ p = p->to.branch;
+ }
+ return p;
+}
+
+/*
+ * reuse reg pointer for mark/sweep state.
+ * leave reg==nil at end because alive==nil.
+ */
+#define alive ((void*)0)
+#define dead ((void*)1)
+
+/* mark all code reachable from firstp as alive */
+static void
+mark(Prog *firstp)
+{
+ Prog *p;
+
+ for(p=firstp; p; p=p->link) {
+ if(p->reg != dead)
+ break;
+ p->reg = alive;
+ if(p->as != ACALL && p->to.type == D_BRANCH && p->to.branch)
+ mark(p->to.branch);
+ if(p->as == AJMP || p->as == ARET || (p->as == ACALL && noreturn(p)))
+ break;
+ }
+}
+
+static void
+fixjmp(Prog *firstp)
+{
+ int jmploop;
+ Prog *p, *last;
+
+ if(debug['R'] && debug['v'])
+ print("\nfixjmp\n");
+
+ // pass 1: resolve jump to AJMP, mark all code as dead.
+ jmploop = 0;
+ for(p=firstp; p; p=p->link) {
+ if(debug['R'] && debug['v'])
+ print("%P\n", p);
+ if(p->as != ACALL && p->to.type == D_BRANCH && p->to.branch && p->to.branch->as == AJMP) {
+ p->to.branch = chasejmp(p->to.branch, &jmploop);
+ if(debug['R'] && debug['v'])
+ print("->%P\n", p);
+ }
+ p->reg = dead;
+ }
+ if(debug['R'] && debug['v'])
+ print("\n");
+
+ // pass 2: mark all reachable code alive
+ mark(firstp);
+
+ // pass 3: delete dead code (mostly JMPs).
+ last = nil;
+ for(p=firstp; p; p=p->link) {
+ if(p->reg == dead) {
+ if(p->link == P && p->as == ARET && last && last->as != ARET) {
+ // This is the final ARET, and the code so far doesn't have one.
+ // Let it stay.
+ } else {
+ if(debug['R'] && debug['v'])
+ print("del %P\n", p);
+ continue;
+ }
+ }
+ if(last)
+ last->link = p;
+ last = p;
+ }
+ last->link = P;
+
+ // pass 4: elide JMP to next instruction.
+ // only safe if there are no jumps to JMPs anymore.
+ if(!jmploop) {
+ last = nil;
+ for(p=firstp; p; p=p->link) {
+ if(p->as == AJMP && p->to.type == D_BRANCH && p->to.branch == p->link) {
+ if(debug['R'] && debug['v'])
+ print("del %P\n", p);
+ continue;
+ }
+ if(last)
+ last->link = p;
+ last = p;
+ }
+ last->link = P;
+ }
+
+ if(debug['R'] && debug['v']) {
+ print("\n");
+ for(p=firstp; p; p=p->link)
+ print("%P\n", p);
+ print("\n");
+ }
+}