summaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/5a/lex.c2
-rw-r--r--src/cmd/5c/gc.h4
-rw-r--r--src/cmd/5g/Makefile13
-rw-r--r--src/cmd/5g/cgen.c217
-rw-r--r--src/cmd/5g/gg.h5
-rw-r--r--src/cmd/5g/ggen.c110
-rw-r--r--src/cmd/5g/gsubr.c3
-rw-r--r--src/cmd/5g/reg.c184
-rw-r--r--src/cmd/5l/5.out.h4
-rw-r--r--src/cmd/5l/Makefile1
-rw-r--r--src/cmd/5l/asm.c311
-rw-r--r--src/cmd/5l/l.h25
-rw-r--r--src/cmd/5l/list.c7
-rw-r--r--src/cmd/5l/noop.c385
-rw-r--r--src/cmd/5l/obj.c33
-rw-r--r--src/cmd/5l/optab.c82
-rw-r--r--src/cmd/5l/pass.c20
-rw-r--r--src/cmd/5l/prof.c9
-rw-r--r--src/cmd/5l/softfloat.c2
-rw-r--r--src/cmd/5l/span.c236
-rw-r--r--src/cmd/5l/thumb.c1658
-rw-r--r--src/cmd/6g/Makefile11
-rw-r--r--src/cmd/6g/cgen.c38
-rw-r--r--src/cmd/6g/gg.h1
-rw-r--r--src/cmd/6g/ggen.c145
-rw-r--r--src/cmd/6g/gsubr.c45
-rw-r--r--src/cmd/6g/reg.c160
-rw-r--r--src/cmd/6l/asm.c62
-rw-r--r--src/cmd/6l/l.h3
-rw-r--r--src/cmd/6l/obj.c2
-rw-r--r--src/cmd/8g/Makefile11
-rw-r--r--src/cmd/8g/cgen.c40
-rw-r--r--src/cmd/8g/gg.h1
-rw-r--r--src/cmd/8g/ggen.c140
-rw-r--r--src/cmd/8g/gsubr.c71
-rw-r--r--src/cmd/8g/reg.c111
-rw-r--r--src/cmd/8l/asm.c69
-rw-r--r--src/cmd/8l/l.h11
-rw-r--r--src/cmd/8l/obj.c4
-rw-r--r--src/cmd/8l/pass.c15
-rw-r--r--src/cmd/cgo/doc.go14
-rw-r--r--src/cmd/cgo/gcc.go122
-rw-r--r--src/cmd/cgo/out.go14
-rw-r--r--src/cmd/gc/Makefile2
-rw-r--r--src/cmd/gc/align.c12
-rw-r--r--src/cmd/gc/builtin.c.boot4
-rw-r--r--src/cmd/gc/closure.c44
-rw-r--r--src/cmd/gc/const.c4
-rw-r--r--src/cmd/gc/dcl.c42
-rw-r--r--src/cmd/gc/gen.c22
-rw-r--r--src/cmd/gc/go.h29
-rw-r--r--src/cmd/gc/go.y20
-rw-r--r--src/cmd/gc/init.c5
-rw-r--r--src/cmd/gc/lex.c22
-rw-r--r--src/cmd/gc/obj.c1
-rw-r--r--src/cmd/gc/pgen.c224
-rw-r--r--src/cmd/gc/print.c4
-rw-r--r--src/cmd/gc/runtime.go1
-rw-r--r--src/cmd/gc/sinit.c4
-rw-r--r--src/cmd/gc/subr.c107
-rw-r--r--src/cmd/gc/swt.c5
-rw-r--r--src/cmd/gc/typecheck.c376
-rw-r--r--src/cmd/gc/unsafe.c1
-rw-r--r--src/cmd/gc/walk.c456
-rw-r--r--src/cmd/godefs/a.h1
-rw-r--r--src/cmd/godefs/main.c14
-rw-r--r--src/cmd/godefs/stabs.c10
-rw-r--r--src/cmd/godoc/doc.go3
-rw-r--r--src/cmd/godoc/godoc.go35
-rw-r--r--src/cmd/godoc/main.go15
-rw-r--r--src/cmd/godoc/spec.go12
-rw-r--r--src/cmd/gofix/Makefile2
-rw-r--r--src/cmd/gofix/fix.go159
-rw-r--r--src/cmd/gofix/httpfinalurl.go56
-rw-r--r--src/cmd/gofix/httpfinalurl_test.go37
-rw-r--r--src/cmd/gofix/main.go18
-rw-r--r--src/cmd/gofix/signal.go49
-rw-r--r--src/cmd/gofix/signal_test.go96
-rw-r--r--src/cmd/gofmt/gofmt.go21
-rwxr-xr-xsrc/cmd/gofmt/test.sh5
-rw-r--r--src/cmd/goinstall/doc.go55
-rw-r--r--src/cmd/goinstall/download.go29
-rw-r--r--src/cmd/goinstall/main.go134
-rw-r--r--src/cmd/goinstall/make.go32
-rw-r--r--src/cmd/goinstall/path.go44
-rw-r--r--src/cmd/gopack/ar.c20
-rw-r--r--src/cmd/gotest/gotest.go7
-rw-r--r--src/cmd/gotype/gotype.go6
-rw-r--r--src/cmd/hgpatch/main.go41
-rw-r--r--src/cmd/ld/data.c12
-rw-r--r--src/cmd/ld/dwarf.c112
-rw-r--r--src/cmd/ld/elf.h4
-rw-r--r--src/cmd/ld/go.c6
-rw-r--r--src/cmd/ld/ldpe.c5
-rw-r--r--src/cmd/ld/lib.c43
-rw-r--r--src/cmd/ld/lib.h4
-rw-r--r--src/cmd/ld/macho.c23
-rw-r--r--src/cmd/ld/macho.h2
-rw-r--r--src/cmd/ld/pe.c54
-rw-r--r--src/cmd/ld/pe.h2
-rw-r--r--src/cmd/ld/symtab.c78
-rwxr-xr-xsrc/cmd/prof/gopprof287
102 files changed, 3177 insertions, 4142 deletions
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
index a04cda220..3978f1a6c 100644
--- a/src/cmd/5a/lex.c
+++ b/src/cmd/5a/lex.c
@@ -338,6 +338,8 @@ struct
"NRMD", LTYPEI, ANRMD,
*/
+ "SQRTF", LTYPEI, ASQRTF,
+ "SQRTD", LTYPEI, ASQRTD,
"CMPF", LTYPEL, ACMPF,
"CMPD", LTYPEL, ACMPD,
"ADDF", LTYPEK, AADDF,
diff --git a/src/cmd/5c/gc.h b/src/cmd/5c/gc.h
index 9e9d1bd7d..549e0c88a 100644
--- a/src/cmd/5c/gc.h
+++ b/src/cmd/5c/gc.h
@@ -69,7 +69,7 @@ struct Adr
Sym* sym;
char type;
- char reg;
+ uchar reg;
char name;
char etype;
};
@@ -83,7 +83,7 @@ struct Prog
Prog* link;
int32 lineno;
char as;
- char reg;
+ uchar reg;
uchar scond;
};
#define P ((Prog*)0)
diff --git a/src/cmd/5g/Makefile b/src/cmd/5g/Makefile
index 6873fbc68..b47014a4e 100644
--- a/src/cmd/5g/Makefile
+++ b/src/cmd/5g/Makefile
@@ -15,16 +15,17 @@ HFILES=\
OFILES=\
../5l/enam.$O\
- list.$O\
- galign.$O\
- gobj.$O\
- ggen.$O\
- gsubr.$O\
cgen.$O\
cgen64.$O\
cplx.$O\
- reg.$O\
+ galign.$O\
+ ggen.$O\
+ gobj.$O\
+ gsubr.$O\
+ list.$O\
peep.$O\
+ pgen.$O\
+ reg.$O\
LIB=\
../gc/gc.a\
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
index 4e5f7ebcd..76e2707fa 100644
--- a/src/cmd/5g/cgen.c
+++ b/src/cmd/5g/cgen.c
@@ -1190,7 +1190,8 @@ void
sgen(Node *n, Node *res, int32 w)
{
Node dst, src, tmp, nend;
- int32 c, q, odst, osrc;
+ int32 c, odst, osrc;
+ int dir, align, op;
Prog *p, *ploop;
if(debug['g']) {
@@ -1200,17 +1201,39 @@ sgen(Node *n, Node *res, int32 w)
}
if(w == 0)
return;
- if(n->ullman >= UINF && res->ullman >= UINF) {
- fatal("sgen UINF");
- }
-
if(w < 0)
fatal("sgen copy %d", w);
+ if(n->ullman >= UINF && res->ullman >= UINF)
+ fatal("sgen UINF");
+ if(n->type == T)
+ fatal("sgen: missing type");
+
+ // determine alignment.
+ // want to avoid unaligned access, so have to use
+ // smaller operations for less aligned types.
+ // for example moving [4]byte must use 4 MOVB not 1 MOVW.
+ align = n->type->align;
+ op = 0;
+ switch(align) {
+ default:
+ fatal("sgen: invalid alignment %d for %T", align, n->type);
+ case 1:
+ op = AMOVB;
+ break;
+ case 2:
+ op = AMOVH;
+ break;
+ case 4:
+ op = AMOVW;
+ break;
+ }
+ if(w%align)
+ fatal("sgen: unaligned size %d (align=%d) for %T", w, align, n->type);
+ c = w / align;
// offset on the stack
osrc = stkof(n);
odst = stkof(res);
-
if(osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000)) {
// osrc and odst both on stack, and at least one is in
// an unknown position. Could generate code to test
@@ -1221,12 +1244,15 @@ sgen(Node *n, Node *res, int32 w)
sgen(&tmp, res, w);
return;
}
-
- if(osrc % 4 != 0 || odst %4 != 0)
- fatal("sgen: non word(4) aligned offset src %d or dst %d", osrc, odst);
+ if(osrc%align != 0 || odst%align != 0)
+ fatal("sgen: unaligned offset src %d or dst %d (align %d)", osrc, odst, align);
+ // if we are copying forward on the stack and
+ // the src and dst overlap, then reverse direction
+ dir = align;
+ if(osrc < odst && odst < osrc+w)
+ dir = -dir;
regalloc(&dst, types[tptr], res);
-
if(n->ullman >= res->ullman) {
agen(n, &dst); // temporarily use dst
regalloc(&src, types[tptr], N);
@@ -1240,141 +1266,64 @@ sgen(Node *n, Node *res, int32 w)
regalloc(&tmp, types[TUINT32], N);
- c = w % 4; // bytes
- q = w / 4; // quads
-
- // if we are copying forward on the stack and
- // the src and dst overlap, then reverse direction
- if(osrc < odst && odst < osrc+w) {
- if(c != 0)
- fatal("sgen: reverse character copy not implemented");
- if(q >= 4) {
- regalloc(&nend, types[TUINT32], N);
- // set up end marker to 4 bytes before source
- p = gins(AMOVW, &src, &nend);
- p->from.type = D_CONST;
- p->from.offset = -4;
-
- // move src and dest to the end of block
- p = gins(AMOVW, &src, &src);
- p->from.type = D_CONST;
- p->from.offset = (q-1)*4;
-
- p = gins(AMOVW, &dst, &dst);
- p->from.type = D_CONST;
- p->from.offset = (q-1)*4;
-
- p = gins(AMOVW, &src, &tmp);
- p->from.type = D_OREG;
- p->from.offset = -4;
- p->scond |= C_PBIT;
- ploop = p;
+ // set up end marker
+ memset(&nend, 0, sizeof nend);
+ if(c >= 4) {
+ regalloc(&nend, types[TUINT32], N);
- p = gins(AMOVW, &tmp, &dst);
- p->to.type = D_OREG;
- p->to.offset = -4;
- p->scond |= C_PBIT;
-
- p = gins(ACMP, &src, N);
- raddr(&nend, p);
+ p = gins(AMOVW, &src, &nend);
+ p->from.type = D_CONST;
+ if(dir < 0)
+ p->from.offset = dir;
+ else
+ p->from.offset = w;
+ }
- patch(gbranch(ABNE, T), ploop);
+ // move src and dest to the end of block if necessary
+ if(dir < 0) {
+ p = gins(AMOVW, &src, &src);
+ p->from.type = D_CONST;
+ p->from.offset = w + dir;
- regfree(&nend);
- } else {
- // move src and dest to the end of block
- p = gins(AMOVW, &src, &src);
- p->from.type = D_CONST;
- p->from.offset = (q-1)*4;
-
- p = gins(AMOVW, &dst, &dst);
- p->from.type = D_CONST;
- p->from.offset = (q-1)*4;
-
- while(q > 0) {
- p = gins(AMOVW, &src, &tmp);
- p->from.type = D_OREG;
- p->from.offset = -4;
- p->scond |= C_PBIT;
-
- p = gins(AMOVW, &tmp, &dst);
- p->to.type = D_OREG;
- p->to.offset = -4;
- p->scond |= C_PBIT;
-
- q--;
- }
- }
+ p = gins(AMOVW, &dst, &dst);
+ p->from.type = D_CONST;
+ p->from.offset = w + dir;
+ }
+
+ // move
+ if(c >= 4) {
+ p = gins(op, &src, &tmp);
+ p->from.type = D_OREG;
+ p->from.offset = dir;
+ p->scond |= C_PBIT;
+ ploop = p;
+
+ p = gins(op, &tmp, &dst);
+ p->to.type = D_OREG;
+ p->to.offset = dir;
+ p->scond |= C_PBIT;
+
+ p = gins(ACMP, &src, N);
+ raddr(&nend, p);
+
+ patch(gbranch(ABNE, T), ploop);
+ regfree(&nend);
} else {
- // normal direction
- if(q >= 4) {
- regalloc(&nend, types[TUINT32], N);
- p = gins(AMOVW, &src, &nend);
- p->from.type = D_CONST;
- p->from.offset = q*4;
-
- p = gins(AMOVW, &src, &tmp);
+ while(c-- > 0) {
+ p = gins(op, &src, &tmp);
p->from.type = D_OREG;
- p->from.offset = 4;
+ p->from.offset = dir;
p->scond |= C_PBIT;
ploop = p;
-
- p = gins(AMOVW, &tmp, &dst);
+
+ p = gins(op, &tmp, &dst);
p->to.type = D_OREG;
- p->to.offset = 4;
+ p->to.offset = dir;
p->scond |= C_PBIT;
-
- p = gins(ACMP, &src, N);
- raddr(&nend, p);
-
- patch(gbranch(ABNE, T), ploop);
-
- regfree(&nend);
- } else
- while(q > 0) {
- p = gins(AMOVW, &src, &tmp);
- p->from.type = D_OREG;
- p->from.offset = 4;
- p->scond |= C_PBIT;
-
- p = gins(AMOVW, &tmp, &dst);
- p->to.type = D_OREG;
- p->to.offset = 4;
- p->scond |= C_PBIT;
-
- q--;
- }
-
- if (c != 0) {
- // MOVW (src), tmp
- p = gins(AMOVW, &src, &tmp);
- p->from.type = D_OREG;
-
- // MOVW tmp<<((4-c)*8),src
- gshift(AMOVW, &tmp, SHIFT_LL, ((4-c)*8), &src);
-
- // MOVW src>>((4-c)*8),src
- gshift(AMOVW, &src, SHIFT_LR, ((4-c)*8), &src);
-
- // MOVW (dst), tmp
- p = gins(AMOVW, &dst, &tmp);
- p->from.type = D_OREG;
-
- // MOVW tmp>>(c*8),tmp
- gshift(AMOVW, &tmp, SHIFT_LR, (c*8), &tmp);
-
- // MOVW tmp<<(c*8),tmp
- gshift(AMOVW, &tmp, SHIFT_LL, c*8, &tmp);
-
- // ORR src, tmp
- gins(AORR, &src, &tmp);
-
- // MOVW tmp, (dst)
- p = gins(AMOVW, &tmp, &dst);
- p->to.type = D_OREG;
}
}
- regfree(&dst);
+
+ regfree(&dst);
regfree(&src);
regfree(&tmp);
}
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
index 78e6833b2..ce4558e21 100644
--- a/src/cmd/5g/gg.h
+++ b/src/cmd/5g/gg.h
@@ -23,10 +23,11 @@ struct Addr
char sval[NSNAME];
Sym* sym;
+ Node* node;
int width;
uchar type;
char name;
- char reg;
+ uchar reg;
char pun;
uchar etype;
};
@@ -41,7 +42,7 @@ struct Prog
Addr to; // dst address
Prog* link; // next instruction in this func
void* regp; // points to enclosing Reg struct
- char reg; // doubles as width in DATA op
+ uchar reg; // doubles as width in DATA op
uchar scond;
};
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
index 7197709d4..0bc1b38fc 100644
--- a/src/cmd/5g/ggen.c
+++ b/src/cmd/5g/ggen.c
@@ -7,107 +7,9 @@
#include "gg.h"
#include "opt.h"
-static Prog *pret;
-
void
-compile(Node *fn)
+defframe(Prog *ptxt)
{
- Plist *pl;
- Node nod1;
- Prog *ptxt;
- int32 lno;
- Type *t;
- Iter save;
-
- if(newproc == N) {
- newproc = sysfunc("newproc");
- deferproc = sysfunc("deferproc");
- deferreturn = sysfunc("deferreturn");
- panicindex = sysfunc("panicindex");
- panicslice = sysfunc("panicslice");
- throwreturn = sysfunc("throwreturn");
- }
-
- if(fn->nbody == nil)
- return;
-
- // set up domain for labels
- clearlabels();
-
- lno = setlineno(fn);
-
- curfn = fn;
- dowidth(curfn->type);
-
- if(curfn->type->outnamed) {
- // add clearing of the output parameters
- t = structfirst(&save, getoutarg(curfn->type));
- while(t != T) {
- if(t->nname != N)
- curfn->nbody = concat(list1(nod(OAS, t->nname, N)), curfn->nbody);
- t = structnext(&save);
- }
- }
-
- hasdefer = 0;
- walk(curfn);
- if(nerrors != 0 || isblank(curfn->nname))
- goto ret;
-
- allocparams();
-
- continpc = P;
- breakpc = P;
-
- pl = newplist();
- pl->name = curfn->nname;
-
- setlineno(curfn);
-
- nodconst(&nod1, types[TINT32], 0);
- ptxt = gins(ATEXT, curfn->nname, &nod1);
- afunclit(&ptxt->from);
-
- ginit();
- genlist(curfn->enter);
-
- pret = nil;
- if(hasdefer || curfn->exit) {
- Prog *p1;
-
- p1 = gjmp(nil);
- pret = gjmp(nil);
- patch(p1, pc);
- }
-
- genlist(curfn->nbody);
- gclean();
- checklabels();
- if(nerrors != 0)
- goto ret;
-
- if(curfn->type->outtuple != 0)
- ginscall(throwreturn, 0);
-
- if(pret)
- patch(pret, pc);
- ginit();
- if(hasdefer)
- ginscall(deferreturn, 0);
- if(curfn->exit)
- genlist(curfn->exit);
- gclean();
- if(nerrors != 0)
- goto ret;
- if(curfn->endlineno)
- lineno = curfn->endlineno;
- pc->as = ARET; // overwrite AEND
- pc->lineno = lineno;
-
- if(!debug['N'] || debug['R'] || debug['P']) {
- regopt(ptxt);
- }
-
// fill in argument size
ptxt->to.type = D_CONST2;
ptxt->reg = 0; // flags
@@ -118,12 +20,6 @@ compile(Node *fn)
maxstksize = stksize;
ptxt->to.offset = rnd(maxstksize+maxarg, widthptr);
maxstksize = 0;
-
- if(debug['f'])
- frame(0);
-
-ret:
- lineno = lno;
}
/*
@@ -197,7 +93,7 @@ ginscall(Node *f, int proc)
nodconst(&con, types[TINT32], 0);
p = gins(ACMP, &con, N);
p->reg = 0;
- patch(gbranch(ABNE, T), pret);
+ patch(gbranch(ABNE, T), retpc);
}
break;
}
@@ -401,7 +297,7 @@ cgen_ret(Node *n)
{
genlist(n->list); // copy out args
if(hasdefer || curfn->exit)
- gjmp(pret);
+ gjmp(retpc);
else
gins(ARET, N, N);
}
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
index 57cb56a64..caaa3e246 100644
--- a/src/cmd/5g/gsubr.c
+++ b/src/cmd/5g/gsubr.c
@@ -1159,6 +1159,7 @@ naddr(Node *n, Addr *a, int canemitcode)
a->type = D_NONE;
a->name = D_NONE;
a->reg = NREG;
+ a->node = N;
if(n == N)
return;
@@ -1247,6 +1248,8 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case PAUTO:
a->name = D_AUTO;
+ if (n->sym)
+ a->node = n->orig;
break;
case PPARAM:
case PPARAMOUT:
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
index 1cbeb3e3d..5fba02c9e 100644
--- a/src/cmd/5g/reg.c
+++ b/src/cmd/5g/reg.c
@@ -32,6 +32,8 @@
#include "gg.h"
#include "opt.h"
+#define NREGVAR 24
+#define REGBITS ((uint32)0xffffff)
#define P2R(p) (Reg*)(p->reg)
void addsplits(void);
@@ -128,6 +130,33 @@ setaddrs(Bits bit)
}
}
+static char* regname[] = {
+ ".R0",
+ ".R1",
+ ".R2",
+ ".R3",
+ ".R4",
+ ".R5",
+ ".R6",
+ ".R7",
+ ".R8",
+ ".R9",
+ ".R10",
+ ".R11",
+ ".R12",
+ ".R13",
+ ".R14",
+ ".R15",
+ ".F0",
+ ".F1",
+ ".F2",
+ ".F3",
+ ".F4",
+ ".F5",
+ ".F6",
+ ".F7",
+};
+
void
regopt(Prog *firstp)
{
@@ -136,7 +165,7 @@ regopt(Prog *firstp)
int i, z, nr;
uint32 vreg;
Bits bit;
-
+
if(first == 0) {
fmtinstall('Q', Qconv);
}
@@ -164,7 +193,17 @@ regopt(Prog *firstp)
r1 = R;
firstr = R;
lastr = R;
- nvar = 0;
+
+ /*
+ * control flow is more complicated in generated go code
+ * than in generated c code. define pseudo-variables for
+ * registers, so we have complete register usage information.
+ */
+ nvar = NREGVAR;
+ memset(var, 0, NREGVAR*sizeof var[0]);
+ for(i=0; i<NREGVAR; i++)
+ var[i].sym = lookup(regname[i]);
+
regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC);
for(z=0; z<BITS; z++) {
externs.b[z] = 0;
@@ -223,6 +262,16 @@ regopt(Prog *firstp)
bit = mkvar(r, &p->from);
for(z=0; z<BITS; z++)
r->use1.b[z] |= bit.b[z];
+
+ /*
+ * middle always read when present
+ */
+ if(p->reg != NREG) {
+ if(p->from.type != D_FREG)
+ r->use1.b[0] |= RtoB(p->reg);
+ else
+ r->use1.b[0] |= FtoB(p->reg);
+ }
/*
* right side depends on opcode
@@ -233,6 +282,67 @@ regopt(Prog *firstp)
default:
yyerror("reg: unknown op: %A", p->as);
break;
+
+ /*
+ * right side read
+ */
+ case ATST:
+ case ATEQ:
+ case ACMP:
+ case ACMN:
+ case ACMPD:
+ case ACMPF:
+ rightread:
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
+ break;
+
+ /*
+ * right side read or read+write, depending on middle
+ * ADD x, z => z += x
+ * ADD x, y, z => z = x + y
+ */
+ case AADD:
+ case AAND:
+ case AEOR:
+ case ASUB:
+ case ARSB:
+ case AADC:
+ case ASBC:
+ case ARSC:
+ case AORR:
+ case ABIC:
+ case ASLL:
+ case ASRL:
+ case ASRA:
+ case AMUL:
+ case AMULU:
+ case ADIV:
+ case AMOD:
+ case AMODU:
+ case ADIVU:
+ if(p->reg != NREG)
+ goto rightread;
+ // fall through
+
+ /*
+ * right side read+write
+ */
+ case AADDF:
+ case AADDD:
+ case ASUBF:
+ case ASUBD:
+ case AMULF:
+ case AMULD:
+ case ADIVF:
+ case ADIVD:
+ case AMULAL:
+ case AMULALU:
+ for(z=0; z<BITS; z++) {
+ r->use2.b[z] |= bit.b[z];
+ r->set.b[z] |= bit.b[z];
+ }
+ break;
/*
* right side write
@@ -240,11 +350,22 @@ regopt(Prog *firstp)
case ANOP:
case AMOVB:
case AMOVBU:
+ case AMOVD:
+ case AMOVDF:
+ case AMOVDW:
+ case AMOVF:
+ case AMOVFW:
case AMOVH:
case AMOVHU:
case AMOVW:
- case AMOVF:
- case AMOVD:
+ case AMOVWD:
+ case AMOVWF:
+ case AMVN:
+ case AMULL:
+ case AMULLU:
+ if((p->scond & C_SCOND) != C_SCOND_NONE)
+ for(z=0; z<BITS; z++)
+ r->use2.b[z] |= bit.b[z];
for(z=0; z<BITS; z++)
r->set.b[z] |= bit.b[z];
break;
@@ -397,6 +518,24 @@ loop2:
}
/*
+ * pass 4.5
+ * move register pseudo-variables into regu.
+ */
+ for(r = firstr; r != R; r = r->link) {
+ r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
+
+ r->set.b[0] &= ~REGBITS;
+ r->use1.b[0] &= ~REGBITS;
+ r->use2.b[0] &= ~REGBITS;
+ r->refbehind.b[0] &= ~REGBITS;
+ r->refahead.b[0] &= ~REGBITS;
+ r->calbehind.b[0] &= ~REGBITS;
+ r->calahead.b[0] &= ~REGBITS;
+ r->regdiff.b[0] &= ~REGBITS;
+ r->act.b[0] &= ~REGBITS;
+ }
+
+ /*
* pass 5
* isolate regions
* calculate costs (paint1)
@@ -606,6 +745,7 @@ addmove(Reg *r, int bn, int rn, int f)
a = &p1->to;
a->sym = v->sym;
a->name = v->name;
+ a->node = v->node;
a->offset = v->offset;
a->etype = v->etype;
a->type = D_OREG;
@@ -715,21 +855,40 @@ mkvar(Reg *r, Adr *a)
goto onereg;
case D_REGREG:
+ bit = zbits;
if(a->offset != NREG)
- r->regu |= RtoB(a->offset);
- goto onereg;
+ bit.b[0] |= RtoB(a->offset);
+ if(a->reg != NREG)
+ bit.b[0] |= RtoB(a->reg);
+ return bit;
case D_REG:
case D_SHIFT:
- case D_OREG:
onereg:
- if(a->reg != NREG)
- r->regu |= RtoB(a->reg);
+ if(a->reg != NREG) {
+ bit = zbits;
+ bit.b[0] = RtoB(a->reg);
+ return bit;
+ }
+ break;
+
+ case D_OREG:
+ if(a->reg != NREG) {
+ if(a == &r->prog->from)
+ r->use1.b[0] |= RtoB(a->reg);
+ else
+ r->use2.b[0] |= RtoB(a->reg);
+ if(r->prog->scond & (C_PBIT|C_WBIT))
+ r->set.b[0] |= RtoB(a->reg);
+ }
break;
case D_FREG:
- if(a->reg != NREG)
- r->regu |= FtoB(a->reg);
+ if(a->reg != NREG) {
+ bit = zbits;
+ bit.b[0] = FtoB(a->reg);
+ return bit;
+ }
break;
}
@@ -795,7 +954,8 @@ mkvar(Reg *r, Adr *a)
v->etype = et;
v->width = w;
v->addr = flag; // funny punning
-
+ v->node = a->node;
+
if(debug['R'])
print("bit=%2d et=%E pun=%d %D\n", i, et, flag, a);
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
index 002b46d45..cf86ae48b 100644
--- a/src/cmd/5l/5.out.h
+++ b/src/cmd/5l/5.out.h
@@ -53,8 +53,6 @@
#define REGLINK 14
#define REGPC 15
-#define REGTMPT 7 /* used by the loader for thumb code */
-
#define NFREG 8
#define FREGRET 0
#define FREGEXT 7
@@ -126,6 +124,8 @@ enum as
AMULD,
ADIVF,
ADIVD,
+ ASQRTF,
+ ASQRTD,
ASRL,
ASRA,
diff --git a/src/cmd/5l/Makefile b/src/cmd/5l/Makefile
index c11ebe990..9f4a192aa 100644
--- a/src/cmd/5l/Makefile
+++ b/src/cmd/5l/Makefile
@@ -22,7 +22,6 @@ OFILES=\
optab.$O\
pass.$O\
prof.$O\
- thumb.$O\
softfloat.$O\
span.$O\
symtab.$O\
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
index e2583e7c3..4afed2b80 100644
--- a/src/cmd/5l/asm.c
+++ b/src/cmd/5l/asm.c
@@ -34,8 +34,6 @@
#include "../ld/lib.h"
#include "../ld/elf.h"
-int32 OFFSET;
-
static Prog *PP;
char linuxdynld[] = "/lib/ld-linux.so.2";
@@ -73,6 +71,8 @@ enum {
ElfStrGosymcounts,
ElfStrGosymtab,
ElfStrGopclntab,
+ ElfStrSymtab,
+ ElfStrStrtab,
ElfStrShstrtab,
ElfStrRelPlt,
ElfStrPlt,
@@ -87,6 +87,9 @@ needlib(char *name)
char *p;
Sym *s;
+ if(*name == '\0')
+ return 0;
+
/* reuse hash code in symbol table */
p = smprint(".dynlib.%s", name);
s = lookup(p, 0);
@@ -163,6 +166,8 @@ doelf(void)
elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts");
elfstr[ElfStrGosymtab] = addstring(shstrtab, ".gosymtab");
elfstr[ElfStrGopclntab] = addstring(shstrtab, ".gopclntab");
+ elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
+ elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
}
elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
@@ -288,15 +293,12 @@ asmb(void)
{
int32 t;
int a, dynsym;
- uint32 va, fo, w, startva;
- int strtabsize;
+ uint32 fo, symo, startva;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
Section *sect;
- strtabsize = 0;
-
if(debug['v'])
Bprint(&bso, "%5.2f asmb\n", cputime());
Bflush(&bso);
@@ -322,15 +324,30 @@ asmb(void)
seek(cout, sect->vaddr - segtext.vaddr + segtext.fileoff, 0);
datblk(sect->vaddr, sect->len);
+ if(iself) {
+ /* index of elf text section; needed by asmelfsym, double-checked below */
+ /* !debug['d'] causes extra sections before the .text section */
+ elftextsh = 1;
+ if(!debug['d']) {
+ elftextsh += 10;
+ if(elfverneed)
+ elftextsh += 2;
+ }
+ }
+
/* output symbol table */
symsize = 0;
lcsize = 0;
+ symo = 0;
if(!debug['s']) {
// TODO: rationalize
if(debug['v'])
Bprint(&bso, "%5.2f sym\n", cputime());
Bflush(&bso);
switch(HEADTYPE) {
+ default:
+ if(iself)
+ goto ElfSym;
case Hnoheader:
case Hrisc:
case Hixp1200:
@@ -338,29 +355,37 @@ asmb(void)
debug['s'] = 1;
break;
case Hplan9x32:
- OFFSET = HEADR+textsize+segdata.filelen;
- seek(cout, OFFSET, 0);
+ symo = HEADR+segtext.len+segdata.filelen;
break;
case Hnetbsd:
- OFFSET += rnd(segdata.filelen, 4096);
- seek(cout, OFFSET, 0);
+ symo = rnd(segdata.filelen, 4096);
break;
- case Hlinux:
- OFFSET += segdata.filelen;
- seek(cout, rnd(OFFSET, INITRND), 0);
+ ElfSym:
+ symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
+ symo = rnd(symo, INITRND);
break;
}
- if(!debug['s'])
- asmthumbmap();
+ seek(cout, symo, 0);
+ if(iself) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f elfsym\n", cputime());
+ asmelfsym();
+ cflush();
+ ewrite(cout, elfstrdat, elfstrsize);
+
+ // if(debug['v'])
+ // Bprint(&bso, "%5.2f dwarf\n", cputime());
+ // dwarfemitdebugsections();
+ }
cflush();
+
}
cursym = nil;
if(debug['v'])
Bprint(&bso, "%5.2f header\n", cputime());
Bflush(&bso);
- OFFSET = 0;
- seek(cout, OFFSET, 0);
+ seek(cout, 0L, 0);
switch(HEADTYPE) {
case Hnoheader: /* no header */
break;
@@ -426,9 +451,7 @@ asmb(void)
/* elf arm */
eh = getElfEhdr();
fo = HEADR;
- va = INITTEXT;
startva = INITTEXT - fo; /* va of byte 0 of file */
- w = textsize;
/* This null SHdr must appear before all others */
sh = newElfShdr(elfstr[ElfStrEmpty]);
@@ -541,6 +564,8 @@ asmb(void)
ph->flags = PF_W+PF_R;
ph->align = 4;
+ if(elftextsh != eh->shnum)
+ diag("elftextsh = %d, want %d", elftextsh, eh->shnum);
for(sect=segtext.sect; sect!=nil; sect=sect->next)
elfshbits(sect);
for(sect=segdata.sect; sect!=nil; sect=sect->next)
@@ -558,6 +583,22 @@ asmb(void)
sh->flags = SHF_ALLOC;
sh->addralign = 1;
shsym(sh, lookup("pclntab", 0));
+
+ sh = newElfShdr(elfstr[ElfStrSymtab]);
+ sh->type = SHT_SYMTAB;
+ sh->off = symo;
+ sh->size = symsize;
+ sh->addralign = 4;
+ sh->entsize = 16;
+ sh->link = eh->shnum; // link to strtab
+
+ sh = newElfShdr(elfstr[ElfStrStrtab]);
+ sh->type = SHT_STRTAB;
+ sh->off = symo+symsize;
+ sh->size = elfstrsize;
+ sh->addralign = 1;
+
+ // dwarfaddelfheaders();
}
sh = newElfShstrtab(elfstr[ElfStrShstrtab]);
@@ -686,59 +727,6 @@ nopstat(char *f, Count *c)
(double)(c->outof - c->count)/c->outof);
}
-static void
-outt(int32 f, int32 l)
-{
- if(debug['L'])
- Bprint(&bso, "tmap: %ux-%ux\n", f, l);
- lput(f);
- lput(l);
-}
-
-void
-asmthumbmap(void)
-{
- int32 pc, lastt;
- Prog *p;
-
- if(!seenthumb)
- return;
- pc = 0;
- lastt = -1;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- p = cursym->text;
- pc = p->pc - INITTEXT;
- setarch(p);
- if(thumb){
- if(p->from.sym->foreign){ // 8 bytes of ARM first
- if(lastt >= 0){
- outt(lastt, pc-1);
- lastt = -1;
- }
- pc += 8;
- }
- if(lastt < 0)
- lastt = pc;
- }
- else{
- if(p->from.sym->foreign){ // 4 bytes of THUMB first
- if(lastt < 0)
- lastt = pc;
- pc += 4;
- }
- if(lastt >= 0){
- outt(lastt, pc-1);
- lastt = -1;
- }
- }
- if(cursym->next == nil)
- for(; p != P; p = p->link)
- pc = p->pc = INITTEXT;
- }
- if(lastt >= 0)
- outt(lastt, pc+1);
-}
-
void
asmout(Prog *p, Optab *o, int32 *out)
{
@@ -762,7 +750,7 @@ if(debug['P']) print("%ux: %P type %d\n", (uint32)(p->pc), p, o->type);
break;
case 0: /* pseudo ops */
-if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->thumb, p->from.sym->foreign, p->from.sym->fnptr);
+if(debug['G']) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr);
break;
case 1: /* op R,[R],R */
@@ -826,10 +814,6 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
v = -8;
if(p->cond != P)
v = (p->cond->pc - pc) - 8;
-#ifdef CALLEEBX
- if(p->as == ABL)
- v += fninc(p->to.sym);
-#endif
o1 = opbra(p->as, p->scond);
o1 |= (v >> 2) & 0xffffff;
break;
@@ -990,40 +974,6 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
o1 |= 1<<22;
break;
- case 22: /* movb/movh/movhu O(R),R -> lr,shl,shr */
- aclass(&p->from);
- r = p->from.reg;
- if(r == NREG)
- r = o->param;
- o1 = olr(instoffset, r, p->to.reg, p->scond);
-
- o2 = oprrr(ASLL, p->scond);
- o3 = oprrr(ASRA, p->scond);
- r = p->to.reg;
- if(p->as == AMOVB) {
- o2 |= (24<<7)|(r)|(r<<12);
- o3 |= (24<<7)|(r)|(r<<12);
- } else {
- o2 |= (16<<7)|(r)|(r<<12);
- if(p->as == AMOVHU)
- o3 = oprrr(ASRL, p->scond);
- o3 |= (16<<7)|(r)|(r<<12);
- }
- break;
-
- case 23: /* movh/movhu R,O(R) -> sb,sb */
- aclass(&p->to);
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o1 = osr(AMOVH, p->from.reg, instoffset, r, p->scond);
-
- o2 = oprrr(ASRL, p->scond);
- o2 |= (8<<7)|(p->from.reg)|(REGTMP<<12);
-
- o3 = osr(AMOVH, REGTMP, instoffset+1, r, p->scond);
- break;
-
case 30: /* mov/movb/movbu R,L(R) */
o1 = omvl(p, &p->to, REGTMP);
if(!o1)
@@ -1037,7 +987,6 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
break;
case 31: /* mov/movbu L(R),R -> lr[b] */
- case 32: /* movh/movb L(R),R -> lr[b] */
o1 = omvl(p, &p->from, REGTMP);
if(!o1)
break;
@@ -1047,53 +996,6 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
o2 = olrr(REGTMP,r, p->to.reg, p->scond);
if(p->as == AMOVBU || p->as == AMOVB)
o2 |= 1<<22;
- if(o->type == 31)
- break;
-
- o3 = oprrr(ASLL, p->scond);
-
- if(p->as == AMOVBU || p->as == AMOVHU)
- o4 = oprrr(ASRL, p->scond);
- else
- o4 = oprrr(ASRA, p->scond);
-
- r = p->to.reg;
- o3 |= (r)|(r<<12);
- o4 |= (r)|(r<<12);
- if(p->as == AMOVB || p->as == AMOVBU) {
- o3 |= (24<<7);
- o4 |= (24<<7);
- } else {
- o3 |= (16<<7);
- o4 |= (16<<7);
- }
- break;
-
- case 33: /* movh/movhu R,L(R) -> sb, sb */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- r = p->to.reg;
- if(r == NREG)
- r = o->param;
- o2 = osrr(p->from.reg, REGTMP, r, p->scond);
- o2 |= (1<<22) ;
-
- o3 = oprrr(ASRL, p->scond);
- o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12);
- o3 |= (1<<6); /* ROR 8 */
-
- o4 = oprrr(AADD, p->scond);
- o4 |= (REGTMP << 12) | (REGTMP << 16);
- o4 |= immrot(1);
-
- o5 = osrr(p->from.reg, REGTMP,r,p->scond);
- o5 |= (1<<22);
-
- o6 = oprrr(ASRL, p->scond);
- o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12);
- o6 |= (1<<6); /* ROL 8 */
-
break;
case 34: /* mov $lacon,R */
@@ -1226,7 +1128,7 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
r = p->reg;
if(r == NREG) {
r = rt;
- if(p->as == AMOVF || p->as == AMOVD)
+ if(p->as == AMOVF || p->as == AMOVD || p->as == ASQRTF || p->as == ASQRTD)
r = 0;
}
o1 |= rf | (r<<16) | (rt<<12);
@@ -1304,54 +1206,12 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
break;
case 65: /* mov/movbu addr,R */
- case 66: /* movh/movhu/movb addr,R */
o1 = omvl(p, &p->from, REGTMP);
if(!o1)
break;
o2 = olr(0, REGTMP, p->to.reg, p->scond);
if(p->as == AMOVBU || p->as == AMOVB)
o2 |= 1<<22;
- if(o->type == 65)
- break;
-
- o3 = oprrr(ASLL, p->scond);
-
- if(p->as == AMOVBU || p->as == AMOVHU)
- o4 = oprrr(ASRL, p->scond);
- else
- o4 = oprrr(ASRA, p->scond);
-
- r = p->to.reg;
- o3 |= (r)|(r<<12);
- o4 |= (r)|(r<<12);
- if(p->as == AMOVB || p->as == AMOVBU) {
- o3 |= (24<<7);
- o4 |= (24<<7);
- } else {
- o3 |= (16<<7);
- o4 |= (16<<7);
- }
- break;
-
- case 67: /* movh/movhu R,addr -> sb, sb */
- o1 = omvl(p, &p->to, REGTMP);
- if(!o1)
- break;
- o2 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
-
- o3 = oprrr(ASRL, p->scond);
- o3 |= (8<<7)|(p->from.reg)|(p->from.reg<<12);
- o3 |= (1<<6); /* ROR 8 */
-
- o4 = oprrr(AADD, p->scond);
- o4 |= (REGTMP << 12) | (REGTMP << 16);
- o4 |= immrot(1);
-
- o5 = osr(p->as, p->from.reg, 0, REGTMP, p->scond);
-
- o6 = oprrr(ASRL, p->scond);
- o6 |= (24<<7)|(p->from.reg)|(p->from.reg<<12);
- o6 |= (1<<6); /* ROL 8 */
break;
case 68: /* floating point store -> ADDR */
@@ -1410,19 +1270,7 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
o2 ^= (1<<6);
break;
case 74: /* bx $I */
-#ifdef CALLEEBX
- diag("bx $i case (arm)");
-#endif
- if(!seenthumb)
- diag("ABX $I and seenthumb==0");
- v = p->cond->pc;
- if(p->to.sym->thumb)
- v |= 1; // T bit
- o1 = olr(8, REGPC, REGTMP, p->scond&C_SCOND); // mov 8(PC), Rtmp
- o2 = oprrr(AADD, p->scond) | immrot(8) | (REGPC<<16) | (REGLINK<<12); // add 8,PC, LR
- o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // bx Rtmp
- o4 = opbra(AB, 14); // B over o6
- o5 = v;
+ diag("ABX $I");
break;
case 75: /* bx O(R) */
aclass(&p->to);
@@ -1441,14 +1289,7 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP; // BX Rtmp
break;
case 76: /* bx O(R) when returning from fn*/
- if(!seenthumb)
- diag("ABXRET and seenthumb==0");
- aclass(&p->to);
-// print("ARM BXRET %d(R%d)\n", instoffset, p->to.reg);
- if(instoffset != 0)
- diag("non-zero offset in ABXRET");
- // o1 = olr(instoffset, p->to.reg, REGTMP, p->scond); // mov O(R), Rtmp
- o1 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg; // BX R
+ diag("ABXRET");
break;
case 77: /* ldrex oreg,reg */
aclass(&p->from);
@@ -1572,6 +1413,22 @@ if(debug['G']) print("%ux: %s: arm %d %d %d\n", (uint32)(p->pc), p->from.sym->na
o1 |= p->to.reg << 12;
o1 |= (p->scond & C_SCOND) << 28;
break;
+ case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
+ o1 = omvl(p, &p->from, REGTMP);
+ if(!o1)
+ break;
+ o2 = olhr(0, REGTMP, p->to.reg, p->scond);
+ if(p->as == AMOVB)
+ o2 ^= (1<<5)|(1<<6);
+ else if(p->as == AMOVH)
+ o2 ^= (1<<6);
+ break;
+ case 94: /* movh/movhu R,addr -> strh */
+ o1 = omvl(p, &p->to, REGTMP);
+ if(!o1)
+ break;
+ o2 = oshr(p->from.reg, 0, REGTMP, p->scond);
+ break;
}
out[0] = o1;
@@ -1686,6 +1543,8 @@ oprrr(int a, int sc)
case AMULF: return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4);
case ADIVD: return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4);
case ADIVF: return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4);
+ case ASQRTD: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4);
+ case ASQRTF: return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4);
case ACMPD: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4);
case ACMPF: return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4);
@@ -2031,3 +1890,9 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
Bprint(&bso, "symsize = %ud\n", symsize);
Bflush(&bso);
}
+
+void
+setpersrc(Sym *s)
+{
+ USED(s);
+}
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
index f3c9d839d..182f3e738 100644
--- a/src/cmd/5l/l.h
+++ b/src/cmd/5l/l.h
@@ -144,8 +144,6 @@ struct Sym
int32 sig;
int32 size;
uchar special;
- uchar thumb; // thumb code
- uchar foreign; // called by arm if thumb, by thumb if arm
uchar fnptr; // used as fn ptr
Sym* hash; // in hash table
Sym* allsym; // in all symbol list
@@ -208,7 +206,6 @@ enum
LFROM = 1<<0,
LTO = 1<<1,
LPOOL = 1<<2,
- V4 = 1<<3, /* arm v4 arch */
C_NONE = 0,
C_REG,
@@ -221,21 +218,16 @@ enum
C_RCON, /* 0xff rotated */
C_NCON, /* ~RCON */
C_SCON, /* 0xffff */
- C_BCON, /* thumb */
C_LCON,
C_ZFCON,
C_SFCON,
C_LFCON,
- C_GCON, /* thumb */
C_RACON,
- C_SACON, /* thumb */
C_LACON,
- C_GACON, /* thumb */
C_SBRA,
C_LBRA,
- C_GBRA, /* thumb */
C_HAUTO, /* halfword insn offset (-0xff to 0xff) */
C_FAUTO, /* float insn offset (0 to 0x3fc, word aligned) */
@@ -250,12 +242,10 @@ enum
C_ROREG,
C_SROREG, /* both S and R */
C_LOREG,
- C_GOREG, /* thumb */
C_PC,
C_SP,
C_HREG,
- C_OFFPC, /* thumb */
C_ADDR, /* reference to relocatable address */
@@ -287,9 +277,6 @@ EXTERN union
#define cbuf u.obuf
#define xbuf u.ibuf
-#define setarch(p) if((p)->as==ATEXT) thumb=(p)->reg&ALLTHUMBS
-#define setthumb(p) if((p)->as==ATEXT) seenthumb|=(p)->reg&ALLTHUMBS
-
#ifndef COFFCVT
EXTERN int32 HEADR; /* length of header */
@@ -319,7 +306,6 @@ EXTERN int nerrors;
EXTERN int32 instoffset;
EXTERN Opcross opcross[8];
EXTERN Oprang oprange[ALAST];
-EXTERN Oprang thumboprange[ALAST];
EXTERN char* outfile;
EXTERN int32 pc;
EXTERN uchar repop[ALAST];
@@ -333,14 +319,10 @@ EXTERN int version;
EXTERN char xcmp[C_GOK+1][C_GOK+1];
EXTERN Prog zprg;
EXTERN int dtype;
-EXTERN int armv4;
-EXTERN int thumb;
-EXTERN int seenthumb;
EXTERN int armsize;
extern char* anames[];
extern Optab optab[];
-extern Optab thumboptab[];
void addpool(Prog*, Adr*);
EXTERN Prog* blitrl;
@@ -368,17 +350,13 @@ int Oconv(Fmt*);
int Pconv(Fmt*);
int Sconv(Fmt*);
int aclass(Adr*);
-int thumbaclass(Adr*, Prog*);
void addhist(int32, int);
Prog* appendp(Prog*);
void asmb(void);
-void asmthumbmap(void);
void asmout(Prog*, Optab*, int32*);
-void thumbasmout(Prog*, Optab*);
int32 atolwhex(char*);
Prog* brloop(Prog*);
void buildop(void);
-void thumbbuildop(void);
void buildrep(int, int);
void cflush(void);
int chipzero(Ieee*);
@@ -442,9 +420,6 @@ int32 immaddr(int32);
int32 opbra(int, int);
int brextra(Prog*);
int isbranch(Prog*);
-int fnpinc(Sym *);
-int fninc(Sym *);
-void thumbcount(void);
void fnptrs(void);
void doelf(void);
diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c
index 2ae25d491..fa838215b 100644
--- a/src/cmd/5l/list.c
+++ b/src/cmd/5l/list.c
@@ -412,7 +412,6 @@ static char*
cnames[] =
{
[C_ADDR] = "C_ADDR",
- [C_BCON] = "C_BCON",
[C_FAUTO] = "C_FAUTO",
[C_ZFCON] = "C_SFCON",
[C_SFCON] = "C_SFCON",
@@ -420,11 +419,7 @@ cnames[] =
[C_FCR] = "C_FCR",
[C_FOREG] = "C_FOREG",
[C_FREG] = "C_FREG",
- [C_GACON] = "C_GACON",
- [C_GBRA] = "C_GBRA",
- [C_GCON] = "C_GCON",
[C_GOK] = "C_GOK",
- [C_GOREG] = "C_GOREG",
[C_HAUTO] = "C_HAUTO",
[C_HFAUTO] = "C_HFAUTO",
[C_HFOREG] = "C_HFOREG",
@@ -437,7 +432,6 @@ cnames[] =
[C_LOREG] = "C_LOREG",
[C_NCON] = "C_NCON",
[C_NONE] = "C_NONE",
- [C_OFFPC] = "C_OFFPC",
[C_PC] = "C_PC",
[C_PSR] = "C_PSR",
[C_RACON] = "C_RACON",
@@ -445,7 +439,6 @@ cnames[] =
[C_REG] = "C_REG",
[C_REGREG] = "C_REGREG",
[C_ROREG] = "C_ROREG",
- [C_SACON] = "C_SACON",
[C_SAUTO] = "C_SAUTO",
[C_SBRA] = "C_SBRA",
[C_SCON] = "C_SCON",
diff --git a/src/cmd/5l/noop.c b/src/cmd/5l/noop.c
index bdcc3cad8..e7c2db5f2 100644
--- a/src/cmd/5l/noop.c
+++ b/src/cmd/5l/noop.c
@@ -47,74 +47,11 @@ static Sym* sym_modu;
static void setdiv(int);
-static Prog *
-movrr(Prog *q, int rs, int rd, Prog *p)
-{
- if(q == nil)
- q = prg();
- q->as = AMOVW;
- q->line = p->line;
- q->from.type = D_REG;
- q->from.reg = rs;
- q->to.type = D_REG;
- q->to.reg = rd;
- q->link = p->link;
- return q;
-}
-
-static Prog *
-fnret(Prog *q, int rs, int foreign, Prog *p)
-{
- q = movrr(q, rs, REGPC, p);
- if(foreign){ // BX rs
- q->as = ABXRET;
- q->from.type = D_NONE;
- q->from.reg = NREG;
- q->to.reg = rs;
- }
- return q;
-}
-
-static Prog *
-aword(int32 w, Prog *p)
-{
- Prog *q;
-
- q = prg();
- q->as = AWORD;
- q->line = p->line;
- q->from.type = D_NONE;
- q->reg = NREG;
- q->to.type = D_CONST;
- q->to.offset = w;
- q->link = p->link;
- p->link = q;
- return q;
-}
-
-static Prog *
-adword(int32 w1, int32 w2, Prog *p)
-{
- Prog *q;
-
- q = prg();
- q->as = ADWORD;
- q->line = p->line;
- q->from.type = D_CONST;
- q->from.offset = w1;
- q->reg = NREG;
- q->to.type = D_CONST;
- q->to.offset = w2;
- q->link = p->link;
- p->link = q;
- return q;
-}
-
void
noops(void)
{
- Prog *p, *q, *q1, *q2;
- int o, foreign;
+ Prog *p, *q, *q1;
+ int o;
Prog *pmorestack;
Sym *symmorestack;
@@ -140,8 +77,6 @@ noops(void)
q = P;
for(cursym = textp; cursym != nil; cursym = cursym->next) {
for(p = cursym->text; p != P; p = p->link) {
- setarch(p);
-
switch(p->as) {
case ATEXT:
p->mark |= LEAF;
@@ -206,7 +141,6 @@ noops(void)
for(cursym = textp; cursym != nil; cursym = cursym->next) {
for(p = cursym->text; p != P; p = p->link) {
- setarch(p);
o = p->as;
switch(o) {
case ATEXT:
@@ -224,54 +158,12 @@ noops(void)
Bflush(&bso);
cursym->text->mark |= LEAF;
}
-#ifdef CALLEEBX
- if(p->from.sym->foreign){
- if(thumb)
- // don't allow literal pool to separate these
- p = adword(0xe28f7001, 0xe12fff17, p); // arm add 1, pc, r7 and bx r7
- // p = aword(0xe12fff17, aword(0xe28f7001, p)); // arm add 1, pc, r7 and bx r7
- else
- p = aword(0x4778, p); // thumb bx pc and 2 bytes padding
- }
-#endif
if(cursym->text->mark & LEAF) {
cursym->leaf = 1;
if(!autosize)
break;
}
- if(thumb){
- if(!(p->reg & NOSPLIT))
- diag("stack splitting not supported in thumb");
- if(!(cursym->text->mark & LEAF)){
- q = movrr(nil, REGLINK, REGTMPT-1, p);
- p->link = q;
- q1 = prg();
- q1->as = AMOVW;
- q1->line = p->line;
- q1->from.type = D_REG;
- q1->from.reg = REGTMPT-1;
- q1->to.type = D_OREG;
- q1->to.name = D_NONE;
- q1->to.reg = REGSP;
- q1->to.offset = 0;
- q1->link = q->link;
- q->link = q1;
- }
- if(autosize){
- q2 = prg();
- q2->as = ASUB;
- q2->line = p->line;
- q2->from.type = D_CONST;
- q2->from.offset = autosize;
- q2->to.type = D_REG;
- q2->to.reg = REGSP;
- q2->link = p->link;
- p->link = q2;
- }
- break;
- }
-
if(p->reg & NOSPLIT) {
q1 = prg();
q1->as = AMOVW;
@@ -432,16 +324,9 @@ noops(void)
case ARET:
nocache(p);
- foreign = seenthumb && (cursym->foreign || cursym->fnptr);
-// print("%s %d %d\n", cursym->name, cursym->foreign, cursym->fnptr);
if(cursym->text->mark & LEAF) {
if(!autosize) {
- if(thumb){
- p = fnret(p, REGLINK, foreign, p);
- break;
- }
-// if(foreign) print("ABXRET 1 %s\n", cursym->name);
- p->as = foreign ? ABXRET : AB;
+ p->as = AB;
p->from = zprg.from;
p->to.type = D_OREG;
p->to.offset = 0;
@@ -449,95 +334,16 @@ noops(void)
break;
}
}
- if(thumb){
- diag("thumb not maintained");
- errorexit();
- if(cursym->text->mark & LEAF){
- if(autosize){
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = autosize;
- p->to.type = D_REG;
- p->to.reg = REGSP;
- q = nil;
- }
- else
- q = p;
- q = fnret(q, REGLINK, foreign, p);
- if(q != p)
- p->link = q;
- }
- else{
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.name = D_NONE;
- p->from.reg = REGSP;
- p->from.offset = 0;
- p->to.type = D_REG;
- p->to.reg = REGTMPT-1;
- if(autosize){
- q = prg();
- q->as = AADD;
- q->from.type = D_CONST;
- q->from.offset = autosize;
- q->to.type = D_REG;
- q->to.reg = REGSP;
- q->link = p->link;
- p->link = q;
- }
- else
- q = p;
- q1 = fnret(nil, REGTMPT-1, foreign, p);
- q1->link = q->link;
- q->link = q1;
- }
- break;
- }
- if(foreign) {
- diag("foreign not maintained");
- errorexit();
-// if(foreign) print("ABXRET 3 %s\n", cursym->name);
-#define R 1
- p->as = AMOVW;
- p->from.type = D_OREG;
- p->from.name = D_NONE;
- p->from.reg = REGSP;
- p->from.offset = 0;
- p->to.type = D_REG;
- p->to.reg = R;
- q = prg();
- q->as = AADD;
- q->scond = p->scond;
- q->line = p->line;
- q->from.type = D_CONST;
- q->from.offset = autosize;
- q->to.type = D_REG;
- q->to.reg = REGSP;
- q->link = p->link;
- p->link = q;
- q1 = prg();
- q1->as = ABXRET;
- q1->scond = p->scond;
- q1->line = p->line;
- q1->to.type = D_OREG;
- q1->to.offset = 0;
- q1->to.reg = R;
- q1->link = q->link;
- q->link = q1;
-#undef R
- }
- else {
- p->as = AMOVW;
- p->scond |= C_PBIT;
- p->from.type = D_OREG;
- p->from.offset = autosize;
- p->from.reg = REGSP;
- p->to.type = D_REG;
- p->to.reg = REGPC;
- // If there are instructions following
- // this ARET, they come from a branch
- // with the same stackframe, so no spadj.
- }
+ p->as = AMOVW;
+ p->scond |= C_PBIT;
+ p->from.type = D_OREG;
+ p->from.offset = autosize;
+ p->from.reg = REGSP;
+ p->to.type = D_REG;
+ p->to.reg = REGPC;
+ // If there are instructions following
+ // this ARET, they come from a branch
+ // with the same stackframe, so no spadj.
break;
case AADD:
@@ -589,7 +395,7 @@ noops(void)
if(q1->reg == NREG)
p->from.reg = q1->to.reg;
p->to.type = D_REG;
- p->to.reg = prog_div->from.sym->thumb ? REGTMPT : REGTMP;
+ p->to.reg = REGTMP;
p->to.offset = 0;
/* CALL appropriate */
@@ -598,14 +404,7 @@ noops(void)
p->link = q;
p = q;
-#ifdef CALLEEBX
p->as = ABL;
-#else
- if(prog_div->from.sym->thumb)
- p->as = thumb ? ABL : ABX;
- else
- p->as = thumb ? ABX : ABL;
-#endif
p->line = q1->line;
p->to.type = D_BRANCH;
p->cond = p;
@@ -637,7 +436,7 @@ noops(void)
p->as = AMOVW;
p->line = q1->line;
p->from.type = D_REG;
- p->from.reg = prog_div->from.sym->thumb ? REGTMPT : REGTMP;
+ p->from.reg = REGTMP;
p->from.offset = 0;
p->to.type = D_REG;
p->to.reg = q1->to.reg;
@@ -669,12 +468,6 @@ noops(void)
break;
case AMOVW:
- if(thumb){
- Adr *a = &p->from;
-
- if(a->type == D_CONST && ((a->name == D_NONE && a->reg == REGSP) || a->name == D_AUTO || a->name == D_PARAM) && (a->offset & 3))
- diag("SP offset not multiple of 4");
- }
if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP)
p->spadj = -p->to.offset;
if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC)
@@ -682,136 +475,6 @@ noops(void)
if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP)
p->spadj = -p->from.offset;
break;
- case AMOVB:
- case AMOVBU:
- case AMOVH:
- case AMOVHU:
- if(thumb){
- if(p->from.type == D_OREG && (p->from.name == D_AUTO || p->from.name == D_PARAM || (p->from.name == D_CONST && p->from.reg == REGSP))){
- q = prg();
- *q = *p;
- if(p->from.name == D_AUTO)
- q->from.offset += autosize;
- else if(p->from.name == D_PARAM)
- q->from.offset += autosize+4;
- q->from.name = D_NONE;
- q->from.reg = REGTMPT;
- p = movrr(p, REGSP, REGTMPT, p);
- q->link = p->link;
- p->link = q;
- }
- if(p->to.type == D_OREG && (p->to.name == D_AUTO || p->to.name == D_PARAM || (p->to.name == D_CONST && p->to.reg == REGSP))){
- q = prg();
- *q = *p;
- if(p->to.name == D_AUTO)
- q->to.offset += autosize;
- else if(p->to.name == D_PARAM)
- q->to.offset += autosize+4;
- q->to.name = D_NONE;
- q->to.reg = REGTMPT;
- p = movrr(p, REGSP, REGTMPT, p);
- q->link = p->link;
- p->link = q;
- if(q->to.offset < 0 || q->to.offset > 255){ // complicated
- p->to.reg = REGTMPT+1; // mov sp, r8
- q1 = prg();
- q1->line = p->line;
- q1->as = AMOVW;
- q1->from.type = D_CONST;
- q1->from.offset = q->to.offset;
- q1->to.type = D_REG;
- q1->to.reg = REGTMPT; // mov $o, r7
- p->link = q1;
- q1->link = q;
- q1 = prg();
- q1->line = p->line;
- q1->as = AADD;
- q1->from.type = D_REG;
- q1->from.reg = REGTMPT+1;
- q1->to.type = D_REG;
- q1->to.reg = REGTMPT; // add r8, r7
- p->link->link = q1;
- q1->link = q;
- q->to.offset = 0; // mov* r, 0(r7)
- /* phew */
- }
- }
- }
- break;
- case AMOVM:
- if(thumb){
- if(p->from.type == D_OREG){
- if(p->from.offset == 0)
- p->from.type = D_REG;
- else
- diag("non-zero AMOVM offset");
- }
- else if(p->to.type == D_OREG){
- if(p->to.offset == 0)
- p->to.type = D_REG;
- else
- diag("non-zero AMOVM offset");
- }
- }
- break;
- case AB:
- if(thumb && p->to.type == D_OREG){
- if(p->to.offset == 0){
- p->as = AMOVW;
- p->from.type = D_REG;
- p->from.reg = p->to.reg;
- p->to.type = D_REG;
- p->to.reg = REGPC;
- }
- else{
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = p->to.offset;
- p->reg = p->to.reg;
- p->to.type = D_REG;
- p->to.reg = REGTMPT-1;
- q = prg();
- q->as = AMOVW;
- q->line = p->line;
- q->from.type = D_REG;
- q->from.reg = REGTMPT-1;
- q->to.type = D_REG;
- q->to.reg = REGPC;
- q->link = p->link;
- p->link = q;
- }
- }
- if(seenthumb && !thumb && p->to.type == D_OREG && p->to.reg == REGLINK){
- // print("warn %s: b (R%d) assuming a return\n", cursym->name, p->to.reg);
- p->as = ABXRET;
- }
- break;
- case ABL:
- case ABX:
- if(thumb && p->to.type == D_OREG){
- if(p->to.offset == 0){
- p->as = o;
- p->from.type = D_NONE;
- p->to.type = D_REG;
- }
- else{
- p->as = AADD;
- p->from.type = D_CONST;
- p->from.offset = p->to.offset;
- p->reg = p->to.reg;
- p->to.type = D_REG;
- p->to.reg = REGTMPT-1;
- q = prg();
- q->as = o;
- q->line = p->line;
- q->from.type = D_NONE;
- q->to.type = D_REG;
- q->to.reg = REGTMPT-1;
- q->link = p->link;
- p->link = q;
- }
- }
- break;
}
}
}
@@ -876,13 +539,19 @@ setdiv(int as)
Prog *p = nil;
switch(as){
- case ADIV: p = prog_div; break;
- case ADIVU: p = prog_divu; break;
- case AMOD: p = prog_mod; break;
- case AMODU: p = prog_modu; break;
+ case ADIV:
+ p = prog_div;
+ break;
+ case ADIVU:
+ p = prog_divu;
+ break;
+ case AMOD:
+ p = prog_mod;
+ break;
+ case AMODU:
+ p = prog_modu;
+ break;
}
- if(thumb != p->from.sym->thumb)
- p->from.sym->foreign = 1;
}
void
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
index c4a2bfc3f..dd3a7329a 100644
--- a/src/cmd/5l/obj.c
+++ b/src/cmd/5l/obj.c
@@ -67,6 +67,7 @@ static char*
linkername[] =
{
"runtime.softfloat",
+ "math.sqrtGoC",
};
void
@@ -219,7 +220,7 @@ main(int argc, char *argv[])
elfinit();
HEADR = ELFRESERVE;
if(INITTEXT == -1)
- INITTEXT = 0x8000 + HEADR;
+ INITTEXT = 0x10000 + HEADR;
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
@@ -241,7 +242,6 @@ main(int argc, char *argv[])
zprg.from.reg = NREG;
zprg.to = zprg.from;
buildop();
- thumbbuildop(); // could build on demand
histgen = 0;
pc = 0;
dtype = 4;
@@ -285,10 +285,8 @@ main(int argc, char *argv[])
asmb();
undef();
- if(debug['c']){
- thumbcount();
+ if(debug['c'])
print("ARM size = %d\n", armsize);
- }
if(debug['v']) {
Bprint(&bso, "%5.2f cpu time\n", cputime());
Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
@@ -405,14 +403,12 @@ nopout(Prog *p)
p->to.type = D_NONE;
}
-static void puntfp(Prog *);
-
void
ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
{
int32 ipc;
Prog *p;
- Sym *h[NSYM], *s, *di;
+ Sym *h[NSYM], *s;
int v, o, r, skip;
uint32 sig;
char *name;
@@ -424,7 +420,6 @@ ldobj1(Biobuf *f, char *pkg, int64 len, char *pn)
lastp = nil;
ntext = 0;
eof = Boffset(f) + len;
- di = S;
src[0] = 0;
newloop:
@@ -622,8 +617,6 @@ loop:
else
textp = s;
etextp = s;
- setarch(p);
- setthumb(p);
p->align = 4;
autosize = (p->to.offset+3L) & ~3L;
p->to.offset = autosize;
@@ -631,7 +624,6 @@ loop:
s->type = STEXT;
s->text = p;
s->value = pc;
- s->thumb = thumb;
lastp = p;
p->pc = pc;
pc++;
@@ -673,13 +665,9 @@ loop:
case AMULD:
case ADIVF:
case ADIVD:
- if(thumb)
- puntfp(p);
goto casedef;
case AMOVF:
- if(thumb)
- puntfp(p);
if(skip)
goto casedef;
@@ -701,8 +689,6 @@ loop:
goto casedef;
case AMOVD:
- if(thumb)
- puntfp(p);
if(skip)
goto casedef;
@@ -758,17 +744,6 @@ prg(void)
return p;
}
-static void
-puntfp(Prog *p)
-{
- USED(p);
- /* floating point - punt for now */
- cursym->text->reg = NREG; /* ARM */
- cursym->thumb = 0;
- thumb = 0;
- // print("%s: generating ARM code (contains floating point ops %d)\n", curtext->from.sym->name, p->line);
-}
-
Prog*
appendp(Prog *q)
{
diff --git a/src/cmd/5l/optab.c b/src/cmd/5l/optab.c
index 625b66812..514786f85 100644
--- a/src/cmd/5l/optab.c
+++ b/src/cmd/5l/optab.c
@@ -77,7 +77,6 @@ Optab optab[] =
{ ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0 },
{ AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0 },
- { AWORD, C_NONE, C_NONE, C_GCON, 11, 4, 0 },
{ AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0 },
{ AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0 },
@@ -117,18 +116,6 @@ Optab optab[] =
{ AMOVBU, C_SAUTO,C_NONE, C_REG, 21, 4, REGSP },
{ AMOVBU, C_SOREG,C_NONE, C_REG, 21, 4, 0 },
- { AMOVB, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP },
- { AMOVB, C_SOREG,C_NONE, C_REG, 22, 12, 0 },
- { AMOVH, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP },
- { AMOVH, C_SOREG,C_NONE, C_REG, 22, 12, 0 },
- { AMOVHU, C_SAUTO,C_NONE, C_REG, 22, 12, REGSP },
- { AMOVHU, C_SOREG,C_NONE, C_REG, 22, 12, 0 },
-
- { AMOVH, C_REG, C_NONE, C_SAUTO, 23, 12, REGSP },
- { AMOVH, C_REG, C_NONE, C_SOREG, 23, 12, 0 },
- { AMOVHU, C_REG, C_NONE, C_SAUTO, 23, 12, REGSP },
- { AMOVHU, C_REG, C_NONE, C_SOREG, 23, 12, 0 },
-
{ AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO },
{ AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO },
{ AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO },
@@ -146,23 +133,6 @@ Optab optab[] =
{ AMOVBU, C_LOREG,C_NONE, C_REG, 31, 8, 0, LFROM },
{ AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM },
- { AMOVB, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM },
- { AMOVB, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM },
- { AMOVB, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM },
- { AMOVH, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM },
- { AMOVH, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM },
- { AMOVH, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM },
- { AMOVHU, C_LAUTO,C_NONE, C_REG, 32, 16, REGSP, LFROM },
- { AMOVHU, C_LOREG,C_NONE, C_REG, 32, 16, 0, LFROM },
- { AMOVHU, C_ADDR, C_NONE, C_REG, 66, 16, 0, LFROM },
-
- { AMOVH, C_REG, C_NONE, C_LAUTO, 33, 24, REGSP, LTO },
- { AMOVH, C_REG, C_NONE, C_LOREG, 33, 24, 0, LTO },
- { AMOVH, C_REG, C_NONE, C_ADDR, 67, 24, 0, LTO },
- { AMOVHU, C_REG, C_NONE, C_LAUTO, 33, 24, REGSP, LTO },
- { AMOVHU, C_REG, C_NONE, C_LOREG, 33, 24, 0, LTO },
- { AMOVHU, C_REG, C_NONE, C_ADDR, 67, 24, 0, LTO },
-
{ AMOVW, C_LACON,C_NONE, C_REG, 34, 8, REGSP, LFROM },
{ AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0 },
@@ -210,29 +180,35 @@ Optab optab[] =
{ ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0 },
{ ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0 },
- { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, V4 },
- { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, V4 },
- { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, V4 },
- { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, V4 },
-
- { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 },
- { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 },
- { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 },
- { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 },
- { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, V4 },
- { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, V4 },
-
- { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO|V4 },
- { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO|V4 },
- { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO|V4 },
- { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO|V4 },
-
- { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 },
- { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 },
- { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 },
- { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 },
- { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM|V4 },
- { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM|V4 },
+ { AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
+ { AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
+ { AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0 },
+ { AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0 },
+
+ { AMOVB, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVB, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+ { AMOVH, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVH, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+ { AMOVHU, C_HAUTO,C_NONE, C_REG, 71, 4, REGSP, 0 },
+ { AMOVHU, C_HOREG,C_NONE, C_REG, 71, 4, 0, 0 },
+
+ { AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
+ { AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
+ { AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO },
+ { AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO },
+ { AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO },
+ { AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO },
+
+ { AMOVB, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVB, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM },
+ { AMOVH, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVH, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM },
+ { AMOVHU, C_LAUTO,C_NONE, C_REG, 73, 8, REGSP, LFROM },
+ { AMOVHU, C_LOREG,C_NONE, C_REG, 73, 8, 0, LFROM },
+ { AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM },
+
{ ALDREX, C_SOREG,C_NONE, C_REG, 77, 4, 0 },
{ ASTREX, C_SOREG,C_REG, C_REG, 78, 4, 0 },
diff --git a/src/cmd/5l/pass.c b/src/cmd/5l/pass.c
index 7e1ba6a09..194a1ed5f 100644
--- a/src/cmd/5l/pass.c
+++ b/src/cmd/5l/pass.c
@@ -100,7 +100,6 @@ xfol(Prog *p, Prog **last)
loop:
if(p == P)
return;
- setarch(p);
a = p->as;
if(a == AB) {
q = p->cond;
@@ -210,14 +209,7 @@ patch(void)
vexit = s->value;
for(cursym = textp; cursym != nil; cursym = cursym->next) {
for(p = cursym->text; p != P; p = p->link) {
- setarch(p);
a = p->as;
- if(seenthumb && a == ABL){
- // if((s = p->to.sym) != S && (s1 = curtext->from.sym) != S)
- // print("%s calls %s\n", s1->name, s->name);
- if((s = p->to.sym) != S && s->thumb != cursym->thumb)
- s->foreign = 1;
- }
if((a == ABL || a == ABX || a == AB || a == ARET) &&
p->to.type != D_BRANCH && p->to.sym != S) {
s = p->to.sym;
@@ -254,19 +246,7 @@ patch(void)
for(cursym = textp; cursym != nil; cursym = cursym->next) {
for(p = cursym->text; p != P; p = p->link) {
- setarch(p);
a = p->as;
- if(seenthumb && a == ABL) {
-#ifdef CALLEEBX
- if(0)
- {}
-#else
- if((s = p->to.sym) != S && (s->foreign || s->fnptr))
- p->as = ABX;
-#endif
- else if(p->to.type == D_OREG)
- p->as = ABX;
- }
if(p->cond != P) {
p->cond = brloop(p->cond);
if(p->cond != P)
diff --git a/src/cmd/5l/prof.c b/src/cmd/5l/prof.c
index ad115a8ca..48ad2dc59 100644
--- a/src/cmd/5l/prof.c
+++ b/src/cmd/5l/prof.c
@@ -47,7 +47,6 @@ doprof1(void)
s = lookup("__mcount", 0);
n = 1;
for(p = firstp->link; p != P; p = p->link) {
- setarch(p);
if(p->as == ATEXT) {
q = prg();
q->line = p->line;
@@ -74,7 +73,7 @@ doprof1(void)
p->from.sym = s;
p->from.offset = n*4 + 4;
p->to.type = D_REG;
- p->to.reg = thumb ? REGTMPT : REGTMP;
+ p->to.reg = REGTMP;
q = prg();
q->line = p->line;
@@ -86,7 +85,7 @@ doprof1(void)
p->from.type = D_CONST;
p->from.offset = 1;
p->to.type = D_REG;
- p->to.reg = thumb ? REGTMPT : REGTMP;
+ p->to.reg = REGTMP;
q = prg();
q->line = p->line;
@@ -96,7 +95,7 @@ doprof1(void)
p = q;
p->as = AMOVW;
p->from.type = D_REG;
- p->from.reg = thumb ? REGTMPT : REGTMP;
+ p->from.reg = REGTMP;
p->to.type = D_OREG;
p->to.name = D_EXTERN;
p->to.sym = s;
@@ -143,7 +142,6 @@ doprof2(void)
ps4 = P;
for(cursym = textp; cursym != nil; cursym = cursym->next) {
p = cursym->text;
- setarch(p);
if(cursym == s2) {
ps2 = p;
p->reg = 1;
@@ -155,7 +153,6 @@ doprof2(void)
}
for(cursym = textp; cursym != nil; cursym = cursym->next)
for(p = cursym->text; p != P; p = p->link) {
- setarch(p);
if(p->as == ATEXT) {
if(p->reg & NOPROF) {
for(;;) {
diff --git a/src/cmd/5l/softfloat.c b/src/cmd/5l/softfloat.c
index 03d8c6d26..4f799d17e 100644
--- a/src/cmd/5l/softfloat.c
+++ b/src/cmd/5l/softfloat.c
@@ -54,6 +54,8 @@ softfloat(void)
case AMULD:
case ADIVF:
case ADIVD:
+ case ASQRTF:
+ case ASQRTD:
goto soft;
default:
diff --git a/src/cmd/5l/span.c b/src/cmd/5l/span.c
index 482d3e90a..eb79f6b5a 100644
--- a/src/cmd/5l/span.c
+++ b/src/cmd/5l/span.c
@@ -50,86 +50,6 @@ isbranch(Prog *p)
}
static int
-ispad(Prog *p)
-{
- if(p->as != AMOVW)
- return 0;
- if(p->from.type != D_REG || p->from.reg != REGTMP)
- return 0;
- if(p->to.type != D_REG || p->to.reg != REGTMP)
- return 0;
- return 1;
-}
-
-int
-fninc(Sym *s)
-{
- if(thumb){
- if(s->thumb){
- if(s->foreign)
- return 8;
- else
- return 0;
- }
- else{
- if(s->foreign)
- return 0;
- else
- diag("T A !foreign in fninc");
- }
- }
- else{
- if(s->thumb){
- if(s->foreign)
- return 0;
- else
- diag("A T !foreign in fninc");
- }
- else{
- if(s->foreign)
- return 4;
- else
- return 0;
- }
- }
- return 0;
-}
-
-int
-fnpinc(Sym *s)
-{
- if(!s->fnptr){ // a simplified case BX O(R) -> BL O(R)
- if(!debug['f'])
- diag("fnptr == 0 in fnpinc");
- if(s->foreign)
- diag("bad usage in fnpinc %s %d %d", s->name, s->foreign, s->thumb);
- return 0;
- }
- /* 0, 1, 2, 3 squared */
- if(s->thumb)
- return s->foreign ? 9 : 1;
- else
- return s->foreign ? 4 : 0;
-}
-
-static Prog *
-pad(Prog *p, int pc)
-{
- Prog *q;
-
- q = prg();
- q->as = AMOVW;
- q->line = p->line;
- q->from.type = D_REG;
- q->from.reg = REGTMP;
- q->to.type = D_REG;
- q->to.reg = REGTMP;
- q->pc = pc;
- q->link = p->link;
- return q;
-}
-
-static int
scan(Prog *op, Prog *p, int c)
{
Prog *q;
@@ -168,7 +88,6 @@ span(void)
Optab *o;
int m, bflag, i, v;
int32 c, otxt, out[6];
- int lastthumb = -1;
Section *sect;
uchar *bp;
@@ -183,11 +102,9 @@ span(void)
otxt = c;
for(cursym = textp; cursym != nil; cursym = cursym->next) {
p = cursym->text;
- setarch(p);
p->pc = c;
cursym->value = c;
- lastthumb = thumb;
autosize = p->to.offset + 4;
if(p->from.sym != S)
p->from.sym->value = c;
@@ -195,19 +112,14 @@ span(void)
if(c-otxt >= 1L<<17)
bflag = 1;
otxt = c;
- if(thumb && blitrl)
- pool.extra += brextra(p);
for(op = p, p = p->link; p != P; op = p, p = p->link) {
curp = p;
- setarch(p);
p->pc = c;
o = oplook(p);
m = o->size;
// must check literal pool here in case p generates many instructions
if(blitrl){
- if(thumb && isbranch(p))
- pool.extra += brextra(p);
if(checkpool(op, p->as == ACASE ? casesz(p) : m))
c = p->pc = scan(op, p, c);
}
@@ -232,8 +144,6 @@ span(void)
c += m;
}
if(blitrl){
- if(thumb && isbranch(op))
- pool.extra += brextra(op);
if(checkpool(op, 0))
c = scan(op, P, c);
}
@@ -255,10 +165,7 @@ span(void)
cursym->value = c;
for(p = cursym->text; p != P; p = p->link) {
curp = p;
- setarch(p);
p->pc = c;
- if(thumb && isbranch(p))
- nocache(p);
o = oplook(p);
/* very large branches
if(o->type == 6 && p->cond) {
@@ -300,74 +207,6 @@ span(void)
}
}
- if(seenthumb){ // branch resolution
- int passes = 0;
- int lastc = 0;
- int again;
- Prog *oop;
-
- loop:
- passes++;
- if(passes > 100){
- diag("span looping !");
- errorexit();
- }
- c = INITTEXT;
- oop = op = nil;
- again = 0;
- for(cursym = textp; cursym != nil; cursym = cursym->next) {
- cursym->value = c;
- for(p = cursym->text; p != P; oop = op, op = p, p = p->link) {
- curp = p;
- setarch(p);
- if(p->pc != c)
- again = 1;
- p->pc = c;
- if(thumb && isbranch(p))
- nocache(p);
- o = oplook(p);
- m = o->size;
- if(passes == 1 && thumb && isbranch(p)){ // start conservative so unneeded alignment is not added
- if(p->as == ABL)
- m = 4;
- else
- m = 2;
- p->align = 0;
- }
- if(p->align){
- if((p->align == 4 && (c&3)) || (p->align == 2 && !(c&3))){
- if(ispad(op)){
- oop->link = p;
- op = oop;
- c -= 2;
- p->pc = c;
- }
- else{
- op->link = pad(op, c);
- op = op->link;
- c += 2;
- p->pc = c;
- }
- again = 1;
- }
- }
- if(m == 0) {
- if(p->as == ATEXT) {
- autosize = p->to.offset + 4;
- if(p->from.sym != S)
- p->from.sym->value = c;
- continue;
- }
- }
- c += m;
- }
- cursym->size = c - cursym->value;
- }
- if(c != lastc || again){
- lastc = c;
- goto loop;
- }
- }
c = rnd(c, 8);
/*
@@ -380,7 +219,6 @@ span(void)
*/
for(cursym = textp; cursym != nil; cursym = cursym->next) {
p = cursym->text;
- setarch(p);
autosize = p->to.offset + 4;
symgrow(cursym, cursym->size);
@@ -414,13 +252,6 @@ span(void)
int
checkpool(Prog *p, int sz)
{
- if(thumb){
- if(pool.size >= 0x3fc || (p->pc+sz+pool.extra+2+2)+(pool.size-4)-pool.start-4 >= 0x3fc)
- return flushpool(p, 1, 0);
- else if(p->link == P)
- return flushpool(p, 2, 0);
- return 0;
- }
if(pool.size >= 0xffc || immaddr((p->pc+sz+4)+4+pool.size - pool.start+8) == 0)
return flushpool(p, 1, 0);
else if(p->link == P)
@@ -443,7 +274,7 @@ flushpool(Prog *p, int skip, int force)
q->link = blitrl;
blitrl = q;
}
- else if(!force && (p->pc+pool.size-pool.start < (thumb ? 0x3fc+4-pool.extra : 2048)))
+ else if(!force && (p->pc+pool.size-pool.start < 2048))
return 0;
elitrl->link = p->link;
p->link = blitrl;
@@ -463,10 +294,7 @@ addpool(Prog *p, Adr *a)
Prog *q, t;
int c;
- if(thumb)
- c = thumbaclass(a, p);
- else
- c = aclass(a);
+ c = aclass(a);
t = zprg;
t.as = AWORD;
@@ -482,12 +310,10 @@ addpool(Prog *p, Adr *a)
case C_FOREG:
case C_SOREG:
case C_HOREG:
- case C_GOREG:
case C_FAUTO:
case C_SAUTO:
case C_LAUTO:
case C_LACON:
- case C_GACON:
t.to.type = D_CONST;
t.to.offset = instoffset;
break;
@@ -593,16 +419,6 @@ symaddr(Sym *s)
return 0;
case STEXT:
-/* TODO(rsc): what is this for?
-#ifdef CALLEEBX
- v += fnpinc(s);
-#else
- if(s->thumb)
- v++; // T bit
-#endif
-*/
- break;
-
case SELFDATA:
case SRODATA:
case SDATA:
@@ -770,35 +586,19 @@ oplook(Prog *p)
int a1, a2, a3, r;
char *c1, *c3;
Optab *o, *e;
- Optab *otab;
- Oprang *orange;
- if(thumb){
- otab = thumboptab;
- orange = thumboprange;
- }
- else{
- otab = optab;
- orange = oprange;
- }
a1 = p->optab;
if(a1)
- return otab+(a1-1);
+ return optab+(a1-1);
a1 = p->from.class;
if(a1 == 0) {
- if(thumb)
- a1 = thumbaclass(&p->from, p) + 1;
- else
- a1 = aclass(&p->from) + 1;
+ a1 = aclass(&p->from) + 1;
p->from.class = a1;
}
a1--;
a3 = p->to.class;
if(a3 == 0) {
- if(thumb)
- a3 = thumbaclass(&p->to, p) + 1;
- else
- a3 = aclass(&p->to) + 1;
+ a3 = aclass(&p->to) + 1;
p->to.class = a3;
}
a3--;
@@ -806,35 +606,35 @@ oplook(Prog *p)
if(p->reg != NREG)
a2 = C_REG;
r = p->as;
- o = orange[r].start;
+ o = oprange[r].start;
if(o == 0) {
a1 = opcross[repop[r]][a1][a2][a3];
if(a1) {
p->optab = a1+1;
- return otab+a1;
+ return optab+a1;
}
- o = orange[r].stop; /* just generate an error */
+ o = oprange[r].stop; /* just generate an error */
}
if(debug['O']) {
print("oplook %A %O %O %O\n",
(int)p->as, a1, a2, a3);
print(" %d %d\n", p->from.type, p->to.type);
}
- e = orange[r].stop;
+ e = oprange[r].stop;
c1 = xcmp[a1];
c3 = xcmp[a3];
for(; o<e; o++)
if(o->a2 == a2)
if(c1[o->a1])
if(c3[o->a3]) {
- p->optab = (o-otab)+1;
+ p->optab = (o-optab)+1;
return o;
}
diag("illegal combination %A %O %O %O, %d %d",
p->as, a1, a2, a3, p->from.type, p->to.type);
prasm(p);
if(o == 0)
- o = otab;
+ o = optab;
return o;
}
@@ -885,9 +685,6 @@ cmp(int a, int b)
if(b == C_SBRA)
return 1;
break;
- case C_GBRA:
- if(b == C_SBRA || b == C_LBRA)
- return 1;
case C_HREG:
return cmp(C_SP, b) || cmp(C_PC, b);
@@ -907,9 +704,6 @@ ocmp(const void *a1, const void *a2)
n = p1->as - p2->as;
if(n)
return n;
- n = (p2->flag&V4) - (p1->flag&V4); /* architecture version */
- if(n)
- return n;
n = p1->a1 - p2->a1;
if(n)
return n;
@@ -927,15 +721,11 @@ buildop(void)
{
int i, n, r;
- armv4 = !debug['h'];
for(i=0; i<C_GOK; i++)
for(n=0; n<C_GOK; n++)
xcmp[i][n] = cmp(n, i);
for(n=0; optab[n].as != AXXX; n++)
- if((optab[n].flag & V4) && !armv4) {
- optab[n].as = AXXX;
- break;
- }
+ ;
qsort(optab, n, sizeof(optab[0]), ocmp);
for(i=0; i<n; i++) {
r = optab[i].as;
@@ -1025,6 +815,8 @@ buildop(void)
oprange[AMULD] = oprange[r];
oprange[ADIVF] = oprange[r];
oprange[ADIVD] = oprange[r];
+ oprange[ASQRTF] = oprange[r];
+ oprange[ASQRTD] = oprange[r];
oprange[AMOVFD] = oprange[r];
oprange[AMOVDF] = oprange[r];
break;
diff --git a/src/cmd/5l/thumb.c b/src/cmd/5l/thumb.c
deleted file mode 100644
index a6f729bed..000000000
--- a/src/cmd/5l/thumb.c
+++ /dev/null
@@ -1,1658 +0,0 @@
-// Inferno utils/5l/thumb.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/thumb.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 "l.h"
-#include "../ld/lib.h"
-
-static int32 thumboprr(int);
-static int32 thumboprrr(int, int);
-static int32 thumbopirr(int , int);
-static int32 thumbopri(int);
-static int32 thumbophh(int);
-static int32 thumbopbra(int);
-static int32 thumbopmv(int, int);
-static void lowreg(Prog *, int);
-static void mult(Prog *, int, int);
-static void numr(Prog *, int, int, int);
-static void regis(Prog *, int, int, int);
-static void dis(int, int);
-
-// build a constant using neg, add and shift - only worth it if < 6 bytes */
-static int
-immbuildcon(int c, Prog *p)
-{
- int n = 0;
-
- USED(p);
- if(c >= 0 && c <= 255)
- return 0; // mv
- if(c >= -255 && c < 0) // mv, neg
- return 1;
- if(c >= 256 && c <= 510) // mv, add
- return 1;
- if(c < 0)
- return 0;
- while(!(c & 1)){
- n++;
- c >>= 1;
- }
- if(c >= 0 && c <= 255) // mv, lsl
- return 1;
- return 0;
-}
-
-// positive 5 bit offset from register - O(R)
-// positive 8 bit offset from register - mov O, R then [R, R]
-// otherwise O goes in literal pool - mov O1(PC), R then [R, R]
-static int
-immoreg(int off, Prog *p)
-{
- int v = 1;
- int as = p->as;
-
- if(off < 0)
- return C_GOREG;
- if(as == AMOVW)
- v = 4;
- else if(as == AMOVH || as == AMOVHU)
- v = 2;
- else if(as == AMOVB || as == AMOVBU)
- v = 1;
- else
- diag("bad op in immoreg");
- if(off/v <= 31)
- return C_SOREG;
- if(off <= 255)
- return C_LOREG;
- return C_GOREG;
-}
-
-// positive 8 bit - mov O, R then 0(R)
-// otherwise O goes in literal pool - mov O1(PC), R then 0(R)
-static int
-immacon(int off, Prog *p, int t1, int t2)
-{
- USED(p);
- if(off < 0)
- return t2;
- if(off <= 255)
- return t1;
- return t2;
-}
-
-// unsigned 8 bit in words
-static int
-immauto(int off, Prog *p)
-{
- if(p->as != AMOVW)
- diag("bad op in immauto");
- mult(p, off, 4);
- if(off >= 0 && off <= 1020)
- return C_SAUTO;
- return C_LAUTO;
-}
-
-static int
-immsmall(int off, Prog *p, int t1, int t2, int t3)
-{
- USED(p);
- if(off >= 0 && off <= 7)
- return t1;
- if(off >= 0 && off <= 255)
- return t2;
- return t3;
-}
-
-static int
-immcon(int off, Prog *p)
-{
- int as = p->as;
-
- if(as == ASLL || as == ASRL || as == ASRA)
- return C_SCON;
- if(p->to.type == D_REG && p->to.reg == REGSP){
- if(as == AADD || as == ASUB){
- if(off >= 0 && off <= 508)
- return C_SCON;
- if(as == ASUB){
- p->as = AADD;
- p->from.offset = -p->from.offset;
- }
- return C_LCON;
- }
- diag("unknown type in immcon");
- }
- if(as == AADD || as == ASUB){
- if(p->reg != NREG)
- return immsmall(off, p, C_SCON, C_LCON, C_GCON);
- return immacon(off, p, C_SCON, C_LCON);
- }
- if(as == AMOVW && p->from.type == D_CONST && p->to.type == D_REG && immbuildcon(off, p))
- return C_BCON;
- if(as == ACMP && p->from.type == D_CONST && immbuildcon(off, p))
- return C_BCON;
- if(as == ACMP || as == AMOVW)
- return immacon(off, p, C_SCON, C_LCON);
- return C_LCON;
-}
-
-int
-thumbaclass(Adr *a, Prog *p)
-{
- Sym *s;
- int t;
-
- switch(a->type) {
- case D_NONE:
- return C_NONE;
- case D_REG:
- if(a->reg == REGSP)
- return C_SP;
- if(a->reg == REGPC)
- return C_PC;
- if(a->reg >= 8)
- return C_HREG;
- return C_REG;
- case D_SHIFT:
- diag("D_SHIFT in thumbaclass");
- return C_SHIFT;
- case D_FREG:
- diag("D_FREG in thumbaclass");
- return C_FREG;
- case D_FPCR:
- diag("D_FPCR in thumbaclass");
- return C_FCR;
- case D_OREG:
- switch(a->name) {
- case D_EXTERN:
- case D_STATIC:
- if(a->sym == 0 || a->sym->name == 0) {
- print("null sym external\n");
- print("%D\n", a);
- return C_GOK;
- }
- t = a->sym->type;
- if(t == 0 || t == SXREF) {
- diag("undefined external: %s in %s\n",
- a->sym->name, TNAME);
- a->sym->type = SDATA;
- }
- instoffset = a->sym->value + a->offset;
- return C_ADDR; /* INITDAT unknown at this stage */
- case D_AUTO:
- instoffset = autosize + a->offset;
- return immauto(instoffset, p);
- case D_PARAM:
- instoffset = autosize + a->offset + 4L;
-// print("D_PARAM %s %d+%d+%d = %d\n", a->sym != S ? a->sym->name : "noname", autosize, a->offset, 4, autosize+a->offset+4);
- return immauto(instoffset, p);
- case D_NONE:
- instoffset = a->offset;
- if(a->reg == REGSP)
- return immauto(instoffset, p);
- else
- return immoreg(instoffset, p);
- }
- return C_GOK;
- case D_PSR:
- diag("D_PSR in thumbaclass");
- return C_PSR;
- case D_OCONST:
- switch(a->name) {
- case D_EXTERN:
- case D_STATIC:
- s = a->sym;
- t = s->type;
- if(t == 0 || t == SXREF) {
- diag("undefined external: %s in %s\n",
- s->name, TNAME);
- s->type = SDATA;
- }
- instoffset = s->value + a->offset;
- if(s->type == STEXT){
- instoffset = s->value + a->offset;
-#ifdef CALLEEBX
- instoffset += fnpinc(s);
-#else
- if(s->thumb)
- instoffset++; // T bit
-#endif
- return C_LCON;
- }
- return C_LCON; /* INITDAT unknown at this stage */
- // return immcon(instoffset, p);
- }
- return C_GOK;
- case D_FCONST:
- diag("D_FCONST in thumaclass");
- return C_LFCON;
- case D_CONST:
- switch(a->name) {
- case D_NONE:
- instoffset = a->offset;
- if(a->reg != NREG)
- goto aconsize;
- return immcon(instoffset, p);
- case D_EXTERN:
- case D_STATIC:
- s = a->sym;
- if(s == S)
- break;
- t = s->type;
- switch(t) {
- case 0:
- case SXREF:
- diag("undefined external: %s in %s\n",
- s->name, TNAME);
- s->type = SDATA;
- break;
- case SCONST:
- case STEXT:
- instoffset = s->value + a->offset;
-#ifdef CALLEEBX
- instoffset += fnpinc(s);
-#else
- if(s->thumb)
- instoffset++; // T bit
-#endif
- return C_LCON;
- }
- instoffset = s->value + a->offset;
- return C_LCON; /* INITDAT unknown at this stage */
- // return immcon(instoffset, p);
- case D_AUTO:
- instoffset = autosize + a->offset;
- goto aconsize;
- case D_PARAM:
- instoffset = autosize + a->offset + 4L;
- aconsize:
- if(p->from.reg == REGSP || p->from.reg == NREG)
- return instoffset >= 0 && instoffset < 1024 ? C_SACON : C_GACON;
- else if(p->from.reg == p->to.reg)
- return immacon(instoffset, p, C_SACON, C_GACON);
- return immsmall(instoffset, p, C_SACON, C_LACON, C_GACON);
- }
- return C_GOK;
- case D_BRANCH: {
- int v, va;
-
- p->align = 0;
- v = -4;
- va = 0;
- if(p->cond != P){
- v = (p->cond->pc - p->pc) - 4;
- va = p->cond->pc;
- }
- instoffset = v;
- if(p->as == AB){
- if(v >= -2048 && v <= 2046)
- return C_SBRA;
- p->align = 4;
- instoffset = va;
- return C_LBRA;
- }
- if(p->as == ABL){
-#ifdef CALLEEBX
- int e;
-
- if((e = fninc(p->to.sym))) {
- v += e;
- va += e;
- instoffset += e;
- }
-#endif
- if(v >= -4194304 && v <= 4194302)
- return C_SBRA;
- p->align = 2;
- instoffset = va;
- return C_LBRA;
- }
- if(p->as == ABX){
- v = va;
- if(v >= 0 && v <= 255)
- return C_SBRA;
- p->align = 2;
- instoffset = va;
- return C_LBRA;
- }
- if(v >= -256 && v <= 254)
- return C_SBRA;
- if(v >= -(2048-2) && v <= (2046+2))
- return C_LBRA;
- p->align = 2;
- instoffset = va;
- return C_GBRA;
- }
- }
- return C_GOK;
-}
-
-// as a1 a2 a3 type size param lit vers
-Optab thumboptab[] =
-{
- { ATEXT, C_ADDR, C_NONE, C_LCON, 0, 0, 0 },
- { ATEXT, C_ADDR, C_REG, C_LCON, 0, 0, 0 },
- { AMVN, C_REG, C_NONE, C_REG, 1, 2, 0 },
- { ASRL, C_REG, C_NONE, C_REG, 1, 2, 0 },
- { ACMP, C_REG, C_REG, C_NONE, 1, 2, 0 },
- { ACMN, C_REG, C_REG, C_NONE, 1, 2, 0 },
- { AADD, C_REG, C_REG, C_REG, 2, 2, 0 },
- { AADD, C_REG, C_NONE, C_REG, 2, 2, 0 },
- { AADD, C_SCON, C_REG, C_REG, 3, 2, 0 },
- { AADD, C_LCON, C_REG, C_REG, 49, 4, 0 },
- { AADD, C_GCON, C_REG, C_REG, 36, 4, 0, LFROM },
- // { AADD, C_LCON, C_NONE, C_REG, 3, 2, 0, LFROM },
- { ASRL, C_SCON, C_REG, C_REG, 4, 2, 0 },
- { ASRL, C_SCON, C_NONE, C_REG, 4, 2, 0 },
- { AADD, C_SCON, C_NONE, C_REG, 5, 2, 0 },
- { AADD, C_LCON, C_NONE, C_REG, 37, 4, 0, LFROM },
- { ACMP, C_SCON, C_REG, C_NONE, 5, 2, 0 },
- { ACMP, C_BCON, C_REG, C_NONE, 48, 6, 0 },
- { ACMP, C_LCON, C_REG, C_NONE, 39, 4, 0, LFROM },
- { AMOVW, C_SCON, C_NONE, C_REG, 5, 2, 0 },
- { AMOVW, C_BCON, C_NONE, C_REG, 47, 4, 0 },
- { AMOVW, C_LCON, C_NONE, C_REG, 38, 2, 0, LFROM },
- // { AADD, C_LCON, C_PC, C_REG, 6, 2, 0, LFROM },
- // { AADD, C_LCON, C_SP, C_REG, 6, 2, 0, LFROM },
- { AADD, C_SCON, C_NONE, C_SP, 7, 2, 0 },
- { AADD, C_LCON, C_NONE, C_SP, 40, 4, 0, LFROM },
- { AADD, C_REG, C_NONE, C_HREG, 8, 2, 0 },
- { AADD, C_HREG, C_NONE, C_REG, 8, 2, 0 },
- { AADD, C_HREG, C_NONE, C_HREG, 8, 2, 0 },
- { AMOVW, C_REG, C_NONE, C_HREG, 8, 2, 0 },
- { AMOVW, C_HREG, C_NONE, C_REG, 8, 2, 0 },
- { AMOVW, C_HREG, C_NONE, C_HREG, 8, 2, 0 },
- { ACMP, C_REG, C_HREG, C_NONE, 8, 2, 0 },
- { ACMP, C_HREG, C_REG, C_NONE, 8, 2, 0 },
- { ACMP, C_HREG, C_HREG, C_NONE, 8, 2, 0 },
- { AB, C_NONE, C_NONE, C_SBRA, 9, 2, 0, LPOOL },
- { ABEQ, C_NONE, C_NONE, C_SBRA, 10, 2, 0 },
- { ABL, C_NONE, C_NONE, C_SBRA, 11, 4, 0 },
- { ABX, C_NONE, C_NONE, C_SBRA, 12, 10, 0 },
- { AB, C_NONE, C_NONE, C_LBRA, 41, 8, 0, LPOOL },
- { ABEQ, C_NONE, C_NONE, C_LBRA, 46, 4, 0 },
- { ABL, C_NONE, C_NONE, C_LBRA, 43, 14, 0 },
- { ABX, C_NONE, C_NONE, C_LBRA, 44, 14, 0 },
- { ABEQ, C_NONE, C_NONE, C_GBRA, 42, 10, 0 },
- // { AB, C_NONE, C_NONE, C_SOREG, 13, 0, 0 },
- // { ABL, C_NONE, C_NONE, C_SOREG, 14, 0, 0 },
- { ABL, C_NONE, C_NONE, C_REG, 51, 4, 0 },
- { ABX, C_NONE, C_NONE, C_REG, 15, 8, 0 },
- { ABX, C_NONE, C_NONE, C_HREG, 15, 8, 0 },
- { ABXRET, C_NONE, C_NONE, C_REG, 45, 2, 0 },
- { ABXRET, C_NONE, C_NONE, C_HREG, 45, 2, 0 },
- { ASWI, C_NONE, C_NONE, C_LCON, 16, 2, 0 },
- { AWORD, C_NONE, C_NONE, C_LCON, 17, 4, 0 },
- { AWORD, C_NONE, C_NONE, C_GCON, 17, 4, 0 },
- { AWORD, C_NONE, C_NONE, C_ADDR, 17, 4, 0 },
- { ADWORD, C_LCON, C_NONE, C_LCON, 50, 8, 0 },
- { AMOVW, C_SAUTO, C_NONE, C_REG, 18, 2, REGSP },
- { AMOVW, C_LAUTO, C_NONE, C_REG, 33, 6, 0, LFROM },
- // { AMOVW, C_OFFPC, C_NONE, C_REG, 18, 2, REGPC, LFROM },
- { AMOVW, C_SOREG, C_NONE, C_REG, 19, 2, 0 },
- { AMOVHU, C_SOREG, C_NONE, C_REG, 19, 2, 0 },
- { AMOVBU, C_SOREG, C_NONE, C_REG, 19, 2, 0 },
- { AMOVW, C_REG, C_NONE, C_SAUTO, 20, 2, 0 },
- { AMOVW, C_REG, C_NONE, C_LAUTO, 34, 6, 0, LTO },
- { AMOVW, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVH, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVB, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVHU, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVBU, C_REG, C_NONE, C_SOREG, 21, 2, 0 },
- { AMOVW, C_REG, C_NONE, C_REG, 22, 2, 0 },
- { AMOVB, C_REG, C_NONE, C_REG, 23, 4, 0 },
- { AMOVH, C_REG, C_NONE, C_REG, 23, 4, 0 },
- { AMOVBU, C_REG, C_NONE, C_REG, 23, 4, 0 },
- { AMOVHU, C_REG, C_NONE, C_REG, 23, 4, 0 },
- { AMOVH, C_SOREG, C_NONE, C_REG, 24, 4, 0 },
- { AMOVB, C_SOREG, C_NONE, C_REG, 24, 4, 0 },
- { AMOVW, C_SACON, C_NONE, C_REG, 25, 2, 0 },
- { AMOVW, C_LACON, C_NONE, C_REG, 35, 4, 0 },
- { AMOVW, C_GACON, C_NONE, C_REG, 35, 4, 0, LFROM },
- { AMOVM, C_LCON, C_NONE, C_REG, 26, 2, 0 },
- { AMOVM, C_REG, C_NONE, C_LCON, 27, 2, 0 },
- { AMOVW, C_LOREG, C_NONE, C_REG, 28, 4, 0 },
- { AMOVH, C_LOREG, C_NONE, C_REG, 28, 4, 0 },
- { AMOVB, C_LOREG, C_NONE, C_REG, 28, 4, 0 },
- { AMOVHU, C_LOREG, C_NONE, C_REG, 28, 4, 0 },
- { AMOVBU, C_LOREG, C_NONE, C_REG, 28, 4, 0 },
- { AMOVW, C_REG, C_NONE, C_LOREG, 29, 4, 0 },
- { AMOVH, C_REG, C_NONE, C_LOREG, 29, 4, 0 },
- { AMOVB, C_REG, C_NONE, C_LOREG, 29, 4, 0 },
- { AMOVHU, C_REG, C_NONE, C_LOREG, 29, 4, 0 },
- { AMOVBU, C_REG, C_NONE, C_LOREG, 29, 4, 0 },
- { AMOVW, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM },
- { AMOVH, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM },
- { AMOVB, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM },
- { AMOVHU, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM },
- { AMOVBU, C_GOREG, C_NONE, C_REG, 28, 4, 0, LFROM },
- { AMOVW, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
- { AMOVH, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
- { AMOVB, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
- { AMOVHU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
- { AMOVBU, C_REG, C_NONE, C_GOREG, 29, 4, 0, LTO },
- { AMOVW, C_ADDR, C_NONE, C_REG, 30, 4, 0, LFROM },
- { AMOVH, C_ADDR, C_NONE, C_REG, 32, 6, 0, LFROM },
- { AMOVB, C_ADDR, C_NONE, C_REG, 32, 6, 0, LFROM },
- { AMOVHU, C_ADDR, C_NONE, C_REG, 30, 4, 0, LFROM },
- { AMOVBU, C_ADDR, C_NONE, C_REG, 30, 4, 0, LFROM },
- { AMOVW, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
- { AMOVH, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
- { AMOVB, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
- { AMOVHU, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
- { AMOVBU, C_REG, C_NONE, C_ADDR, 31, 4, 0, LTO },
-
- { AXXX, C_NONE, C_NONE, C_NONE, 0, 2, 0 },
-};
-
-#define OPCNTSZ 52
-int opcount[OPCNTSZ];
-
-// is this too pessimistic ?
-int
-brextra(Prog *p)
-{
- int c;
-
- // +2 is for padding
- if(p->as == ATEXT)
- return 0-0+2;
- if(!isbranch(p))
- diag("bad op in brextra()");
- c = thumbaclass(&p->to, p);
- switch(p->as){
- case AB:
- if(c != C_SBRA)
- return 0;
- return 8-2+2;
- case ABL:
- if(c != C_SBRA)
- return 0;
- return 14-4+2;
- case ABX:
- if(c == C_REG || c == C_HREG)
- return 0;
-#ifdef CALLEEBX
- diag("ABX $I in brextra");
-#endif
- if(c != C_SBRA)
- return 0;
- return 14-10+2;
- default:
- if(c == C_GBRA)
- return 0;
- if(c == C_LBRA)
- return 10-4+2;
- return 10-2+2;
- }
- return 0;
-}
-
-#define high(r) ((r)>=8)
-
-static int32
-mv(Prog *p, int r, int off)
-{
- int v, o;
- if(p != nil && p->cond != nil){ // in literal pool
- v = p->cond->pc - p->pc - 4;
- if(p->cond->pc & 3)
- diag("mv: bad literal pool alignment");
- if(v & 3)
- v += 2; // ensure M(4) offset
- mult(p, v, 4);
- off = v/4;
- numr(p, off, 0, 255);
- o = 0x9<<11;
- }
- else{
- numr(p, off, 0, 255);
- o = 0x4<<11;
- }
- o |= (r<<8) | off;
- return o;
-}
-
-static void
-mvcon(Prog *p, int r, int c, int32 *o1, int32 *o2)
-{
- int op = 0, n = 0;
-
- if(c >= 0 && c <= 255)
- diag("bad c in mvcon");
- if(c >= -255 && c < 0) // mv, neg
- c = -c;
- else if(c >= 256 && c <= 510){ // mv, add
- n = rand()%(511-c) + (c-255);
- c -= n;
- // n = c-255;
- // c = 255;
- op = AADD;
- }
- else{
- if(c < 0)
- diag("-ve in mvcon");
- while(!(c & 1)){
- n++;
- c >>= 1;
- }
- if(c >= 0 && c <= 255) // mv, lsl
- op = ASLL;
- else
- diag("bad shift in mvcon");
- }
- *o1 = mv(p, r, c);
- switch(op){
- case 0:
- *o2 = (1<<14) | (9<<6) | (r<<3) | r;
- break;
- case AADD:
- *o2 = (6<<11) | (r<<8) | n;
- break;
- case ASLL:
- *o2 = (n<<6) | (r<<3) | r;
- break;
- }
-}
-
-static int32
-mvlh(int rs, int rd)
-{
- int o = 0x46<<8;
-
- if(high(rs)){
- rs -= 8;
- o |= 1<<6;
- }
- if(high(rd)){
- rd -= 8;
- o |= 1<<7;
- }
- o |= (rs<<3) | rd;
- return o;
-}
-
-void
-thumbbuildop()
-{
- int i, n, r;
- Optab *optab = thumboptab;
- Oprang *oprange = thumboprange;
-
- for(n=0; optab[n].as != AXXX; n++)
- ;
- qsort(optab, n, sizeof(optab[0]), ocmp);
- for(i=0; i<n; i++) {
- r = optab[i].as;
- oprange[r].start = optab+i;
- while(optab[i].as == r)
- i++;
- oprange[r].stop = optab+i;
- i--;
-
- switch(r)
- {
- default:
- break;
- case ABEQ:
- oprange[ABNE] = oprange[r];
- oprange[ABCS] = oprange[r];
- oprange[ABHS] = oprange[r];
- oprange[ABCC] = oprange[r];
- oprange[ABLO] = oprange[r];
- oprange[ABMI] = oprange[r];
- oprange[ABPL] = oprange[r];
- oprange[ABVS] = oprange[r];
- oprange[ABVC] = oprange[r];
- oprange[ABHI] = oprange[r];
- oprange[ABLS] = oprange[r];
- oprange[ABGE] = oprange[r];
- oprange[ABLT] = oprange[r];
- oprange[ABGT] = oprange[r];
- oprange[ABLE] = oprange[r];
- break;
- case AMVN:
- oprange[AADC] = oprange[r];
- oprange[ASBC] = oprange[r];
- oprange[AMUL] = oprange[r];
- oprange[AAND] = oprange[r];
- oprange[AEOR] = oprange[r];
- oprange[AORR] = oprange[r];
- oprange[ABIC] = oprange[r];
- oprange[AMULU] = oprange[r];
- break;
- case ACMN:
- oprange[ATST] = oprange[r];
- break;
- case ASRL:
- oprange[ASRA] = oprange[r];
- oprange[ASLL] = oprange[r];
- break;
- case AADD:
- oprange[ASUB] = oprange[r];
- break;
- }
- }
-}
-
-void
-thumbasmout(Prog *p, Optab *o)
-{
- int32 o1, o2, o3, o4, o5, o6, o7, v;
- int r, rf, rt;
-
- rf = p->from.reg;
- rt = p->to.reg;
- r = p->reg;
- o1 = o2 = o3 = o4 = o5 = o6 = o7 = 0;
-if(debug['P']) print("%ux: %P type %d %d\n", (uint32)(p->pc), p, o->type, p->align);
- opcount[o->type] += o->size;
- switch(o->type) {
- default:
- diag("unknown asm %d", o->type);
- prasm(p);
- break;
- case 0: /* pseudo ops */
-if(debug['G']) print("%ux: %s: thumb\n", (uint32)(p->pc), p->from.sym->name);
- break;
- case 1: /* op R, -, R or op R, R, - */
- o1 = thumboprr(p->as);
- if(rt == NREG)
- rt = r;
- lowreg(p, rf);
- lowreg(p, rt);
- o1 |= (0x10<<10) | (rf<<3) | rt;
- break;
- case 2: /* add/sub R, R, R or add/sub R, -, R */
- o1 = p->as == AADD ? 0x0<<9 : 0x1<<9;
- if(r == NREG)
- r = rt;
- lowreg(p, rf);
- lowreg(p, r);
- lowreg(p, rt);
- o1 |= (0x6<<10) | (rf<<6) | (r<<3) | rt;
- break;
- case 3: /* add/sub $I, R, R or add/sub $I, -, R */
- thumbaclass(&p->from, p);
- o1 = p->as == AADD ? 0x0<<9 : 0x1<<9;
- if(r == NREG)
- r = rt;
- numr(p, instoffset, 0, 7);
- lowreg(p, r);
- lowreg(p, rt);
- o1 |= (0x7<<10) | (instoffset<<6) | (r<<3) | rt;
- break;
- case 4: /* shift $I, R, R or shift $I, -, R */
- thumbaclass(&p->from, p);
- if(instoffset < 0)
- diag("negative shift in thumbasmout");
- instoffset %= 32;
- o1 = thumbopri(p->as);
- if(r == NREG)
- r = rt;
- numr(p, instoffset, 0, 31);
- lowreg(p, r);
- lowreg(p, rt);
- o1 |= (0x0<<13) | (instoffset<<6) | (r<<3) | rt;
- break;
- case 5: /* add/sub/mov $I, -, R or cmp $I, R, - */
- thumbaclass(&p->from, p);
- o1 = thumbopri(p->as);
- if(rt == NREG)
- rt = r;
- numr(p, instoffset, 0, 255);
- lowreg(p, rt);
- o1 |= (0x1<<13) | (rt<<8) | instoffset;
- break;
- case 6: /* add $I, PC/SP, R */
- if(p->as == ASUB)
- diag("subtract in add $I, PC/SP, R");
- thumbaclass(&p->from, p);
- o1 = r == REGSP ? 0x1<<11 : 0x0<<11;
- numr(p, instoffset, 0, 255);
- regis(p, r, REGSP, REGPC);
- lowreg(p, rt);
- o1 |= (0xa<<12) | (rt<<8) | instoffset;
- break;
- case 7: /* add, sub $I, SP */
- thumbaclass(&p->from, p);
- o1 = p->as == AADD ? 0x0<<7 : 0x1<<7;
- numr(p, instoffset, 0, 508);
- mult(p, instoffset, 4);
- regis(p, rt, REGSP, REGSP);
- o1 |= (0xb0<<8) | (instoffset>>2);
- break;
- case 8: /* add/mov/cmp R, R where at least 1 reg is high */
- o1 = 0;
- if(rt == NREG)
- rt = r;
- if(high(rf)){
- o1 |= 1<<6;
- rf -= 8;
- }
- if(high(rt)){
- o1 |= 2<<6;
- rt -= 8;
- }
- if(o1 == 0)
- diag("no high register(%P)", p);
- o1 |= thumbophh(p->as);
- o1 |= (0x11<<10) | (rf<<3) | rt;
- break;
- case 9: /* B $I */
- thumbaclass(&p->to, p);
- numr(p, instoffset, -2048, 2046);
- o1 = (0x1c<<11) | ((instoffset>>1)&0x7ff);
- break;
- case 10: /* Bcc $I */
- thumbaclass(&p->to, p);
- numr(p, instoffset, -256, 254);
- o1 = thumbopbra(p->as);
- o1 |= (0xd<<12) | ((instoffset>>1)&0xff);
- break;
- case 11: /* BL $I */
- thumbaclass(&p->to, p);
- numr(p, instoffset, -4194304, 4194302);
- o1 = (0x1e<<11) | ((instoffset>>12)&0x7ff);
- o2 = (0x1f<<11) | ((instoffset>>1)&0x7ff);
- break;
- case 12: /* BX $I */
-#ifdef CALLEEBX
- diag("BX $I case");
-#endif
- thumbaclass(&p->to, p);
- if(p->to.sym->thumb)
- instoffset |= 1; // T bit
- o1 = mvlh(REGPC, REGTMPT);
- o2 = (0x6<<11) | (REGTMPT<<8) | 7; // add 7, RTMP (T bit + PC offset)
- o3 = mvlh(REGTMPT, REGLINK);
- o4 = mv(nil, REGTMPT, instoffset);
- o5 = (0x11c<<6) | (REGTMPT<<3);
- // o1 = mv(nil, REGTMPT, v);
- // o2 = (0x11b<<6) | (REGPC<<3) | REGLINK;
- // o3 = (0x11c<<6) | (REGTMPT<<3);
- break;
- case 13: /* B O(R) */
- diag("B O(R)");
- break;
- case 14: /* BL O(R) */
- diag("BL O(R)");
- break;
- case 15: /* BX R */
- o1 = mvlh(REGPC, REGTMPT);
- o2 = (0x6<<11) | (REGTMPT<<8) | 5; // add 5, RTMP (T bit + PC offset)
- o3 = mvlh(REGTMPT, REGLINK);
- o4 = 0;
- if(high(rt)){
- rt -= 8;
- o4 |= 1<<6;
- }
- o4 |= (0x8e<<7) | (rt<<3);
- // o1 = (0x11c<<6) | (rt<<3);
- break;
- case 16: /* SWI $I */
- thumbaclass(&p->to, p);
- numr(p, instoffset, 0, 255);
- o1 = (0xdf<<8) | instoffset;
- break;
- case 17: /* AWORD */
- thumbaclass(&p->to, p);
- o1 = instoffset&0xffff;
- o2 = (instoffset>>16)&0xffff;
- break;
- case 18: /* AMOVW O(SP), R and AMOVW O(PC), R */
- thumbaclass(&p->from, p);
- rf = o->param;
- o1 = rf == REGSP ? 0x13<<11 : 0x9<<11;
- regis(p, rf, REGSP, REGPC);
- lowreg(p, rt);
- mult(p, instoffset, 4);
- numr(p, instoffset/4, 0, 255);
- o1 |= (rt<<8) | (instoffset/4);
- break;
- case 19: /* AMOVW... O(R), R */
- thumbaclass(&p->from, p);
- o1 = thumbopmv(p->as, 1);
- v = 4;
- if(p->as == AMOVHU)
- v = 2;
- else if(p->as == AMOVBU)
- v = 1;
- mult(p, instoffset, v);
- lowreg(p, rf);
- lowreg(p, rt);
- numr(p, instoffset/v, 0, 31);
- o1 |= ((instoffset/v)<<6) | (rf<<3) | rt;
- break;
- case 20: /* AMOVW R, O(SP) */
- thumbaclass(&p->to, p);
- o1 = 0x12<<11;
- if(rt != NREG) regis(p, rt, REGSP, REGSP);
- lowreg(p, rf);
- mult(p, instoffset, 4);
- numr(p, instoffset/4, 0, 255);
- o1 |= (rf<<8) | (instoffset/4);
- break;
- case 21: /* AMOVW... R, O(R) */
- thumbaclass(&p->to, p);
- o1 = thumbopmv(p->as, 0);
- v = 4;
- if(p->as == AMOVHU || p->as == AMOVH)
- v = 2;
- else if(p->as == AMOVBU || p->as == AMOVB)
- v = 1;
- lowreg(p, rf);
- lowreg(p, rt);
- mult(p, instoffset, v);
- numr(p, instoffset/v, 0, 31);
- o1 |= ((instoffset/v)<<6) | (rt<<3) | rf;
- break;
- case 22: /* AMOVW R, R -> ASLL $0, R, R */
- o1 = thumbopri(ASLL);
- lowreg(p, rf);
- lowreg(p, rt);
- o1 |= (0x0<<13) | (rf<<3) | rt;
- break;
- case 23: /* AMOVB/AMOVH/AMOVBU/AMOVHU R, R */
- o1 = thumbopri(ASLL);
- o2 = p->as == AMOVB || p->as == AMOVH ? thumbopri(ASRA) : thumbopri(ASRL);
- v = p->as == AMOVB || p->as == AMOVBU ? 24 : 16;
- lowreg(p, rf);
- lowreg(p, rt);
- o1 |= (0x0<<13) | (v<<6) | (rf<<3) | rt;
- o2 |= (0x0<<13) | (v<<6) | (rt<<3) | rt;
- break;
- case 24: /* AMOVH/AMOVB O(R), R -> AMOVH/AMOVB [R, R], R */
- thumbaclass(&p->from, p);
- lowreg(p, rf);
- lowreg(p, rt);
- if(rf == rt)
- r = REGTMPT;
- else
- r = rt;
- if(p->as == AMOVB)
- numr(p, instoffset, 0, 31);
- else{
- mult(p, instoffset, 2);
- numr(p, instoffset, 0, 62);
- }
- o1 = mv(p, r, instoffset);
- o2 = p->as == AMOVH ? 0x2f<<9 : 0x2b<<9;
- o2 |= (r<<6) | (rf<<3) | rt;
- break;
- case 25: /* MOVW $sacon, R */
- thumbaclass(&p->from, p);
-// print("25: %d %d %d %d\n", instoffset, rf, r, rt);
- if(rf == NREG)
- rf = REGSP;
- lowreg(p, rt);
- if(rf == REGSP){
- mult(p, instoffset, 4);
- numr(p, instoffset>>2, 0, 255);
- o1 = (0x15<<11) | (rt<<8) | (instoffset>>2); // add $O, SP, R
- }
- else if(rf == rt){
- numr(p, instoffset, 0, 255);
- o1 = (0x6<<11) | (rt<<8) | instoffset; // add $O, R
- }
- else{
- lowreg(p, rf);
- numr(p, instoffset, 0, 7);
- o1 = (0xe<<9) | (instoffset<<6) | (rf<<3) | rt; // add $O, Rs, Rd
- }
- break;
- case 26: /* AMOVM $c, oreg -> stmia */
- lowreg(p, rt);
- numr(p, p->from.offset, -256, 255);
- o1 = (0x18<<11) | (rt<<8) | (p->from.offset&0xff);
- break;
- case 27: /* AMOVM oreg, $c ->ldmia */
- lowreg(p, rf);
- numr(p, p->to.offset, -256, 256);
- o1 = (0x19<<11) | (rf<<8) | (p->to.offset&0xff);
- break;
- case 28: /* AMOV* O(R), R -> AMOV* [R, R], R (offset large) */
- thumbaclass(&p->from, p);
- lowreg(p, rf);
- lowreg(p, rt);
- if(rf == rt)
- r = REGTMPT;
- else
- r = rt;
- o1 = mv(p, r, instoffset);
- o2 = thumboprrr(p->as, 1);
- o2 |= (r<<6) | (rf<<3) | rt;
- break;
- case 29: /* AMOV* R, O(R) -> AMOV* R, [R, R] (offset large) */
- thumbaclass(&p->to, p);
- lowreg(p, rf);
- lowreg(p, rt);
- if(rt == REGTMPT){ // used as tmp reg
- if(instoffset >= 0 && instoffset <= 255){
- o1 = (1<<13) | (2<<11) | (rt<<8) | instoffset; // add $O, R7
- o2 = thumbopirr(p->as, 0);
- o2 |= (0<<6) | (rt<<3) | rf; // mov* R, 0(R)
- }
- else
- diag("big offset - case 29");
- }
- else{
- o1 = mv(p, REGTMPT, instoffset);
- o2 = thumboprrr(p->as, 0);
- o2 |= (REGTMPT<<6) | (rt<<3) | rf;
- }
- break;
- case 30: /* AMOVW... *addr, R */
- diag("likely broken"); // does this still refer to SB?
- thumbaclass(&p->from, p);
- o1 = mv(p, rt, instoffset); // MOV addr, rtmp
- o2 = thumbopmv(p->as, 1);
- lowreg(p, rt);
- o2 |= (rt<<3) | rt; // MOV* 0(rtmp), R
- break;
- case 31: /* AMOVW... R, *addr */
- diag("likely broken"); // does this still refer to SB?
- thumbaclass(&p->to, p);
- o1 = mv(p, REGTMPT, instoffset);
- o2 = thumbopmv(p->as, 0);
- lowreg(p, rf);
- o2 |= (REGTMPT<<3) | rf;
- break;
- case 32: /* AMOVH/AMOVB *addr, R -> AMOVH/AMOVB [R, R], R */
- thumbaclass(&p->from, p);
- o1 = mv(p, rt, instoffset);
- lowreg(p, rt);
- o2 = mv(nil, REGTMPT, 0);
- o3 = p->as == AMOVH ? 0x2f<<9 : 0x2b<<9;
- o3 |= (REGTMPT<<6) | (rt<<3) | rt;
- break;
- case 33: /* AMOVW O(SP), R (O large) */
- thumbaclass(&p->from, p);
- lowreg(p, rt);
- o1 = mv(p, rt, instoffset);
- o2 = (0x111<<6) | (REGSP-8)<<3 | rt; // add SP, rt
- o3 = thumbopmv(p->as, 1);
- o3 |= (rt<<3) | rt;
- break;
- case 34: /* AMOVW R, O(SP) (O large) */
- thumbaclass(&p->to, p);
- lowreg(p, rf);
- o1 = mv(p, REGTMPT, instoffset);
- o2 = (0x111<<6) | (REGSP-8)<<3 | REGTMPT; // add SP, REGTMP
- o3 = thumbopmv(p->as, 0);
- o3 |= (REGTMPT<<3) | rf;
- break;
- case 35: /* AMOVW $lacon, R */
- thumbaclass(&p->from, p);
- lowreg(p, rt);
- if(rf == NREG)
- rf = REGSP;
- if(rf == rt)
- rf = r = REGTMPT;
- else
- r = rt;
-// print("35: io=%d rf=%d rt=%d\n", instoffset, rf, rt);
- o1 = mv(p, r, instoffset); // mov O, Rd
- if(high(rf))
- o2 = (0x44<<8) | (0x1<<6) | ((rf-8)<<3) | rt; // add Rs, Rd
- else
- o2 = (0x6<<10) | (rf<<6) | (rt<<3) | rt; // add Rs, Rd
- break;
- case 36: /* AADD/ASUB $i, r, r when $i too big */
- thumbaclass(&p->from, p);
- lowreg(p, r);
- lowreg(p, rt);
- o1 = mv(p, REGTMPT, instoffset);
- o2 = p->as == AADD ? 0xc<<9 : 0xd<<9;
- o2 |= (REGTMPT<<6) | (r<<3) | rt;
- break;
- case 37: /* AADD/ASUB $i, r when $i too big */
- thumbaclass(&p->from, p);
- lowreg(p, rt);
- o1 = mv(p, REGTMPT, instoffset);
- o2 = p->as == AADD ? 0xc<<9 : 0xd<<9;
- o2 |= (REGTMPT<<6) | (rt<<3) | rt;
- break;
- case 38: /* AMOVW $i, r when $i too big */
- thumbaclass(&p->from, p);
- lowreg(p, rt);
- o1 = mv(p, rt, instoffset);
- break;
- case 39: /* ACMP $i, r when $i too big */
- thumbaclass(&p->from, p);
- lowreg(p, r);
- o1 = mv(p, REGTMPT, instoffset);
- o2 = (0x10a<<6) | (REGTMPT<<3) | r;
- break;
- case 40: /* add, sub $I, SP when $I large*/
- thumbaclass(&p->from, p);
- if(p->as == ASUB)
- instoffset = -instoffset;
- o1 = mv(p, REGTMPT, instoffset);
- o2 = (0x112<<6) | (REGTMPT<<3) | (REGSP-8);
- regis(p, rt, REGSP, REGSP);
- break;
- case 41: /* BL LBRA */
- thumbaclass(&p->to, p);
- o1 = (0x9<<11) | (REGTMPT<<8); // mov 0(pc), r7
- o2 = mvlh(REGTMPT, REGPC); // mov r7, pc
- o3 = instoffset&0xffff; // $lab
- o4 = (instoffset>>16)&0xffff;
- break;
- case 42: /* Bcc GBRA */
- thumbaclass(&p->to, p);
- o1 = (0xd<<12) | thumbopbra(relinv(p->as)) | (6>>1); // bccnot
- // ab lbra
- o2 = (0x9<<11) | (REGTMPT<<8); // mov 0(pc), r7
- o3 = mvlh(REGTMPT, REGPC); // mov r7, pc
- o4 = instoffset&0xffff; // $lab
- o5 = (instoffset>>16)&0xffff;
- break;
- case 43: /* BL LBRA */
- thumbaclass(&p->to, p);
- o1 = mvlh(REGPC, REGTMPT); // mov pc, r7
- o2 = (0x6<<11) | (REGTMPT<<8) | 10; // add 10, r7
- o3 = mvlh(REGTMPT, REGLINK); // mov r7, lr
- o4 = (0x9<<11) | (REGTMPT<<8); // mov o(pc), r7
- o5 = mvlh(REGTMPT, REGPC); // mov r7, pc
- o6 = instoffset&0xffff; // $lab
- o7 = (instoffset>>16)&0xffff;
- break;
- case 44: /* BX LBRA */
-#ifdef CALLEEBX
- diag("BX LBRA case");
-#endif
- thumbaclass(&p->to, p);
- if(p->to.sym->thumb)
- instoffset |= 1; // T bit
- o1 = mvlh(REGPC, REGTMPT); // mov pc, r7
- o2 = (0x6<<11) | (REGTMPT<<8) | 11; // add 11, r7
- o3 = mvlh(REGTMPT, REGLINK); // mov r7, lr
- o4 = (0x9<<11) | (REGTMPT<<8); // mov o(pc), r7
- o5 = (0x11c<<6) | (REGTMPT<<3); // bx r7
- o6 = instoffset&0xffff; // $lab
- o7 = (instoffset>>16)&0xffff;
- break;
- case 45: /* BX R when returning from fn */
- o1 = 0;
- if(high(rt)){
- rt -= 8;
- o1 |= 1<<6;
- }
- o1 |= (0x8e<<7) | (rt<<3);
- break;
- case 46: /* Bcc LBRA */
- thumbaclass(&p->to, p);
- o1 = (0xd<<12) | thumbopbra(relinv(p->as)) | (0>>1); // bccnot
- // ab lbra
- instoffset -= 2;
- numr(p, instoffset, -2048, 2046);
- o2 = (0x1c<<11) | ((instoffset>>1)&0x7ff);
- break;
- case 47: /* mov $i, R where $i can be built */
- thumbaclass(&p->from, p);
- mvcon(p, rt, instoffset, &o1, &o2);
- break;
- case 48: /* ACMP $i, r when $i built up */
- thumbaclass(&p->from, p);
- lowreg(p, r);
- mvcon(p, REGTMPT, instoffset, &o1, &o2);
- o3 = (0x10a<<6) | (REGTMPT<<3) | r;
- break;
- case 49: /* AADD $i, r, r when $i is between 0 and 255 - could merge with case 36 */
- thumbaclass(&p->from, p);
- lowreg(p, r);
- lowreg(p, rt);
- numr(p, instoffset, 0, 255);
- o1 = mv(p, REGTMPT, instoffset);
- o2 = p->as == AADD ? 0xc<<9 : 0xd<<9;
- o2 |= (REGTMPT<<6) | (r<<3) | rt;
- break;
- case 50: /* ADWORD */
- thumbaclass(&p->from, p);
- o1 = instoffset&0xffff;
- o2 = (instoffset>>16)&0xffff;
- thumbaclass(&p->to, p);
- o3 = instoffset&0xffff;
- o4 = (instoffset>>16)&0xffff;
- break;
- case 51: /* BL r */
- o1 = mvlh(REGPC, REGLINK); // mov pc, lr
- o2 = mvlh(rt, REGPC); // mov r, pc
- break;
- }
-
- v = p->pc;
- switch(o->size) {
- default:
- if(debug['a'])
- Bprint(&bso, " %.8ux:\t\t%P\n", v, p);
- break;
- case 2:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux\t%P\n", v, o1, p);
- hputl(o1);
- break;
- case 4:
- if(debug['a'])
- Bprint(&bso, " %.8ux: %.8ux %.8ux\t%P\n", v, o1, o2, p);
- hputl(o1);
- hputl(o2);
- break;
- case 6:
- if(debug['a'])
- Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, p);
- hputl(o1);
- hputl(o2);
- hputl(o3);
- break;
- case 8:
- if(debug['a'])
- Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, p);
- hputl(o1);
- hputl(o2);
- hputl(o3);
- hputl(o4);
- break;
- case 10:
- if(debug['a'])
- Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, o5, p);
- hputl(o1);
- hputl(o2);
- hputl(o3);
- hputl(o4);
- hputl(o5);
- break;
- case 12:
- if(debug['a'])
- Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, o5, o6, p);
- hputl(o1);
- hputl(o2);
- hputl(o3);
- hputl(o4);
- hputl(o5);
- hputl(o6);
- break;
- case 14:
- if(debug['a'])
- Bprint(&bso, "%.8ux: %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux %.8ux\t%P\n", v, o1, o2, o3, o4, o5, o6, o7, p);
- hputl(o1);
- hputl(o2);
- hputl(o3);
- hputl(o4);
- hputl(o5);
- hputl(o6);
- hputl(o7);
- break;
- }
- if(debug['G']){
- if(o->type == 17){
- print("%x: word %d\n", p->pc, (o2<<16)+o1);
- return;
- }
- if(o->type == 50){
- print("%x: word %d\n", p->pc, (o2<<16)+o1);
- print("%x: word %d\n", p->pc, (o4<<16)+o3);
- return;
- }
- if(o->size > 0) dis(o1, p->pc);
- if(o->size > 2) dis(o2, p->pc+2);
- if(o->size > 4) dis(o3, p->pc+4);
- if(o->size > 6) dis(o4, p->pc+6);
- if(o->size > 8) dis(o5, p->pc+8);
- if(o->size > 10) dis(o6, p->pc+10);
- if(o->size > 12) dis(o7, p->pc+12);
- // if(o->size > 14) dis(o8, p->pc+14);
- }
-}
-
-static int32
-thumboprr(int a)
-{
- switch(a) {
- case AMVN: return 0xf<<6;
- case ACMP: return 0xa<<6;
- case ACMN: return 0xb<<6;
- case ATST: return 0x8<<6;
- case AADC: return 0x5<<6;
- case ASBC: return 0x6<<6;
- case AMUL:
- case AMULU: return 0xd<<6;
- case AAND: return 0x0<<6;
- case AEOR: return 0x1<<6;
- case AORR: return 0xc<<6;
- case ABIC: return 0xe<<6;
- case ASRL: return 0x3<<6;
- case ASRA: return 0x4<<6;
- case ASLL: return 0x2<<6;
- }
- diag("bad thumbop oprr %d", a);
- prasm(curp);
- return 0;
-}
-
-static int32
-thumbopirr(int a, int ld)
-{
- if(ld)
- diag("load in thumbopirr");
- switch(a){
- case AMOVW: return 0xc<<11;
- case AMOVH:
- case AMOVHU: return 0x10<<11;
- case AMOVB:
- case AMOVBU: return 0xe<<11;
- }
- return 0;
-}
-
-static int32
-thumboprrr(int a, int ld)
-{
- if(ld){
- switch(a){
- case AMOVW: return 0x2c<<9;
- case AMOVH: return 0x2f<<9;
- case AMOVB: return 0x2b<<9;
- case AMOVHU: return 0x2d<<9;
- case AMOVBU: return 0x2e<<9;
- }
- }
- else{
- switch(a){
- case AMOVW: return 0x28<<9;
- case AMOVHU:
- case AMOVH: return 0x29<<9;
- case AMOVBU:
- case AMOVB: return 0x2a<<9;
- }
- }
- diag("bad thumbop oprrr %d", a);
- prasm(curp);
- return 0;
-}
-
-static int32
-thumbopri(int a)
-{
- switch(a) {
- case ASRL: return 0x1<<11;
- case ASRA: return 0x2<<11;
- case ASLL: return 0x0<<11;
- case AADD: return 0x2<<11;
- case ASUB: return 0x3<<11;
- case AMOVW: return 0x0<<11;
- case ACMP: return 0x1<<11;
- }
- diag("bad thumbop opri %d", a);
- prasm(curp);
- return 0;
-}
-
-static int32
-thumbophh(int a)
-{
- switch(a) {
- case AADD: return 0x0<<8;
- case AMOVW: return 0x2<<8;
- case ACMP: return 0x1<<8;
- }
- diag("bad thumbop ophh %d", a);
- prasm(curp);
- return 0;
-}
-
-static int32
-thumbopbra(int a)
-{
- switch(a) {
- case ABEQ: return 0x0<<8;
- case ABNE: return 0x1<<8;
- case ABCS: return 0x2<<8;
- case ABHS: return 0x2<<8;
- case ABCC: return 0x3<<8;
- case ABLO: return 0x3<<8;
- case ABMI: return 0x4<<8;
- case ABPL: return 0x5<<8;
- case ABVS: return 0x6<<8;
- case ABVC: return 0x7<<8;
- case ABHI: return 0x8<<8;
- case ABLS: return 0x9<<8;
- case ABGE: return 0xa<<8;
- case ABLT: return 0xb<<8;
- case ABGT: return 0xc<<8;
- case ABLE: return 0xd<<8;
- }
- diag("bad thumbop opbra %d", a);
- prasm(curp);
- return 0;
-}
-
-static int32
-thumbopmv(int a, int ld)
-{
- switch(a) {
- case AMOVW: return (ld ? 0xd : 0xc)<<11;
- case AMOVH:
- case AMOVHU: return (ld ? 0x11: 0x10)<<11;
- case AMOVB:
- case AMOVBU: return (ld ? 0xf : 0xe)<<11;
- }
- diag("bad thumbop opmv %d", a);
- prasm(curp);
- return 0;
-}
-
-static void
-lowreg(Prog *p, int r)
-{
- if(high(r))
- diag("high reg [%P]", p);
-}
-
-static void
-mult(Prog *p, int n, int m)
-{
- if(m*(n/m) != n)
- diag("%d not M(%d) [%P]", n, m, p);
-}
-
-static void
-numr(Prog *p, int n, int min, int max)
-{
- if(n < min || n > max)
- diag("%d not in %d-%d [%P]", n, min, max, p);
-}
-
-static void
-regis(Prog *p, int r, int r1, int r2)
-{
- if(r != r1 && r != r2)
- diag("reg %d not %d or %d [%P]", r, r1, r2, p);
-}
-
-void
-hputl(int n)
-{
- cbp[1] = n>>8;
- cbp[0] = n;
- cbp += 2;
- cbc -= 2;
- if(cbc <= 0)
- cflush();
-}
-
-void
-thumbcount()
-{
- int i, c = 0, t = 0;
-
- for (i = 0; i < OPCNTSZ; i++)
- t += opcount[i];
- if(t == 0)
- return;
- for (i = 0; i < OPCNTSZ; i++){
- c += opcount[i];
- print("%d: %d %d %d%%\n", i, opcount[i], c, (opcount[i]*100+t/2)/t);
- }
-}
-
-char *op1[] = { "lsl", "lsr", "asr" };
-char *op2[] = { "add", "sub" };
-char *op3[] = { "movw", "cmp", "add", "sub" };
-char *op4[] = { "and", "eor", "lsl", "lsr", "asr", "adc", "sbc", "ror",
- "tst", "neg", "cmp", "cmpn", "or", "mul", "bitc", "movn" };
-char *op5[] = { "add", "cmp", "movw", "bx" };
-char *op6[] = { "smovw", "smovh", "smovb", "lmovb", "lmovw", "lmovhu", "lmovbu", "lmovh" };
-char *op7[] = { "smovw", "lmovw", "smovb", "lmovbu" };
-char *op8[] = { "smovh", "lmovhu" };
-char *op9[] = { "smovw", "lmovw" };
-char *op10[] = { "push", "pop" };
-char *op11[] = { "stmia", "ldmia" };
-
-char *cond[] = { "eq", "ne", "hs", "lo", "mi", "pl", "vs", "vc",
- "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" };
-
-#define B(h, l) bits(i, h, l)
-#define IMM(h, l) B(h, l)
-#define REG(h, l) reg(B(h, l))
-#define LHREG(h, l, lh) lhreg(B(h, l), B(lh, lh))
-#define COND(h, l) cond[B(h, l)]
-#define OP1(h, l) op1[B(h, l)]
-#define OP2(h, l) op2[B(h, l)]
-#define OP3(h, l) op3[B(h, l)]
-#define OP4(h, l) op4[B(h, l)]
-#define OP5(h, l) op5[B(h, l)]
-#define OP6(h, l) op6[B(h, l)]
-#define OP7(h, l) op7[B(h, l)]
-#define OP8(h, l) op8[B(h, l)]
-#define OP9(h, l) op9[B(h, l)]
-#define OP10(h, l) op10[B(h, l)]
-#define OP11(h, l) op11[B(h, l)]
-#define SBZ(h, l) if(IMM(h, l) != 0) diag("%x: %x bits %d,%d not zero", pc, i, h, l)
-#define SNBZ(h, l) if(IMM(h, l) == 0) diag("%x: %x bits %d,%d zero", pc, i, h, l)
-#define SBO(h, l) if(IMM(h, l) != 1) diag("%x: %x bits %d,%d not one", pc, i, h, l)
-
-static int
-bits(int i, int h, int l)
-{
- if(h < l)
- diag("h < l in bits");
- return (i&(((1<<(h-l+1))-1)<<l))>>l;
-}
-
-static char *
-reg(int r)
-{
- static char s[4][4];
- static int i = 0;
-
- if(r < 0 || r > 7)
- diag("register %d out of range", r);
- i++;
- if(i == 4)
- i = 0;
- sprint(s[i], "r%d", r);
- return s[i];
-}
-
-static char *regnames[] = { "sp", "lr", "pc" };
-
-static char *
-lhreg(int r, int lh)
-{
- static char s[4][4];
- static int i = 0;
-
- if(lh == 0)
- return reg(r);
- if(r < 0 || r > 7)
- diag("high register %d out of range", r);
- i++;
- if(i == 4)
- i = 0;
- if(r >= 5)
- sprint(s[i], "%s", regnames[r-5]);
- else
- sprint(s[i], "r%d", r+8);
- return s[i];
-}
-
-static void
-illegal(int i, int pc)
-{
- diag("%x: %x illegal instruction", pc, i);
-}
-
-static void
-dis(int i, int pc)
-{
- static int lasto;
- int o, l;
- char *op;
-
- print("%x: %x: ", pc, i);
- if(i&0xffff0000)
- illegal(i, pc);
- o = B(15, 13);
- switch(o){
- case 0:
- o = B(12, 11);
- switch(o){
- case 0:
- case 1:
- case 2:
- print("%s %d, %s, %s\n", OP1(12, 11), IMM(10, 6), REG(5, 3), REG(2, 0));
- return;
- case 3:
- if(B(10, 10) == 0)
- print("%s %s, %s, %s\n", OP2(9, 9), REG(8, 6), REG(5, 3), REG(2, 0));
- else
- print("%s %d, %s, %s\n", OP2(9, 9), IMM(8, 6), REG(5, 3), REG(2, 0));
- return;
- }
- case 1:
- print("%s %d, %s\n", OP3(12, 11), IMM(7, 0), REG(10, 8));
- return;
- case 2:
- o = B(12, 10);
- if(o == 0){
- print("%s %s, %s\n", OP4(9, 6), REG(5, 3), REG(2, 0));
- return;
- }
- if(o == 1){
- o = B(9, 8);
- if(o == 3){
- SBZ(7, 7);
- SBZ(2, 0);
- print("%s %s\n", OP5(9, 8), LHREG(5, 3, 6));
- return;
- }
- SNBZ(7, 6);
- print("%s %s, %s\n", OP5(9, 8), LHREG(5, 3, 6), LHREG(2, 0, 7));
- return;
- }
- if(o == 2 || o == 3){
- print("movw %d(pc)[%x], %s\n", 4*IMM(7, 0), 4*IMM(7, 0)+pc+4, REG(10, 8));
- return;
- }
- op = OP6(11, 9);
- if(*op == 'l')
- print("%s [%s, %s], %s\n", op+1, REG(8, 6), REG(5, 3), REG(2, 0));
- else
- print("%s %s, [%s, %s]\n", op+1, REG(2, 0), REG(8, 6), REG(5, 3));
- return;
- case 3:
- op = OP7(12, 11);
- if(B(12, 11) == 0 || B(12,11) == 1)
- l = 4;
- else
- l = 1;
- if(*op == 'l')
- print("%s %d(%s), %s\n", op+1, l*IMM(10, 6), REG(5, 3), REG(2, 0));
- else
- print("%s %s, %d(%s)\n", op+1, REG(2, 0), l*IMM(10, 6), REG(5, 3));
- return;
- case 4:
- if(B(12, 12) == 0){
- op = OP8(11, 11);
- if(*op == 'l')
- print("%s %d(%s), %s\n", op+1, 2*IMM(10, 6), REG(5, 3), REG(2, 0));
- else
- print("%s %s, %d(%s)\n", op+1, REG(2, 0), 2*IMM(10, 6), REG(5, 3));
- return;
- }
- op = OP9(11, 11);
- if(*op == 'l')
- print("%s %d(sp), %s\n", op+1, 4*IMM(7, 0), REG(10, 8));
- else
- print("%s %s, %d(sp)\n", op+1, REG(10, 8), 4*IMM(7, 0));
- return;
- case 5:
- if(B(12, 12) == 0){
- if(B(11, 11) == 0)
- print("add %d, pc, %s\n", 4*IMM(7, 0), REG(10, 8));
- else
- print("add %d, sp, %s\n", 4*IMM(7, 0), REG(10, 8));
- return;
- }
- if(B(11, 8) == 0){
- print("%s %d, sp\n", OP2(7, 7), 4*IMM(6, 0));
- return;
- }
- SBO(10, 10);
- SBZ(9, 9);
- if(B(8, 8) == 0)
- print("%s sp, %d\n", OP10(11, 11), IMM(7, 0));
- else
- print("%s sp, %d|15\n", OP10(11, 11), IMM(7, 0));
- return;
- case 6:
- if(B(12, 12) == 0){
- print("%s %s, %d\n", OP11(11, 11), REG(10, 8), IMM(7, 0));
- return;
- }
- if(B(11, 8) == 0xf){
- print("swi %d\n", IMM(7, 0));
- return;
- }
- o = IMM(7, 0);
- if(o&0x80)
- o |= 0xffffff00;
- o = pc+4+(o<<1);
- print("b%s %x\n", COND(11, 8), o);
- return;
- case 7:
- o = B(12, 11);
- switch(o){
- case 0:
- o = IMM(10, 0);
- if(o&0x400)
- o |= 0xfffff800;
- o = pc+4+(o<<1);
- print("b %x\n", o);
- return;
- case 1:
- illegal(i, pc);
- return;
- case 2:
- lasto = IMM(10, 0);
- print("bl\n");
- return;
- case 3:
- if(lasto&0x400)
- lasto |= 0xfffff800;
- o = IMM(10, 0);
- o = (pc-2)+4+(o<<1)+(lasto<<12);
- print("bl %x\n", o);
- return;
- }
- }
-}
diff --git a/src/cmd/6g/Makefile b/src/cmd/6g/Makefile
index 023f5d111..64fa15399 100644
--- a/src/cmd/6g/Makefile
+++ b/src/cmd/6g/Makefile
@@ -14,16 +14,17 @@ HFILES=\
opt.h\
OFILES=\
- list.$O\
- gobj.$O\
- galign.$O\
- ggen.$O\
+ ../6l/enam.$O\
cgen.$O\
cplx.$O\
+ galign.$O\
+ ggen.$O\
+ gobj.$O\
gsubr.$O\
+ list.$O\
peep.$O\
+ pgen.$O\
reg.$O\
- ../6l/enam.$O\
LIB=\
../gc/gc.a\
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
index 75dc4fe13..fca4b64dd 100644
--- a/src/cmd/6g/cgen.c
+++ b/src/cmd/6g/cgen.c
@@ -283,11 +283,9 @@ cgen(Node *n, Node *res)
if(istype(nl->type, TSTRING) || isslice(nl->type)) {
// both slice and string have len one pointer into the struct.
// a zero pointer means zero length
- regalloc(&n1, types[tptr], res);
- agen(nl, &n1);
- n1.op = OINDREG;
+ igen(nl, &n1, res);
n1.type = types[TUINT32];
- n1.xoffset = Array_nel;
+ n1.xoffset += Array_nel;
gmove(&n1, res);
regfree(&n1);
break;
@@ -319,11 +317,9 @@ cgen(Node *n, Node *res)
break;
}
if(isslice(nl->type)) {
- regalloc(&n1, types[tptr], res);
- agen(nl, &n1);
- n1.op = OINDREG;
+ igen(nl, &n1, res);
n1.type = types[TUINT32];
- n1.xoffset = Array_cap;
+ n1.xoffset += Array_cap;
gmove(&n1, res);
regfree(&n1);
break;
@@ -542,7 +538,8 @@ agen(Node *n, Node *res)
gmove(&n1, &n3);
}
- ginscon(optoas(OADD, types[tptr]), v*w, &n3);
+ if (v*w != 0)
+ ginscon(optoas(OADD, types[tptr]), v*w, &n3);
gmove(&n3, res);
regfree(&n3);
break;
@@ -682,6 +679,28 @@ ret:
void
igen(Node *n, Node *a, Node *res)
{
+ Type *fp;
+ Iter flist;
+
+ switch(n->op) {
+ case ONAME:
+ if((n->class&PHEAP) || n->class == PPARAMREF)
+ break;
+ *a = *n;
+ return;
+
+ case OCALLFUNC:
+ fp = structfirst(&flist, getoutarg(n->left->type));
+ cgen_call(n, 0);
+ memset(a, 0, sizeof *a);
+ a->op = OINDREG;
+ a->val.u.reg = D_SP;
+ a->addable = 1;
+ a->xoffset = fp->width;
+ a->type = n->type;
+ return;
+ }
+
regalloc(a, types[tptr], res);
agen(n, a);
a->op = OINDREG;
@@ -848,6 +867,7 @@ bgen(Node *n, int true, Prog *to)
n2 = n1;
n2.op = OINDREG;
n2.xoffset = Array_array;
+ n2.type = types[tptr];
nodconst(&tmp, types[tptr], 0);
gins(optoas(OCMP, types[tptr]), &n2, &tmp);
patch(gbranch(a, types[tptr]), to);
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
index 7efb2c252..2493771a0 100644
--- a/src/cmd/6g/gg.h
+++ b/src/cmd/6g/gg.h
@@ -23,6 +23,7 @@ struct Addr
Sym* gotype;
Sym* sym;
+ Node* node;
int width;
uchar type;
uchar index;
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index 8d89fb164..5260335df 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -7,121 +7,18 @@
#include "gg.h"
#include "opt.h"
-static Prog *pret;
-
void
-compile(Node *fn)
+defframe(Prog *ptxt)
{
- Plist *pl;
- Node nod1;
- Prog *ptxt;
- int32 lno;
- Type *t;
- Iter save;
-
- if(newproc == N) {
- newproc = sysfunc("newproc");
- deferproc = sysfunc("deferproc");
- deferreturn = sysfunc("deferreturn");
- panicindex = sysfunc("panicindex");
- panicslice = sysfunc("panicslice");
- throwreturn = sysfunc("throwreturn");
- }
-
- if(fn->nbody == nil)
- return;
-
- // set up domain for labels
- clearlabels();
-
- lno = setlineno(fn);
-
- curfn = fn;
- dowidth(curfn->type);
-
- if(curfn->type->outnamed) {
- // add clearing of the output parameters
- t = structfirst(&save, getoutarg(curfn->type));
- while(t != T) {
- if(t->nname != N)
- curfn->nbody = concat(list1(nod(OAS, t->nname, N)), curfn->nbody);
- t = structnext(&save);
- }
- }
-
- hasdefer = 0;
- walk(curfn);
- if(nerrors != 0 || isblank(curfn->nname))
- goto ret;
-
- allocparams();
-
- continpc = P;
- breakpc = P;
-
- pl = newplist();
- pl->name = curfn->nname;
-
- setlineno(curfn);
-
- nodconst(&nod1, types[TINT32], 0);
- ptxt = gins(ATEXT, curfn->nname, &nod1);
- afunclit(&ptxt->from);
-
- ginit();
- genlist(curfn->enter);
-
- pret = nil;
- if(hasdefer || curfn->exit) {
- Prog *p1;
-
- p1 = gjmp(nil);
- pret = gjmp(nil);
- patch(p1, pc);
- }
-
- genlist(curfn->nbody);
- gclean();
- checklabels();
- if(nerrors != 0)
- goto ret;
- if(curfn->endlineno)
- lineno = curfn->endlineno;
-
- if(curfn->type->outtuple != 0)
- ginscall(throwreturn, 0);
-
- if(pret)
- patch(pret, pc);
- ginit();
- if(hasdefer)
- ginscall(deferreturn, 0);
- if(curfn->exit)
- genlist(curfn->exit);
- gclean();
- if(nerrors != 0)
- goto ret;
- pc->as = ARET; // overwrite AEND
- pc->lineno = lineno;
-
- if(!debug['N'] || debug['R'] || debug['P']) {
- regopt(ptxt);
- }
-
// fill in argument size
ptxt->to.offset = rnd(curfn->type->argwid, widthptr);
// fill in final stack size
ptxt->to.offset <<= 32;
ptxt->to.offset |= rnd(stksize+maxarg, widthptr);
-
- if(debug['f'])
- frame(0);
-
-ret:
- lineno = lno;
}
+
/*
* generate:
* call f
@@ -163,7 +60,7 @@ ginscall(Node *f, int proc)
if(proc == 2) {
nodreg(&reg, types[TINT64], D_AX);
gins(ATESTQ, &reg, &reg);
- patch(gbranch(AJNE, T), pret);
+ patch(gbranch(AJNE, T), retpc);
}
break;
}
@@ -201,7 +98,7 @@ cgen_callinter(Node *n, Node *res, int proc)
regalloc(&nodo, types[tptr], &nodr);
nodo.op = OINDREG;
- agen(i, &nodr); // REG = &inter
+ agen(i, &nodr); // REG = &inter
nodindreg(&nodsp, types[tptr], D_SP);
nodo.xoffset += widthptr;
@@ -355,7 +252,7 @@ cgen_ret(Node *n)
{
genlist(n->list); // copy out args
if(hasdefer || curfn->exit)
- gjmp(pret);
+ gjmp(retpc);
else
gins(ARET, N, N);
}
@@ -1206,7 +1103,7 @@ cgen_inline(Node *n, Node *res)
Node nodes[5];
Node n1, n2, nres, ntemp;
vlong v;
- int i, narg;
+ int i, narg, nochk;
if(n->op != OCALLFUNC)
goto no;
@@ -1242,6 +1139,7 @@ slicearray:
// len = hb[3] - lb[2] (destroys hb)
n2 = *res;
n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
v = mpgetfix(nodes[3].val.u.xval) -
@@ -1260,6 +1158,7 @@ slicearray:
// cap = nel[1] - lb[2] (destroys nel)
n2 = *res;
n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
v = mpgetfix(nodes[1].val.u.xval) -
@@ -1288,6 +1187,7 @@ slicearray:
// ary = old[0] + (lb[2] * width[4]) (destroys old)
n2 = *res;
n2.xoffset += Array_array;
+ n2.type = types[tptr];
if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
v = mpgetfix(nodes[2].val.u.xval) *
@@ -1311,6 +1211,7 @@ slicearray:
return 1;
sliceslice:
+ nochk = n->etype; // skip bounds checking
ntemp.op = OXXX;
if(!sleasy(n->list->n->right)) {
Node *n0;
@@ -1340,11 +1241,13 @@ sliceslice:
n2 = nodes[0];
n2.xoffset += Array_nel;
n2.type = types[TUINT32];
- cmpandthrow(&nodes[1], &n2);
+ if(!nochk)
+ cmpandthrow(&nodes[1], &n2);
// ret.nel = old.nel[0]-lb[1];
n2 = nodes[0];
n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
regalloc(&n1, types[TUINT32], N);
gins(optoas(OAS, types[TUINT32]), &n2, &n1);
@@ -1353,22 +1256,24 @@ sliceslice:
n2 = nres;
n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
regfree(&n1);
} else { // old[lb:hb]
- // if(hb[2] > old.cap[0]) goto throw;
n2 = nodes[0];
n2.xoffset += Array_cap;
n2.type = types[TUINT32];
- cmpandthrow(&nodes[2], &n2);
-
- // if(lb[1] > hb[2]) goto throw;
- cmpandthrow(&nodes[1], &nodes[2]);
-
+ if(!nochk) {
+ // if(hb[2] > old.cap[0]) goto throw;
+ cmpandthrow(&nodes[2], &n2);
+ // if(lb[1] > hb[2]) goto throw;
+ cmpandthrow(&nodes[1], &nodes[2]);
+ }
// ret.len = hb[2]-lb[1]; (destroys hb[2])
n2 = nres;
n2.xoffset += Array_nel;
-
+ n2.type = types[TUINT32];
+
if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
v = mpgetfix(nodes[2].val.u.xval) -
mpgetfix(nodes[1].val.u.xval);
@@ -1387,6 +1292,7 @@ sliceslice:
// ret.cap = old.cap[0]-lb[1]; (uses hb[2])
n2 = nodes[0];
n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
regalloc(&n1, types[TUINT32], &nodes[2]);
gins(optoas(OAS, types[TUINT32]), &n2, &n1);
@@ -1395,13 +1301,15 @@ sliceslice:
n2 = nres;
n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
+
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
regfree(&n1);
// ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
n2 = nodes[0];
n2.xoffset += Array_array;
-
+ n2.type = types[tptr];
regalloc(&n1, types[tptr], &nodes[1]);
if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
gins(optoas(OAS, types[tptr]), &n2, &n1);
@@ -1418,6 +1326,7 @@ sliceslice:
n2 = nres;
n2.xoffset += Array_array;
+ n2.type = types[tptr];
gins(optoas(OAS, types[tptr]), &n1, &n2);
regfree(&n1);
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index 78b8c4351..49d66e083 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -48,7 +48,7 @@ clearp(Prog *p)
/*
* generate and return proc with p->as = as,
- * linked into program. pc is next instruction.
+ * linked into program. pc is next instruction.
*/
Prog*
prog(int as)
@@ -368,11 +368,13 @@ regfree(Node *n)
{
int i;
- if(n->op == ONAME && iscomplex[n->type->etype])
+ if(n->op == ONAME)
return;
if(n->op != OREGISTER && n->op != OINDREG)
fatal("regfree: not a register");
i = n->val.u.reg;
+ if(i == D_SP)
+ return;
if(i < 0 || i >= sizeof(reg))
fatal("regfree: reg out of range");
if(reg[i] <= 0)
@@ -926,7 +928,7 @@ Prog*
gins(int as, Node *f, Node *t)
{
// Node nod;
-// int32 v;
+ int32 w;
Prog *p;
Addr af, at;
@@ -971,6 +973,27 @@ gins(int as, Node *f, Node *t)
p->to = at;
if(debug['g'])
print("%P\n", p);
+
+
+ w = 0;
+ switch(as) {
+ case AMOVB:
+ w = 1;
+ break;
+ case AMOVW:
+ w = 2;
+ break;
+ case AMOVL:
+ w = 4;
+ break;
+ case AMOVQ:
+ w = 8;
+ break;
+ }
+ if(w != 0 && f != N && (af.width > w || at.width > w)) {
+ fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
+ }
+
return p;
}
@@ -985,7 +1008,7 @@ checkoffset(Addr *a, int canemitcode)
fatal("checkoffset %#llx, cannot emit code", a->offset);
// cannot rely on unmapped nil page at 0 to catch
- // reference with large offset. instead, emit explicit
+ // reference with large offset. instead, emit explicit
// test of 0(reg).
p = gins(ATESTB, nodintconst(0), N);
p->to = *a;
@@ -1003,7 +1026,7 @@ naddr(Node *n, Addr *a, int canemitcode)
a->index = D_NONE;
a->type = D_NONE;
a->gotype = S;
-
+ a->node = N;
if(n == N)
return;
@@ -1082,6 +1105,8 @@ 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:
@@ -1144,8 +1169,9 @@ naddr(Node *n, Addr *a, int canemitcode)
naddr(n->left, a, canemitcode);
if(a->type == D_CONST && a->offset == 0)
break; // len(nil)
- a->etype = TUINT;
+ a->etype = TUINT32;
a->offset += Array_nel;
+ a->width = 4;
if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
checkoffset(a, canemitcode);
break;
@@ -1155,8 +1181,9 @@ naddr(Node *n, Addr *a, int canemitcode)
naddr(n->left, a, canemitcode);
if(a->type == D_CONST && a->offset == 0)
break; // cap(nil)
- a->etype = TUINT;
+ a->etype = TUINT32;
a->offset += Array_cap;
+ a->width = 4;
if(a->offset >= unmappedzero && a->offset-Array_cap < unmappedzero)
checkoffset(a, canemitcode);
break;
@@ -2000,12 +2027,12 @@ oindex:
if(o & OAddable) {
n2 = *l;
n2.xoffset += Array_array;
- n2.type = types[TUINT64];
+ n2.type = types[tptr];
gmove(&n2, reg);
} else {
n2 = *reg;
- n2.xoffset = Array_array;
n2.op = OINDREG;
+ n2.xoffset = Array_array;
n2.type = types[tptr];
gmove(&n2, reg);
}
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
index ed8bac3f0..af9b29cbc 100644
--- a/src/cmd/6g/reg.c
+++ b/src/cmd/6g/reg.c
@@ -33,6 +33,8 @@
#define EXTERN
#include "opt.h"
+#define NREGVAR 32 /* 16 general + 16 floating */
+#define REGBITS ((uint32)0xffffffff)
#define P2R(p) (Reg*)(p->reg)
static int first = 1;
@@ -114,6 +116,41 @@ setaddrs(Bits bit)
}
}
+static char* regname[] = {
+ ".AX",
+ ".CX",
+ ".DX",
+ ".BX",
+ ".SP",
+ ".BP",
+ ".SI",
+ ".DI",
+ ".R8",
+ ".R9",
+ ".R10",
+ ".R11",
+ ".R12",
+ ".R13",
+ ".R14",
+ ".R15",
+ ".X0",
+ ".X1",
+ ".X2",
+ ".X3",
+ ".X4",
+ ".X5",
+ ".X6",
+ ".X7",
+ ".X8",
+ ".X9",
+ ".X10",
+ ".X11",
+ ".X12",
+ ".X13",
+ ".X14",
+ ".X15",
+};
+
void
regopt(Prog *firstp)
{
@@ -143,6 +180,17 @@ regopt(Prog *firstp)
firstr = R;
lastr = R;
nvar = 0;
+
+ /*
+ * control flow is more complicated in generated go code
+ * than in generated c code. define pseudo-variables for
+ * registers, so we have complete register usage information.
+ */
+ nvar = NREGVAR;
+ memset(var, 0, NREGVAR*sizeof var[0]);
+ for(i=0; i<NREGVAR; i++)
+ var[i].sym = lookup(regname[i]);
+
regbits = RtoB(D_SP);
for(z=0; z<BITS; z++) {
externs.b[z] = 0;
@@ -247,6 +295,9 @@ regopt(Prog *firstp)
case ACOMISD:
case AUCOMISS:
case AUCOMISD:
+ case ATESTB:
+ case ATESTL:
+ case ATESTQ:
for(z=0; z<BITS; z++)
r->use2.b[z] |= bit.b[z];
break;
@@ -254,6 +305,7 @@ regopt(Prog *firstp)
/*
* right side write
*/
+ case ALEAQ:
case ANOP:
case AMOVL:
case AMOVQ:
@@ -261,6 +313,8 @@ regopt(Prog *firstp)
case AMOVW:
case AMOVBLSX:
case AMOVBLZX:
+ case AMOVBWSX:
+ case AMOVBWZX:
case AMOVBQSX:
case AMOVBQZX:
case AMOVLQSX:
@@ -269,6 +323,7 @@ regopt(Prog *firstp)
case AMOVWLZX:
case AMOVWQSX:
case AMOVWQZX:
+ case APOPQ:
case AMOVSS:
case AMOVSD:
@@ -357,6 +412,8 @@ regopt(Prog *firstp)
case AIMULL:
case AIMULQ:
case AIMULW:
+ case ANEGB:
+ case ANEGW:
case ANEGL:
case ANEGQ:
case ANOTL:
@@ -366,6 +423,23 @@ regopt(Prog *firstp)
case ASBBL:
case ASBBQ:
+ case ASETCC:
+ case ASETCS:
+ case ASETEQ:
+ case ASETGE:
+ case ASETGT:
+ case ASETHI:
+ case ASETLE:
+ case ASETLS:
+ case ASETLT:
+ case ASETMI:
+ case ASETNE:
+ case ASETOC:
+ case ASETOS:
+ case ASETPC:
+ case ASETPL:
+ case ASETPS:
+
case AXCHGB:
case AXCHGW:
case AXCHGL:
@@ -411,32 +485,44 @@ regopt(Prog *firstp)
if(p->to.type != D_NONE)
break;
- case AIDIVB:
case AIDIVL:
- case AIDIVQ:
case AIDIVW:
- case AIMULB:
- case ADIVB:
+ case AIDIVQ:
case ADIVL:
- case ADIVQ:
case ADIVW:
- case AMULB:
+ case ADIVQ:
case AMULL:
- case AMULQ:
case AMULW:
+ case AMULQ:
+ r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ break;
+
+ case AIDIVB:
+ case AIMULB:
+ case ADIVB:
+ case AMULB:
+ r->set.b[0] |= RtoB(D_AX);
+ r->use1.b[0] |= RtoB(D_AX);
+ break;
case ACWD:
- case ACDQ:
- case ACQO:
- r->regu |= RtoB(D_AX) | RtoB(D_DX);
+ r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX);
break;
+ case ACDQ:
+ r->set.b[0] |= RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX);
+ break;
+
case AREP:
case AREPN:
case ALOOP:
case ALOOPEQ:
case ALOOPNE:
- r->regu |= RtoB(D_CX);
+ r->set.b[0] |= RtoB(D_CX);
+ r->use1.b[0] |= RtoB(D_CX);
break;
case AMOVSB:
@@ -447,7 +533,8 @@ regopt(Prog *firstp)
case ACMPSL:
case ACMPSQ:
case ACMPSW:
- r->regu |= RtoB(D_SI) | RtoB(D_DI);
+ r->set.b[0] |= RtoB(D_SI) | RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_SI) | RtoB(D_DI);
break;
case ASTOSB:
@@ -458,16 +545,22 @@ regopt(Prog *firstp)
case ASCASL:
case ASCASQ:
case ASCASW:
- r->regu |= RtoB(D_AX) | RtoB(D_DI);
+ r->set.b[0] |= RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DI);
break;
case AINSB:
case AINSL:
case AINSW:
+ r->set.b[0] |= RtoB(D_DX) | RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_DI);
+ break;
+
case AOUTSB:
case AOUTSL:
case AOUTSW:
- r->regu |= RtoB(D_DI) | RtoB(D_DX);
+ r->set.b[0] |= RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_DX) | RtoB(D_DI);
break;
}
}
@@ -574,6 +667,24 @@ loop2:
dumpit("pass4", firstr);
/*
+ * pass 4.5
+ * move register pseudo-variables into regu.
+ */
+ for(r = firstr; r != R; r = r->link) {
+ r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
+
+ r->set.b[0] &= ~REGBITS;
+ r->use1.b[0] &= ~REGBITS;
+ r->use2.b[0] &= ~REGBITS;
+ r->refbehind.b[0] &= ~REGBITS;
+ r->refahead.b[0] &= ~REGBITS;
+ r->calbehind.b[0] &= ~REGBITS;
+ r->calahead.b[0] &= ~REGBITS;
+ r->regdiff.b[0] &= ~REGBITS;
+ r->act.b[0] &= ~REGBITS;
+ }
+
+ /*
* pass 5
* isolate regions
* calculate costs (paint1)
@@ -726,6 +837,7 @@ addmove(Reg *r, int bn, int rn, int f)
a->etype = v->etype;
a->type = v->name;
a->gotype = v->gotype;
+ a->node = v->node;
// need to clean this up with wptr and
// some of the defaults
@@ -818,6 +930,7 @@ mkvar(Reg *r, Adr *a)
{
Var *v;
int i, t, n, et, z, w, flag;
+ uint32 regu;
int32 o;
Bits bit;
Sym *s;
@@ -829,14 +942,17 @@ mkvar(Reg *r, Adr *a)
if(t == D_NONE)
goto none;
- if(r != R) {
- r->regu |= doregbits(t);
- r->regu |= doregbits(a->index);
- }
+ if(r != R)
+ r->use1.b[0] |= doregbits(a->index);
switch(t) {
default:
- goto none;
+ regu = doregbits(t);
+ if(regu == 0)
+ goto none;
+ bit = zbits;
+ bit.b[0] = regu;
+ return bit;
case D_ADDR:
a->type = a->index;
@@ -873,14 +989,17 @@ mkvar(Reg *r, Adr *a)
// if they overlaps, disable both
if(overlap(v->offset, v->width, o, w)) {
+// print("disable overlap %s %d %d %d %d, %E != %E\n", s->name, v->offset, v->width, o, w, v->etype, et);
v->addr = 1;
flag = 1;
}
}
}
- if(a->pun)
+ if(a->pun) {
+// print("disable pun %s\n", s->name);
flag = 1;
+ }
switch(et) {
case 0:
case TFUNC:
@@ -903,6 +1022,7 @@ mkvar(Reg *r, Adr *a)
v->etype = et;
v->width = w;
v->addr = flag; // funny punning
+ v->node = a->node;
if(debug['R'])
print("bit=%2d et=%2d w=%d %S %D\n", i, et, w, s, a);
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
index dda19e48d..4c04112b7 100644
--- a/src/cmd/6l/asm.c
+++ b/src/cmd/6l/asm.c
@@ -108,6 +108,9 @@ needlib(char *name)
char *p;
Sym *s;
+ if(*name == '\0')
+ return 0;
+
/* reuse hash code in symbol table */
p = smprint(".elfload.%s", name);
s = lookup(p, 0);
@@ -695,7 +698,7 @@ asmb(void)
{
int32 magic;
int a, dynsym;
- vlong vl, startva, symo, elfsymo, elfstro, elfsymsize, machlink;
+ vlong vl, startva, symo, machlink;
ElfEhdr *eh;
ElfPhdr *ph, *pph;
ElfShdr *sh;
@@ -706,9 +709,6 @@ asmb(void)
Bflush(&bso);
elftextsh = 0;
- elfsymsize = 0;
- elfstro = 0;
- elfsymo = 0;
if(debug['v'])
Bprint(&bso, "%5.2f codeblk\n", cputime());
@@ -787,40 +787,28 @@ asmb(void)
symo = rnd(symo, PEFILEALIGN);
break;
}
- /*
- * the symbol information is stored as
- * 32-bit symbol table size
- * 32-bit line number table size
- * symbol table
- * line number table
- */
- seek(cout, symo+8, 0);
- if(debug['v'])
- Bprint(&bso, "%5.2f sp\n", cputime());
- Bflush(&bso);
- if(debug['v'])
- Bprint(&bso, "%5.2f pc\n", cputime());
- Bflush(&bso);
- if(!debug['s'])
- strnput("", INITRND-(8+symsize+lcsize)%INITRND);
- cflush();
seek(cout, symo, 0);
- lputl(symsize);
- lputl(lcsize);
- cflush();
- if(HEADTYPE != Hwindows && !debug['s']) {
- elfsymo = symo+8+symsize+lcsize;
- seek(cout, elfsymo, 0);
- asmelfsym64();
- cflush();
- elfstro = seek(cout, 0, 1);
- elfsymsize = elfstro - elfsymo;
- ewrite(cout, elfstrdat, elfstrsize);
+ switch(HEADTYPE) {
+ default:
+ if(iself) {
+ seek(cout, symo, 0);
+ asmelfsym();
+ cflush();
+ ewrite(cout, elfstrdat, elfstrsize);
+
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+ dwarfemitdebugsections();
+ }
+ break;
+ case Hdarwin:
+ case Hwindows:
if(debug['v'])
Bprint(&bso, "%5.2f dwarf\n", cputime());
dwarfemitdebugsections();
+ break;
}
}
@@ -1039,15 +1027,15 @@ asmb(void)
sh = newElfShdr(elfstr[ElfStrSymtab]);
sh->type = SHT_SYMTAB;
- sh->off = elfsymo;
- sh->size = elfsymsize;
+ sh->off = symo;
+ sh->size = symsize;
sh->addralign = 8;
sh->entsize = 24;
sh->link = eh->shnum; // link to strtab
sh = newElfShdr(elfstr[ElfStrStrtab]);
sh->type = SHT_STRTAB;
- sh->off = elfstro;
+ sh->off = symo+symsize;
sh->size = elfstrsize;
sh->addralign = 1;
@@ -1134,6 +1122,10 @@ genasmsym(void (*put)(Sym*, char*, int, vlong, vlong, int, Sym*))
Auto *a;
Sym *s;
+ s = lookup("etext", 0);
+ if(s->type == STEXT)
+ put(s, s->name, 'T', s->value, s->size, s->version, 0);
+
for(s=allsym; s!=S; s=s->allsym) {
if(s->hide)
continue;
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
index 33ca51b2c..f4ee6aa92 100644
--- a/src/cmd/6l/l.h
+++ b/src/cmd/6l/l.h
@@ -350,9 +350,6 @@ EXTERN Sym* fromgotype; // type symbol on last p->from read
EXTERN vlong textstksiz;
EXTERN vlong textarg;
-EXTERN int elfstrsize;
-EXTERN char* elfstrdat;
-EXTERN int elftextsh;
extern Optab optab[];
extern Optab* opindex[];
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
index d53814a74..e3191bb4d 100644
--- a/src/cmd/6l/obj.c
+++ b/src/cmd/6l/obj.c
@@ -177,7 +177,7 @@ main(int argc, char *argv[])
*/
tlsoffset = 0x8a0;
machoinit();
- HEADR = MACHORESERVE;
+ HEADR = INITIAL_MACHO_HEADR;
if(INITRND == -1)
INITRND = 4096;
if(INITTEXT == -1)
diff --git a/src/cmd/8g/Makefile b/src/cmd/8g/Makefile
index 09cf8d4e3..b459782a3 100644
--- a/src/cmd/8g/Makefile
+++ b/src/cmd/8g/Makefile
@@ -15,15 +15,16 @@ HFILES=\
OFILES=\
../8l/enam.$O\
- list.$O\
- galign.$O\
- gobj.$O\
- ggen.$O\
- gsubr.$O\
cgen.$O\
cgen64.$O\
cplx.$O\
+ galign.$O\
+ ggen.$O\
+ gobj.$O\
+ gsubr.$O\
+ list.$O\
peep.$O\
+ pgen.$O\
reg.$O\
LIB=\
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
index 596824a6c..1614a2d77 100644
--- a/src/cmd/8g/cgen.c
+++ b/src/cmd/8g/cgen.c
@@ -232,6 +232,7 @@ cgen(Node *n, Node *res)
cgen(nl, res);
break;
}
+
tempname(&n2, n->type);
mgen(nl, &n1, res);
gmove(&n1, &n2);
@@ -277,15 +278,10 @@ cgen(Node *n, Node *res)
if(istype(nl->type, TSTRING) || isslice(nl->type)) {
// both slice and string have len one pointer into the struct.
igen(nl, &n1, res);
- n1.op = OREGISTER; // was OINDREG
- regalloc(&n2, types[TUINT32], &n1);
- n1.op = OINDREG;
n1.type = types[TUINT32];
- n1.xoffset = Array_nel;
- gmove(&n1, &n2);
- gmove(&n2, res);
+ n1.xoffset += Array_nel;
+ gmove(&n1, res);
regfree(&n1);
- regfree(&n2);
break;
}
fatal("cgen: OLEN: unknown type %lT", nl->type);
@@ -594,9 +590,10 @@ agen(Node *n, Node *res)
gmove(&n1, &n3);
}
- nodconst(&n2, types[tptr], v*w);
- gins(optoas(OADD, types[tptr]), &n2, &n3);
-
+ if (v*w != 0) {
+ nodconst(&n2, types[tptr], v*w);
+ gins(optoas(OADD, types[tptr]), &n2, &n3);
+ }
gmove(&n3, res);
regfree(&n3);
break;
@@ -729,7 +726,27 @@ void
igen(Node *n, Node *a, Node *res)
{
Node n1;
-
+ Type *fp;
+ Iter flist;
+
+ switch(n->op) {
+ case ONAME:
+ if((n->class&PHEAP) || n->class == PPARAMREF)
+ break;
+ *a = *n;
+ return;
+
+ case OCALLFUNC:
+ fp = structfirst(&flist, getoutarg(n->left->type));
+ cgen_call(n, 0);
+ memset(a, 0, sizeof *a);
+ a->op = OINDREG;
+ a->val.u.reg = D_SP;
+ a->addable = 1;
+ a->xoffset = fp->width;
+ a->type = n->type;
+ return;
+ }
// release register for now, to avoid
// confusing tempname.
if(res != N && res->op == OREGISTER)
@@ -919,6 +936,7 @@ bgen(Node *n, int true, Prog *to)
n2 = n1;
n2.op = OINDREG;
n2.xoffset = Array_array;
+ n2.type = types[tptr];
nodconst(&tmp, types[tptr], 0);
gins(optoas(OCMP, types[tptr]), &n2, &tmp);
patch(gbranch(a, types[tptr]), to);
diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h
index 57cd1b56b..7da60d767 100644
--- a/src/cmd/8g/gg.h
+++ b/src/cmd/8g/gg.h
@@ -25,6 +25,7 @@ struct Addr
Sym* gotype;
Sym* sym;
+ Node* node;
int width;
uchar type;
uchar index;
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
index 920725c3e..25adb38c0 100644
--- a/src/cmd/8g/ggen.c
+++ b/src/cmd/8g/ggen.c
@@ -7,106 +7,9 @@
#include "gg.h"
#include "opt.h"
-static Prog *pret;
-
void
-compile(Node *fn)
+defframe(Prog *ptxt)
{
- Plist *pl;
- Node nod1;
- Prog *ptxt;
- int32 lno;
- Type *t;
- Iter save;
-
- if(newproc == N) {
- newproc = sysfunc("newproc");
- deferproc = sysfunc("deferproc");
- deferreturn = sysfunc("deferreturn");
- panicindex = sysfunc("panicindex");
- panicslice = sysfunc("panicslice");
- throwreturn = sysfunc("throwreturn");
- }
-
- if(fn->nbody == nil)
- return;
-
- // set up domain for labels
- clearlabels();
-
- lno = setlineno(fn);
-
- curfn = fn;
- dowidth(curfn->type);
-
- if(curfn->type->outnamed) {
- // add clearing of the output parameters
- t = structfirst(&save, getoutarg(curfn->type));
- while(t != T) {
- if(t->nname != N)
- curfn->nbody = concat(list1(nod(OAS, t->nname, N)), curfn->nbody);
- t = structnext(&save);
- }
- }
-
- hasdefer = 0;
- walk(curfn);
- if(nerrors != 0 || isblank(curfn->nname))
- goto ret;
-
- allocparams();
-
- continpc = P;
- breakpc = P;
-
- pl = newplist();
- pl->name = curfn->nname;
-
- setlineno(curfn);
-
- nodconst(&nod1, types[TINT32], 0);
- ptxt = gins(ATEXT, curfn->nname, &nod1);
- afunclit(&ptxt->from);
-
- ginit();
- genlist(curfn->enter);
-
- pret = nil;
- if(hasdefer || curfn->exit) {
- Prog *p1;
-
- p1 = gjmp(nil);
- pret = gjmp(nil);
- patch(p1, pc);
- }
-
- genlist(curfn->nbody);
- gclean();
- checklabels();
- if(nerrors != 0)
- goto ret;
- if(curfn->endlineno)
- lineno = curfn->endlineno;
-
- if(curfn->type->outtuple != 0)
- ginscall(throwreturn, 0);
-
- if(pret)
- patch(pret, pc);
- ginit();
- if(hasdefer)
- ginscall(deferreturn, 0);
- if(curfn->exit)
- genlist(curfn->exit);
- gclean();
- if(nerrors != 0)
- goto ret;
- pc->as = ARET; // overwrite AEND
- pc->lineno = lineno;
-
- if(!debug['N'] || debug['R'] || debug['P']) {
- regopt(ptxt);
- }
// fill in argument size
ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
@@ -115,12 +18,6 @@ compile(Node *fn)
maxstksize = stksize;
ptxt->to.offset = rnd(maxstksize+maxarg, widthptr);
maxstksize = 0;
-
- if(debug['f'])
- frame(0);
-
-ret:
- lineno = lno;
}
void
@@ -200,7 +97,7 @@ ginscall(Node *f, int proc)
if(proc == 2) {
nodreg(&reg, types[TINT64], D_AX);
gins(ATESTL, &reg, &reg);
- patch(gbranch(AJNE, T), pret);
+ patch(gbranch(AJNE, T), retpc);
}
break;
}
@@ -391,8 +288,8 @@ void
cgen_ret(Node *n)
{
genlist(n->list); // copy out args
- if(pret)
- gjmp(pret);
+ if(retpc)
+ gjmp(retpc);
else
gins(ARET, N, N);
}
@@ -915,7 +812,7 @@ cgen_inline(Node *n, Node *res)
Node nodes[5];
Node n1, n2, nres, ntemp;
vlong v;
- int i, narg;
+ int i, narg, nochk;
if(n->op != OCALLFUNC)
goto no;
@@ -953,6 +850,7 @@ slicearray:
// len = hb[3] - lb[2] (destroys hb)
n2 = *res;
n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
if(smallintconst(&nodes[3]) && smallintconst(&nodes[2])) {
v = mpgetfix(nodes[3].val.u.xval) -
@@ -971,6 +869,7 @@ slicearray:
// cap = nel[1] - lb[2] (destroys nel)
n2 = *res;
n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
if(smallintconst(&nodes[1]) && smallintconst(&nodes[2])) {
v = mpgetfix(nodes[1].val.u.xval) -
@@ -999,6 +898,7 @@ slicearray:
// ary = old[0] + (lb[2] * width[4]) (destroys old)
n2 = *res;
n2.xoffset += Array_array;
+ n2.type = types[tptr];
if(smallintconst(&nodes[2]) && smallintconst(&nodes[4])) {
v = mpgetfix(nodes[2].val.u.xval) *
@@ -1026,6 +926,7 @@ slicearray:
sliceslice:
if(!fix64(n->list, narg))
goto no;
+ nochk = n->etype; // skip bounds checking
ntemp.op = OXXX;
if(!sleasy(n->list->n->right)) {
Node *n0;
@@ -1055,11 +956,13 @@ sliceslice:
n2 = nodes[0];
n2.xoffset += Array_nel;
n2.type = types[TUINT32];
- cmpandthrow(&nodes[1], &n2);
+ if(!nochk)
+ cmpandthrow(&nodes[1], &n2);
// ret.nel = old.nel[0]-lb[1];
n2 = nodes[0];
n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
regalloc(&n1, types[TUINT32], N);
gins(optoas(OAS, types[TUINT32]), &n2, &n1);
@@ -1068,22 +971,25 @@ sliceslice:
n2 = nres;
n2.xoffset += Array_nel;
+ n2.type = types[TUINT32];
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
regfree(&n1);
} else { // old[lb:hb]
- // if(hb[2] > old.cap[0]) goto throw;
n2 = nodes[0];
n2.xoffset += Array_cap;
n2.type = types[TUINT32];
- cmpandthrow(&nodes[2], &n2);
-
- // if(lb[1] > hb[2]) goto throw;
- cmpandthrow(&nodes[1], &nodes[2]);
+ if (!nochk) {
+ // if(hb[2] > old.cap[0]) goto throw;
+ cmpandthrow(&nodes[2], &n2);
+ // if(lb[1] > hb[2]) goto throw;
+ cmpandthrow(&nodes[1], &nodes[2]);
+ }
// ret.len = hb[2]-lb[1]; (destroys hb[2])
n2 = nres;
n2.xoffset += Array_nel;
-
+ n2.type = types[TUINT32];
+
if(smallintconst(&nodes[2]) && smallintconst(&nodes[1])) {
v = mpgetfix(nodes[2].val.u.xval) -
mpgetfix(nodes[1].val.u.xval);
@@ -1102,6 +1008,7 @@ sliceslice:
// ret.cap = old.cap[0]-lb[1]; (uses hb[2])
n2 = nodes[0];
n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
regalloc(&n1, types[TUINT32], &nodes[2]);
gins(optoas(OAS, types[TUINT32]), &n2, &n1);
@@ -1110,12 +1017,14 @@ sliceslice:
n2 = nres;
n2.xoffset += Array_cap;
+ n2.type = types[TUINT32];
gins(optoas(OAS, types[TUINT32]), &n1, &n2);
regfree(&n1);
// ret.array = old.array[0]+lb[1]*width[3]; (uses lb[1])
n2 = nodes[0];
n2.xoffset += Array_array;
+ n2.type = types[tptr];
regalloc(&n1, types[tptr], &nodes[1]);
if(smallintconst(&nodes[1]) && smallintconst(&nodes[3])) {
@@ -1135,6 +1044,7 @@ sliceslice:
n2 = nres;
n2.xoffset += Array_array;
+ n2.type = types[tptr];
gins(optoas(OAS, types[tptr]), &n1, &n2);
regfree(&n1);
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
index ae9901eeb..a8d65cf22 100644
--- a/src/cmd/8g/gsubr.c
+++ b/src/cmd/8g/gsubr.c
@@ -736,7 +736,6 @@ ginit(void)
reg[i] = 1;
for(i=D_AL; i<=D_DI; i++)
reg[i] = 0;
-
for(i=0; i<nelem(resvd); i++)
reg[resvd[i]]++;
}
@@ -827,6 +826,8 @@ err:
return;
out:
+ if (i == D_SP)
+ print("alloc SP\n");
if(reg[i] == 0) {
regpc[i] = (ulong)__builtin_return_address(0);
if(i == D_AX || i == D_CX || i == D_DX || i == D_SP) {
@@ -842,10 +843,14 @@ void
regfree(Node *n)
{
int i;
-
+
+ if(n->op == ONAME)
+ return;
if(n->op != OREGISTER && n->op != OINDREG)
fatal("regfree: not a register");
i = n->val.u.reg;
+ if(i == D_SP)
+ return;
if(i < 0 || i >= sizeof(reg))
fatal("regfree: reg out of range");
if(reg[i] <= 0)
@@ -1167,6 +1172,9 @@ gmove(Node *f, Node *t)
case CASE(TINT8, TUINT8):
case CASE(TUINT8, TINT8):
case CASE(TUINT8, TUINT8):
+ a = AMOVB;
+ break;
+
case CASE(TINT16, TINT8): // truncate
case CASE(TUINT16, TINT8):
case CASE(TINT32, TINT8):
@@ -1176,7 +1184,7 @@ gmove(Node *f, Node *t)
case CASE(TINT32, TUINT8):
case CASE(TUINT32, TUINT8):
a = AMOVB;
- break;
+ goto rsrc;
case CASE(TINT64, TINT8): // truncate low word
case CASE(TUINT64, TINT8):
@@ -1184,7 +1192,7 @@ gmove(Node *f, Node *t)
case CASE(TUINT64, TUINT8):
split64(f, &flo, &fhi);
nodreg(&r1, t->type, D_AX);
- gins(AMOVB, &flo, &r1);
+ gmove(&flo, &r1);
gins(AMOVB, &r1, t);
splitclean();
return;
@@ -1193,12 +1201,15 @@ gmove(Node *f, Node *t)
case CASE(TINT16, TUINT16):
case CASE(TUINT16, TINT16):
case CASE(TUINT16, TUINT16):
+ a = AMOVW;
+ break;
+
case CASE(TINT32, TINT16): // truncate
case CASE(TUINT32, TINT16):
case CASE(TINT32, TUINT16):
case CASE(TUINT32, TUINT16):
a = AMOVW;
- break;
+ goto rsrc;
case CASE(TINT64, TINT16): // truncate low word
case CASE(TUINT64, TINT16):
@@ -1206,7 +1217,7 @@ gmove(Node *f, Node *t)
case CASE(TUINT64, TUINT16):
split64(f, &flo, &fhi);
nodreg(&r1, t->type, D_AX);
- gins(AMOVW, &flo, &r1);
+ gmove(&flo, &r1);
gins(AMOVW, &r1, t);
splitclean();
return;
@@ -1224,7 +1235,7 @@ gmove(Node *f, Node *t)
case CASE(TUINT64, TUINT32):
split64(f, &flo, &fhi);
nodreg(&r1, t->type, D_AX);
- gins(AMOVL, &flo, &r1);
+ gmove(&flo, &r1);
gins(AMOVL, &r1, t);
splitclean();
return;
@@ -1378,14 +1389,14 @@ gmove(Node *f, Node *t)
case TUINT8:
gins(ATESTL, ncon(0xffffff00), &t1);
p1 = gbranch(AJEQ, T);
- gins(AMOVB, ncon(0), &t1);
+ gins(AMOVL, ncon(0), &t1);
patch(p1, pc);
gmove(&t1, t);
break;
case TUINT16:
gins(ATESTL, ncon(0xffff0000), &t1);
p1 = gbranch(AJEQ, T);
- gins(AMOVW, ncon(0), &t1);
+ gins(AMOVL, ncon(0), &t1);
patch(p1, pc);
gmove(&t1, t);
break;
@@ -1456,11 +1467,11 @@ gmove(Node *f, Node *t)
split64(t, &tlo, &thi);
gins(AXORL, ncon(0x80000000), &thi); // + 2^63
patch(p3, pc);
- patch(p1, pc);
splitclean();
-
// restore rounding mode
gins(AFLDCW, &t1, N);
+
+ patch(p1, pc);
return;
/*
@@ -1609,6 +1620,14 @@ gmove(Node *f, Node *t)
gins(a, f, t);
return;
+rsrc:
+ // requires register source
+ regalloc(&r1, f->type, t);
+ gmove(f, &r1);
+ gins(a, &r1, t);
+ regfree(&r1);
+ return;
+
rdst:
// requires register destination
regalloc(&r1, t->type, t);
@@ -1661,6 +1680,7 @@ gins(int as, Node *f, Node *t)
{
Prog *p;
Addr af, at;
+ int w;
if(as == AFMOVF && f && f->op == OREGISTER && t && t->op == OREGISTER)
fatal("gins MOVF reg, reg");
@@ -1686,6 +1706,26 @@ gins(int as, Node *f, Node *t)
p->to = at;
if(debug['g'])
print("%P\n", p);
+
+ w = 0;
+ switch(as) {
+ case AMOVB:
+ w = 1;
+ break;
+ case AMOVW:
+ w = 2;
+ break;
+ case AMOVL:
+ w = 4;
+ break;
+ }
+
+ if(1 && w != 0 && f != N && (af.width > w || at.width > w)) {
+ dump("bad width from:", f);
+ dump("bad width to:", t);
+ fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
+ }
+
return p;
}
@@ -1718,6 +1758,7 @@ naddr(Node *n, Addr *a, int canemitcode)
a->index = D_NONE;
a->type = D_NONE;
a->gotype = S;
+ a->node = N;
if(n == N)
return;
@@ -1775,6 +1816,8 @@ 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:
@@ -1837,8 +1880,9 @@ naddr(Node *n, Addr *a, int canemitcode)
naddr(n->left, a, canemitcode);
if(a->type == D_CONST && a->offset == 0)
break; // len(nil)
- a->etype = TUINT;
+ a->etype = TUINT32;
a->offset += Array_nel;
+ a->width = 4;
if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
checkoffset(a, canemitcode);
break;
@@ -1848,8 +1892,9 @@ naddr(Node *n, Addr *a, int canemitcode)
naddr(n->left, a, canemitcode);
if(a->type == D_CONST && a->offset == 0)
break; // cap(nil)
- a->etype = TUINT;
+ a->etype = TUINT32;
a->offset += Array_cap;
+ a->width = 4;
if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
checkoffset(a, canemitcode);
break;
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
index 1465d372c..a2f3def37 100644
--- a/src/cmd/8g/reg.c
+++ b/src/cmd/8g/reg.c
@@ -33,6 +33,8 @@
#define EXTERN
#include "opt.h"
+#define NREGVAR 8
+#define REGBITS ((uint32)0xff)
#define P2R(p) (Reg*)(p->reg)
static int first = 1;
@@ -114,6 +116,8 @@ setaddrs(Bits bit)
}
}
+static char* regname[] = { ".ax", ".cx", ".dx", ".bx", ".sp", ".bp", ".si", ".di" };
+
void
regopt(Prog *firstp)
{
@@ -142,7 +146,17 @@ regopt(Prog *firstp)
r1 = R;
firstr = R;
lastr = R;
- nvar = 0;
+
+ /*
+ * control flow is more complicated in generated go code
+ * than in generated c code. define pseudo-variables for
+ * registers, so we have complete register usage information.
+ */
+ nvar = NREGVAR;
+ memset(var, 0, NREGVAR*sizeof var[0]);
+ for(i=0; i<NREGVAR; i++)
+ var[i].sym = lookup(regname[i]);
+
regbits = RtoB(D_SP);
for(z=0; z<BITS; z++) {
externs.b[z] = 0;
@@ -249,14 +263,19 @@ regopt(Prog *firstp)
/*
* right side write
*/
+ case AFSTSW:
+ case ALEAL:
case ANOP:
case AMOVL:
case AMOVB:
case AMOVW:
case AMOVBLSX:
case AMOVBLZX:
+ case AMOVBWSX:
+ case AMOVBWZX:
case AMOVWLSX:
case AMOVWLZX:
+ case APOPL:
for(z=0; z<BITS; z++)
r->set.b[z] |= bit.b[z];
break;
@@ -321,6 +340,23 @@ regopt(Prog *firstp)
case AADCL:
case ASBBL:
+ case ASETCC:
+ case ASETCS:
+ case ASETEQ:
+ case ASETGE:
+ case ASETGT:
+ case ASETHI:
+ case ASETLE:
+ case ASETLS:
+ case ASETLT:
+ case ASETMI:
+ case ASETNE:
+ case ASETOC:
+ case ASETOS:
+ case ASETPC:
+ case ASETPL:
+ case ASETPS:
+
case AXCHGB:
case AXCHGW:
case AXCHGL:
@@ -349,20 +385,32 @@ regopt(Prog *firstp)
if(p->to.type != D_NONE)
break;
- case AIDIVB:
case AIDIVL:
case AIDIVW:
- case AIMULB:
- case ADIVB:
case ADIVL:
case ADIVW:
- case AMULB:
case AMULL:
case AMULW:
+ r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ break;
+
+ case AIDIVB:
+ case AIMULB:
+ case ADIVB:
+ case AMULB:
+ r->set.b[0] |= RtoB(D_AX);
+ r->use1.b[0] |= RtoB(D_AX);
+ break;
case ACWD:
+ r->set.b[0] |= RtoB(D_AX) | RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX);
+ break;
+
case ACDQ:
- r->regu |= RtoB(D_AX) | RtoB(D_DX);
+ r->set.b[0] |= RtoB(D_DX);
+ r->use1.b[0] |= RtoB(D_AX);
break;
case AREP:
@@ -370,7 +418,8 @@ regopt(Prog *firstp)
case ALOOP:
case ALOOPEQ:
case ALOOPNE:
- r->regu |= RtoB(D_CX);
+ r->set.b[0] |= RtoB(D_CX);
+ r->use1.b[0] |= RtoB(D_CX);
break;
case AMOVSB:
@@ -379,7 +428,8 @@ regopt(Prog *firstp)
case ACMPSB:
case ACMPSL:
case ACMPSW:
- r->regu |= RtoB(D_SI) | RtoB(D_DI);
+ r->set.b[0] |= RtoB(D_SI) | RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_SI) | RtoB(D_DI);
break;
case ASTOSB:
@@ -388,16 +438,22 @@ regopt(Prog *firstp)
case ASCASB:
case ASCASL:
case ASCASW:
- r->regu |= RtoB(D_AX) | RtoB(D_DI);
+ r->set.b[0] |= RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_AX) | RtoB(D_DI);
break;
case AINSB:
case AINSL:
case AINSW:
+ r->set.b[0] |= RtoB(D_DX) | RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_DI);
+ break;
+
case AOUTSB:
case AOUTSL:
case AOUTSW:
- r->regu |= RtoB(D_DI) | RtoB(D_DX);
+ r->set.b[0] |= RtoB(D_DI);
+ r->use1.b[0] |= RtoB(D_DX) | RtoB(D_DI);
break;
}
}
@@ -504,6 +560,24 @@ loop2:
dumpit("pass4", firstr);
/*
+ * pass 4.5
+ * move register pseudo-variables into regu.
+ */
+ for(r = firstr; r != R; r = r->link) {
+ r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
+
+ r->set.b[0] &= ~REGBITS;
+ r->use1.b[0] &= ~REGBITS;
+ r->use2.b[0] &= ~REGBITS;
+ r->refbehind.b[0] &= ~REGBITS;
+ r->refahead.b[0] &= ~REGBITS;
+ r->calbehind.b[0] &= ~REGBITS;
+ r->calahead.b[0] &= ~REGBITS;
+ r->regdiff.b[0] &= ~REGBITS;
+ r->act.b[0] &= ~REGBITS;
+ }
+
+ /*
* pass 5
* isolate regions
* calculate costs (paint1)
@@ -656,6 +730,7 @@ addmove(Reg *r, int bn, int rn, int f)
a->etype = v->etype;
a->type = v->name;
a->gotype = v->gotype;
+ a->node = v->node;
// need to clean this up with wptr and
// some of the defaults
@@ -732,7 +807,7 @@ Bits
mkvar(Reg *r, Adr *a)
{
Var *v;
- int i, t, n, et, z, w, flag;
+ int i, t, n, et, z, w, flag, regu;
int32 o;
Bits bit;
Sym *s;
@@ -744,14 +819,17 @@ mkvar(Reg *r, Adr *a)
if(t == D_NONE)
goto none;
- if(r != R) {
- r->regu |= doregbits(t);
- r->regu |= doregbits(a->index);
- }
+ if(r != R)
+ r->use1.b[0] |= doregbits(a->index);
switch(t) {
default:
- goto none;
+ regu = doregbits(t);
+ if(regu == 0)
+ goto none;
+ bit = zbits;
+ bit.b[0] = regu;
+ return bit;
case D_ADDR:
a->type = a->index;
@@ -821,6 +899,7 @@ mkvar(Reg *r, Adr *a)
v->etype = et;
v->width = w;
v->addr = flag; // funny punning
+ v->node = a->node;
if(debug['R'])
print("bit=%2d et=%2d w=%d %S %D flag=%d\n", i, et, w, s, a, v->addr);
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
index f28b8d904..cb900d28d 100644
--- a/src/cmd/8l/asm.c
+++ b/src/cmd/8l/asm.c
@@ -104,6 +104,9 @@ needlib(char *name)
char *p;
Sym *s;
+ if(*name == '\0')
+ return 0;
+
/* reuse hash code in symbol table */
p = smprint(".dynlib.%s", name);
s = lookup(p, 0);
@@ -532,6 +535,8 @@ doelf(void)
elfstr[ElfStrGosymcounts] = addstring(shstrtab, ".gosymcounts");
elfstr[ElfStrGosymtab] = addstring(shstrtab, ".gosymtab");
elfstr[ElfStrGopclntab] = addstring(shstrtab, ".gopclntab");
+ elfstr[ElfStrSymtab] = addstring(shstrtab, ".symtab");
+ elfstr[ElfStrStrtab] = addstring(shstrtab, ".strtab");
dwarfaddshstrings(shstrtab);
}
elfstr[ElfStrShstrtab] = addstring(shstrtab, ".shstrtab");
@@ -715,10 +720,10 @@ asmb(void)
if(iself)
goto Elfsym;
case Hgarbunix:
- seek(cout, rnd(HEADR+segtext.filelen, 8192)+segdata.filelen, 0);
+ symo = rnd(HEADR+segtext.filelen, 8192)+segdata.filelen;
break;
case Hunixcoff:
- seek(cout, rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen, 0);
+ symo = rnd(HEADR+segtext.filelen, INITRND)+segdata.filelen;
break;
case Hplan9x32:
symo = HEADR+segtext.filelen+segdata.filelen;
@@ -736,32 +741,44 @@ asmb(void)
symo = rnd(symo, INITRND);
break;
case Hwindows:
- // TODO(brainman): not sure what symo meant to be, but it is not used for Windows PE for now anyway
symo = rnd(HEADR+segtext.filelen, PEFILEALIGN)+segdata.filelen;
symo = rnd(symo, PEFILEALIGN);
break;
}
- if(!debug['s']) {
- seek(cout, symo, 0);
-
- if(HEADTYPE == Hplan9x32) {
- asmplan9sym();
+ seek(cout, symo, 0);
+ switch(HEADTYPE) {
+ default:
+ if(iself) {
+ if(debug['v'])
+ Bprint(&bso, "%5.2f elfsym\n", cputime());
+ asmelfsym();
cflush();
-
- sym = lookup("pclntab", 0);
- if(sym != nil) {
- lcsize = sym->np;
- for(i=0; i < lcsize; i++)
- cput(sym->p[i]);
-
- cflush();
- }
-
- } else if(HEADTYPE != Hwindows) {
+ ewrite(cout, elfstrdat, elfstrsize);
+
if(debug['v'])
Bprint(&bso, "%5.2f dwarf\n", cputime());
dwarfemitdebugsections();
}
+ break;
+ case Hplan9x32:
+ asmplan9sym();
+ cflush();
+
+ sym = lookup("pclntab", 0);
+ if(sym != nil) {
+ lcsize = sym->np;
+ for(i=0; i < lcsize; i++)
+ cput(sym->p[i]);
+
+ cflush();
+ }
+ break;
+ case Hdarwin:
+ case Hwindows:
+ if(debug['v'])
+ Bprint(&bso, "%5.2f dwarf\n", cputime());
+ dwarfemitdebugsections();
+ break;
}
}
if(debug['v'])
@@ -1082,6 +1099,20 @@ asmb(void)
sh->addralign = 1;
shsym(sh, lookup("pclntab", 0));
+ sh = newElfShdr(elfstr[ElfStrSymtab]);
+ sh->type = SHT_SYMTAB;
+ sh->off = symo;
+ sh->size = symsize;
+ sh->addralign = 4;
+ sh->entsize = 16;
+ sh->link = eh->shnum; // link to strtab
+
+ sh = newElfShdr(elfstr[ElfStrStrtab]);
+ sh->type = SHT_STRTAB;
+ sh->off = symo+symsize;
+ sh->size = elfstrsize;
+ sh->addralign = 1;
+
dwarfaddelfheaders();
}
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
index 8f39ef519..7e7cd5d63 100644
--- a/src/cmd/8l/l.h
+++ b/src/cmd/8l/l.h
@@ -260,11 +260,15 @@ EXTERN union
#define cbuf u.obuf
#define xbuf u.ibuf
-#pragma varargck type "A" uint
+#pragma varargck type "A" int
#pragma varargck type "D" Adr*
+#pragma varargck type "I" int
+#pragma varargck type "I" uchar*
#pragma varargck type "P" Prog*
#pragma varargck type "R" int
#pragma varargck type "S" char*
+#pragma varargck type "Y" Sym*
+#pragma varargck type "i" char*
EXTERN int32 HEADR;
EXTERN int32 HEADTYPE;
@@ -383,11 +387,6 @@ void deadcode(void);
#define WPUT(a) wputl(a)
#define VPUT(a) vputl(a)
-#pragma varargck type "D" Adr*
-#pragma varargck type "P" Prog*
-#pragma varargck type "R" int
-#pragma varargck type "A" int
-
/* Used by ../ld/dwarf.c */
enum
{
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
index 2a38f7ef0..440dcb77f 100644
--- a/src/cmd/8l/obj.c
+++ b/src/cmd/8l/obj.c
@@ -188,7 +188,7 @@ main(int argc, char *argv[])
if(INITDAT == -1)
INITDAT = 0;
if(INITRND == -1)
- INITRND = 1;
+ INITRND = 4096;
break;
case Hmsdoscom: /* MS-DOS .COM */
HEADR = 0;
@@ -218,7 +218,7 @@ main(int argc, char *argv[])
*/
tlsoffset = 0x468;
machoinit();
- HEADR = MACHORESERVE;
+ HEADR = INITIAL_MACHO_HEADR;
if(INITTEXT == -1)
INITTEXT = 4096+HEADR;
if(INITDAT == -1)
diff --git a/src/cmd/8l/pass.c b/src/cmd/8l/pass.c
index 28589b66a..72ae043d6 100644
--- a/src/cmd/8l/pass.c
+++ b/src/cmd/8l/pass.c
@@ -32,23 +32,10 @@
#include "l.h"
#include "../ld/lib.h"
+#include "../../pkg/runtime/stack.h"
static void xfol(Prog*, Prog**);
-// see ../../pkg/runtime/proc.c:/StackGuard
-enum
-{
-#ifdef __WINDOWS__
- // use larger stacks to compensate for larger stack guard,
- // needed for exception handling.
- StackSmall = 256,
- StackBig = 8192,
-#else
- StackSmall = 128,
- StackBig = 4096,
-#endif
-};
-
Prog*
brchain(Prog *p)
{
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index b3aa9aded..064725c1d 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -35,9 +35,17 @@ systems. For example:
// #include <png.h>
import "C"
-C identifiers or field names that are keywords in Go can be
-accessed by prefixing them with an underscore: if x points at
-a C struct with a field named "type", x._type accesses the field.
+Alternatively, CFLAGS and LDFLAGS may be obtained via the pkg-config
+tool using a '#cgo pkg-config:' directive followed by the package names.
+For example:
+
+ // #cgo pkg-config: png cairo
+ // #include <png.h>
+ import "C"
+
+Within the Go file, C identifiers or field names that are keywords in Go
+can be accessed by prefixing them with an underscore: if x points at a C
+struct with a field named "type", x._type accesses the field.
The standard C numeric types are available under the names
C.char, C.schar (signed char), C.uchar (unsigned char),
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index ae5ca2c7d..10411e94f 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -100,27 +100,81 @@ NextLine:
fatalf("%s: bad #cgo option: %s", srcfile, fields[0])
}
- if k != "CFLAGS" && k != "LDFLAGS" {
- fatalf("%s: unsupported #cgo option %s", srcfile, k)
- }
-
- v := strings.TrimSpace(fields[1])
- args, err := splitQuoted(v)
+ args, err := splitQuoted(fields[1])
if err != nil {
- fatalf("%s: bad #cgo option %s: %s", srcfile, k, err.String())
+ fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
}
- if oldv, ok := p.CgoFlags[k]; ok {
- p.CgoFlags[k] = oldv + " " + v
- } else {
- p.CgoFlags[k] = v
+ for _, arg := range args {
+ if !safeName(arg) {
+ fatalf("%s: #cgo option %s is unsafe: %s", srcfile, k, arg)
+ }
}
- if k == "CFLAGS" {
- p.GccOptions = append(p.GccOptions, args...)
+
+ switch k {
+
+ case "CFLAGS", "LDFLAGS":
+ p.addToFlag(k, args)
+
+ case "pkg-config":
+ cflags, ldflags, err := pkgConfig(args)
+ if err != nil {
+ fatalf("%s: bad #cgo option %s: %s", srcfile, k, err)
+ }
+ p.addToFlag("CFLAGS", cflags)
+ p.addToFlag("LDFLAGS", ldflags)
+
+ default:
+ fatalf("%s: unsupported #cgo option %s", srcfile, k)
+
}
}
f.Preamble = strings.Join(linesOut, "\n")
}
+// addToFlag appends args to flag. All flags are later written out onto the
+// _cgo_flags file for the build system to use.
+func (p *Package) addToFlag(flag string, args []string) {
+ if oldv, ok := p.CgoFlags[flag]; ok {
+ p.CgoFlags[flag] = oldv + " " + strings.Join(args, " ")
+ } else {
+ p.CgoFlags[flag] = strings.Join(args, " ")
+ }
+ if flag == "CFLAGS" {
+ // We'll also need these when preprocessing for dwarf information.
+ p.GccOptions = append(p.GccOptions, args...)
+ }
+}
+
+// pkgConfig runs pkg-config and extracts --libs and --cflags information
+// for packages.
+func pkgConfig(packages []string) (cflags, ldflags []string, err os.Error) {
+ for _, name := range packages {
+ if len(name) == 0 || name[0] == '-' {
+ return nil, nil, os.NewError(fmt.Sprintf("invalid name: %q", name))
+ }
+ }
+
+ args := append([]string{"pkg-config", "--cflags"}, packages...)
+ stdout, stderr, ok := run(nil, args)
+ if !ok {
+ os.Stderr.Write(stderr)
+ return nil, nil, os.NewError("pkg-config failed")
+ }
+ cflags, err = splitQuoted(string(stdout))
+ if err != nil {
+ return
+ }
+
+ args = append([]string{"pkg-config", "--libs"}, packages...)
+ stdout, stderr, ok = run(nil, args)
+ if !ok {
+ os.Stderr.Write(stderr)
+ return nil, nil, os.NewError("pkg-config failed")
+ }
+ ldflags, err = splitQuoted(string(stdout))
+ return
+}
+
// splitQuoted splits the string s around each instance of one or more consecutive
// white space characters while taking into account quotes and escaping, and
// returns an array of substrings of s or an empty list if s contains only white space.
@@ -182,6 +236,20 @@ func splitQuoted(s string) (r []string, err os.Error) {
return args, err
}
+var safeBytes = []byte("+-.,/0123456789=ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz")
+
+func safeName(s string) bool {
+ if s == "" {
+ return false
+ }
+ for i := 0; i < len(s); i++ {
+ if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
+ return false
+ }
+ }
+ return true
+}
+
// Translate rewrites f.AST, the original Go input, to remove
// references to the imported package C, replacing them with
// references to the equivalent Go types, functions, and variables.
@@ -592,11 +660,14 @@ func (p *Package) gccName() (ret string) {
}
// gccMachine returns the gcc -m flag to use, either "-m32" or "-m64".
-func (p *Package) gccMachine() string {
- if p.PtrSize == 8 {
- return "-m64"
+func (p *Package) gccMachine() []string {
+ switch runtime.GOARCH {
+ case "amd64":
+ return []string{"-m64"}
+ case "386":
+ return []string{"-m32"}
}
- return "-m32"
+ return nil
}
const gccTmp = "_obj/_cgo_.o"
@@ -604,9 +675,8 @@ const gccTmp = "_obj/_cgo_.o"
// gccCmd returns the gcc command line to use for compiling
// the input.
func (p *Package) gccCmd() []string {
- return []string{
+ c := []string{
p.gccName(),
- p.gccMachine(),
"-Wall", // many warnings
"-Werror", // warnings are errors
"-o" + gccTmp, // write object to tmp
@@ -614,15 +684,18 @@ func (p *Package) gccCmd() []string {
"-fno-eliminate-unused-debug-types", // gets rid of e.g. untyped enum otherwise
"-c", // do not link
"-xc", // input language is C
- "-", // read input from standard input
}
+ c = append(c, p.GccOptions...)
+ c = append(c, p.gccMachine()...)
+ c = append(c, "-") //read input from standard input
+ return c
}
// gccDebug runs gcc -gdwarf-2 over the C program stdin and
// returns the corresponding DWARF data and any messages
// printed to standard error.
func (p *Package) gccDebug(stdin []byte) *dwarf.Data {
- runGcc(stdin, append(p.gccCmd(), p.GccOptions...))
+ runGcc(stdin, p.gccCmd())
// Try to parse f as ELF and Mach-O and hope one works.
var f interface {
@@ -649,8 +722,9 @@ func (p *Package) gccDebug(stdin []byte) *dwarf.Data {
// #defines that gcc encountered while processing the input
// and its included files.
func (p *Package) gccDefines(stdin []byte) string {
- base := []string{p.gccName(), p.gccMachine(), "-E", "-dM", "-xc", "-"}
- stdout, _ := runGcc(stdin, append(base, p.GccOptions...))
+ base := []string{p.gccName(), "-E", "-dM", "-xc"}
+ base = append(base, p.gccMachine()...)
+ stdout, _ := runGcc(stdin, append(append(base, p.GccOptions...), "-"))
return stdout
}
@@ -659,7 +733,7 @@ func (p *Package) gccDefines(stdin []byte) string {
// gcc to fail.
func (p *Package) gccErrors(stdin []byte) string {
// TODO(rsc): require failure
- args := append(p.gccCmd(), p.GccOptions...)
+ args := p.gccCmd()
if *debugGcc {
fmt.Fprintf(os.Stderr, "$ %s <<EOF\n", strings.Join(args, " "))
os.Stderr.Write(stdin)
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index bc031cc58..dbc7bcf69 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -142,7 +142,7 @@ func dynimport(obj string) {
if f, err := pe.Open(obj); err == nil {
sym, err := f.ImportedSymbols()
if err != nil {
- fatalf("cannot load imported symbols from PE file %s: v", obj, err)
+ fatalf("cannot load imported symbols from PE file %s: %v", obj, err)
}
for _, s := range sym {
ss := strings.Split(s, ":", -1)
@@ -331,7 +331,11 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
fmt.Fprintf(fgcc, "\tint e;\n") // assuming 32 bit (see comment above structType)
fmt.Fprintf(fgcc, "\terrno = 0;\n")
}
- fmt.Fprintf(fgcc, "\t%s *a = v;\n", ctype)
+ // We're trying to write a gcc struct that matches 6c/8c/5c's layout.
+ // Use packed attribute to force no padding in this struct in case
+ // gcc has different packing requirements. For example,
+ // on 386 Windows, gcc wants to 8-align int64s, but 8c does not.
+ fmt.Fprintf(fgcc, "\t%s __attribute__((__packed__)) *a = v;\n", ctype)
fmt.Fprintf(fgcc, "\t")
if t := n.FuncType.Result; t != nil {
fmt.Fprintf(fgcc, "a->r = ")
@@ -370,7 +374,9 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
fn := exp.Func
// Construct a gcc struct matching the 6c argument and
- // result frame.
+ // result frame. The gcc struct will be compiled with
+ // __attribute__((packed)) so all padding must be accounted
+ // for explicitly.
ctype := "struct {\n"
off := int64(0)
npad := 0
@@ -458,7 +464,7 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
fmt.Fprintf(fgcc, "extern _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName)
fmt.Fprintf(fgcc, "\n%s\n", s)
fmt.Fprintf(fgcc, "{\n")
- fmt.Fprintf(fgcc, "\t%s a;\n", ctype)
+ fmt.Fprintf(fgcc, "\t%s __attribute__((packed)) a;\n", ctype)
if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
}
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile
index dbfd86474..286618ec1 100644
--- a/src/cmd/gc/Makefile
+++ b/src/cmd/gc/Makefile
@@ -49,7 +49,7 @@ include ../../Make.clib
install: $(LIB)
y1.tab.c: y.tab.c # make yystate global, yytname mutable
- cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/' >y1.tab.c
+ cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/; s/char const \*yymsgp/char *yymsgp/' >y1.tab.c
yerr.h: bisonerrors go.errors y.tab.h # y.tab.h rule generates y.output too
awk -f bisonerrors y.output go.errors >yerr.h
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
index a8454bf13..7fcac4833 100644
--- a/src/cmd/gc/align.c
+++ b/src/cmd/gc/align.c
@@ -234,9 +234,11 @@ dowidth(Type *t)
if(t->bound > cap)
yyerror("type %lT larger than address space", t);
w = t->bound * t->type->width;
- if(w == 0)
- w = 1;
t->align = t->type->align;
+ if(w == 0) {
+ w = 1;
+ t->align = 1;
+ }
}
else if(t->bound == -1) {
w = sizeof_Array;
@@ -253,10 +255,10 @@ dowidth(Type *t)
if(t->funarg)
fatal("dowidth fn struct %T", t);
w = widstruct(t, 0, 1);
- if(w == 0)
+ if(w == 0) {
w = 1;
- //if(t->align < widthptr)
- // warn("align %d: %T\n", t->align, t);
+ t->align = 1;
+ }
break;
case TFUNC:
diff --git a/src/cmd/gc/builtin.c.boot b/src/cmd/gc/builtin.c.boot
index bdbca7f78..c9bf501d1 100644
--- a/src/cmd/gc/builtin.c.boot
+++ b/src/cmd/gc/builtin.c.boot
@@ -1,5 +1,6 @@
char *runtimeimport =
"package runtime\n"
+ "import runtime \"runtime\"\n"
"func \"\".new (? int32) *any\n"
"func \"\".panicindex ()\n"
"func \"\".panicslice ()\n"
@@ -21,7 +22,6 @@ char *runtimeimport =
"func \"\".printsp ()\n"
"func \"\".goprintf ()\n"
"func \"\".concatstring ()\n"
- "func \"\".append ()\n"
"func \"\".appendslice (typ *uint8, x any, y []any) any\n"
"func \"\".cmpstring (? string, ? string) int\n"
"func \"\".slicestring (? string, ? int, ? int) string\n"
@@ -81,6 +81,7 @@ char *runtimeimport =
"func \"\".selectgo (sel *uint8)\n"
"func \"\".block ()\n"
"func \"\".makeslice (typ *uint8, nel int64, cap int64) []any\n"
+ "func \"\".growslice (typ *uint8, old []any, cap int64) []any\n"
"func \"\".sliceslice1 (old []any, lb uint64, width uint64) []any\n"
"func \"\".sliceslice (old []any, lb uint64, hb uint64, width uint64) []any\n"
"func \"\".slicearray (old *any, nel uint64, lb uint64, hb uint64, width uint64) []any\n"
@@ -98,6 +99,7 @@ char *runtimeimport =
"$$\n";
char *unsafeimport =
"package unsafe\n"
+ "import runtime \"runtime\"\n"
"type \"\".Pointer uintptr\n"
"func \"\".Offsetof (? any) int\n"
"func \"\".Sizeof (? any) int\n"
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c
index eb7014366..906dadbc9 100644
--- a/src/cmd/gc/closure.c
+++ b/src/cmd/gc/closure.c
@@ -75,7 +75,7 @@ closurebody(NodeList *body)
}
void
-typecheckclosure(Node *func)
+typecheckclosure(Node *func, int top)
{
Node *oldfn;
NodeList *l;
@@ -106,6 +106,10 @@ typecheckclosure(Node *func)
v->op = 0;
continue;
}
+ // For a closure that is called in place, but not
+ // inside a go statement, avoid moving variables to the heap.
+ if ((top & (Ecall|Eproc)) == Ecall)
+ v->heapaddr->etype = 1;
typecheck(&v->heapaddr, Erv);
func->enter = list(func->enter, v->heapaddr);
v->heapaddr = N;
@@ -199,3 +203,41 @@ walkclosure(Node *func, NodeList **init)
walkexpr(&call, init);
return call;
}
+
+// Special case for closures that get called in place.
+// Optimize runtime.closure(X, __func__xxxx_, .... ) away
+// to __func__xxxx_(Y ....).
+// On entry, expect n->op == OCALL, n->left->op == OCLOSURE.
+void
+walkcallclosure(Node *n, NodeList **init)
+{
+ Node *z;
+ NodeList *ll, *cargs;
+
+ walkexpr(&n->left, init);
+ cargs = n->left // FUNC runtime.closure
+ ->list // arguments
+ ->next // skip first
+ ->next; // skip second
+
+ n->left = n->left // FUNC runtime.closure
+ ->list // arguments
+ ->next // skip first
+ ->n // AS (to indreg)
+ ->right; // argument == the generated function
+
+ // New arg list for n. First the closure-args, stolen from
+ // runtime.closure's 3rd and following,
+ ll = nil;
+ for (; cargs; cargs = cargs->next)
+ ll = list(ll, cargs->n->right); // cargs->n is the OAS(INDREG, arg)
+
+ // then an extra zero, to fill the dummy return pointer slot,
+ z = nod(OXXX, N, N);
+ nodconst(z, types[TUINTPTR], 0);
+ z->typecheck = 1;
+ ll = list(ll, z);
+
+ // and finally the original parameter list.
+ n->list = concat(ll, n->list);
+}
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
index a36ec68c0..8fe9072b2 100644
--- a/src/cmd/gc/const.c
+++ b/src/cmd/gc/const.c
@@ -103,6 +103,8 @@ convlit1(Node **np, Type *t, int explicit)
case ORSH:
convlit1(&n->left, t, explicit && isideal(n->left->type));
t = n->left->type;
+ if(t != T && t->etype == TIDEAL && n->val.ctype != CTINT)
+ n->val = toint(n->val);
if(t != T && !isint[t->etype]) {
yyerror("invalid operation: %#N (shift of type %T)", n, t);
t = T;
@@ -514,6 +516,8 @@ evconst(Node *n)
n->right = nr;
if(nr->type && (issigned[nr->type->etype] || !isint[nr->type->etype]))
goto illegal;
+ nl->val = toint(nl->val);
+ nr->val = toint(nr->val);
break;
}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
index 8e790ef08..335d056a0 100644
--- a/src/cmd/gc/dcl.c
+++ b/src/cmd/gc/dcl.c
@@ -188,6 +188,7 @@ declare(Node *n, int ctxt)
else if(n->op == ONAME)
gen = ++vargen;
pushdcl(s);
+ n->curfn = curfn;
}
if(ctxt == PAUTO)
n->xoffset = BADWIDTH;
@@ -437,20 +438,6 @@ newtype(Sym *s)
return t;
}
-/*
- * type check top level declarations
- */
-void
-dclchecks(void)
-{
- NodeList *l;
-
- for(l=externdcl; l; l=l->next) {
- if(l->n->op != ONAME)
- continue;
- typecheck(&l->n, Erv);
- }
-}
/*
* := declarations
@@ -524,6 +511,30 @@ colas(NodeList *left, NodeList *right)
}
/*
+ * declare the arguments in an
+ * interface field declaration.
+ */
+void
+ifacedcl(Node *n)
+{
+ if(n->op != ODCLFIELD || n->right == N)
+ fatal("ifacedcl");
+
+ dclcontext = PAUTO;
+ markdcl();
+ funcdepth++;
+ n->outer = curfn;
+ curfn = n;
+ funcargs(n->right);
+
+ // funcbody is normally called after the parser has
+ // seen the body of a function but since an interface
+ // field declaration does not have a body, we must
+ // call it now to pop the current declaration context.
+ funcbody(n);
+}
+
+/*
* declare the function proper
* and declare the arguments.
* called in extern-declaration context
@@ -1226,9 +1237,6 @@ funccompile(Node *n, int isclosure)
if(curfn)
fatal("funccompile %S inside %S", n->nname->sym, curfn->nname->sym);
- curfn = n;
- typechecklist(n->nbody, Etop);
- curfn = nil;
stksize = 0;
dclcontext = PAUTO;
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
index 857fcbef9..ad7b65b30 100644
--- a/src/cmd/gc/gen.c
+++ b/src/cmd/gc/gen.c
@@ -51,6 +51,8 @@ allocparams(void)
}
if(n->op != ONAME || n->class != PAUTO)
continue;
+ if (n->xoffset != BADWIDTH)
+ continue;
if(n->type == T)
continue;
dowidth(n->type);
@@ -59,6 +61,8 @@ allocparams(void)
fatal("bad width");
stksize += w;
stksize = rnd(stksize, n->type->align);
+ if(thechar == '5')
+ stksize = rnd(stksize, widthptr);
n->xoffset = -stksize;
}
lineno = lno;
@@ -668,14 +672,18 @@ dotoffset(Node *n, int *oary, Node **nn)
* make a new off the books
*/
void
-tempname(Node *n, Type *t)
+tempname(Node *nn, Type *t)
{
+ Node *n;
Sym *s;
uint32 w;
if(stksize < 0)
fatal("tempname not during code generation");
+ if (curfn == N)
+ fatal("no curfn for tempname");
+
if(t == T) {
yyerror("tempname called with nil type");
t = types[TINT32];
@@ -686,19 +694,25 @@ tempname(Node *n, Type *t)
snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
statuniqgen++;
s = lookup(namebuf);
- memset(n, 0, sizeof(*n));
- n->op = ONAME;
+ n = nod(ONAME, N, N);
n->sym = s;
n->type = t;
n->class = PAUTO;
n->addable = 1;
n->ullman = 1;
n->noescape = 1;
+ n->curfn = curfn;
+ curfn->dcl = list(curfn->dcl, n);
dowidth(t);
w = t->width;
stksize += w;
stksize = rnd(stksize, t->align);
+ if(thechar == '5')
+ stksize = rnd(stksize, widthptr);
n->xoffset = -stksize;
- n->pun = anyregalloc();
+
+ // print("\ttmpname (%d): %N\n", stksize, n);
+
+ *nn = *n;
}
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
index 4b4e8fcd1..c16903e77 100644
--- a/src/cmd/gc/go.h
+++ b/src/cmd/gc/go.h
@@ -225,6 +225,7 @@ struct Node
Type* realtype; // as determined by typecheck
NodeList* list;
NodeList* rlist;
+ Node* orig; // original form, for printing, and tracking copies of ONAMEs
// for-body
NodeList* ninit;
@@ -253,6 +254,7 @@ struct Node
Node* ntype;
Node* defn;
Node* pack; // real package for import . names
+ Node* curfn; // function for local variables
// ONAME func param with PHEAP
Node* heapaddr; // temp holding heap address of param
@@ -271,6 +273,7 @@ struct Node
int32 lineno;
int32 endlineno;
vlong xoffset;
+ int32 stkdelta; // offset added by stack frame compaction phase.
int32 ostk;
int32 iota;
};
@@ -516,15 +519,16 @@ enum
enum
{
- Etop = 1<<1, // evaluated at statement level
- Erv = 1<<2, // evaluated in value context
+ Etop = 1<<1, // evaluated at statement level
+ Erv = 1<<2, // evaluated in value context
Etype = 1<<3,
- Ecall = 1<<4, // call-only expressions are ok
+ Ecall = 1<<4, // call-only expressions are ok
Efnstruct = 1<<5, // multivalue function returns are ok
Eiota = 1<<6, // iota is ok
Easgn = 1<<7, // assigning to expression
Eindir = 1<<8, // indirecting through expression
Eaddr = 1<<9, // taking address of expression
+ Eproc = 1<<10, // inside a go statement
};
#define BITS 5
@@ -544,6 +548,7 @@ struct Var
vlong offset;
Sym* sym;
Sym* gotype;
+ Node* node;
int width;
char name;
char etype;
@@ -814,8 +819,9 @@ int bset(Bits a, uint n);
*/
Node* closurebody(NodeList *body);
void closurehdr(Node *ntype);
-void typecheckclosure(Node *func);
+void typecheckclosure(Node *func, int top);
Node* walkclosure(Node *func, NodeList **init);
+void walkcallclosure(Node *n, NodeList **init);
/*
* const.c
@@ -858,7 +864,6 @@ NodeList* checkarglist(NodeList *all, int input);
Node* colas(NodeList *left, NodeList *right);
void colasdefn(NodeList *left, Node *defn);
NodeList* constiter(NodeList *vl, Node *t, NodeList *cl);
-void dclchecks(void);
Node* dclname(Sym *s);
void declare(Node *n, int ctxt);
Type* dostruct(NodeList *l, int et);
@@ -869,6 +874,7 @@ void funcbody(Node *n);
void funccompile(Node *n, int isclosure);
void funchdr(Node *n);
Type* functype(Node *this, NodeList *in, NodeList *out);
+void ifacedcl(Node *n);
int isifacemethod(Type *f);
void markdcl(void);
Node* methodname(Node *n, Type *t);
@@ -1103,6 +1109,7 @@ int istype(Type *t, int et);
void linehist(char *file, int32 off, int relative);
NodeList* list(NodeList *l, Node *n);
NodeList* list1(Node *n);
+void listsort(NodeList**, int(*f)(Node*, Node*));
Node* liststmt(NodeList *l);
NodeList* listtreecopy(NodeList *l);
Sym* lookup(char *name);
@@ -1161,6 +1168,11 @@ int exportassignok(Type *t, char *desc);
int islvalue(Node *n);
Node* typecheck(Node **np, int top);
void typechecklist(NodeList *l, int top);
+Node* typecheckdef(Node *n);
+void resumetypecopy(void);
+void copytype(Node *n, Type *t);
+void defertypecopy(Node *n, Type *t);
+void queuemethod(Node *n);
/*
* unsafe.c
@@ -1172,15 +1184,10 @@ Node* unsafenmagic(Node *n);
*/
Node* callnew(Type *t);
Node* chanfn(char *name, int n, Type *t);
-void copytype(Node *n, Type *t);
-void defertypecopy(Node *n, Type *t);
Node* mkcall(char *name, Type *t, NodeList **init, ...);
Node* mkcall1(Node *fn, Type *t, NodeList **init, ...);
-void queuemethod(Node *n);
-void resumetypecopy(void);
int vmatch1(Node *l, Node *r);
void walk(Node *fn);
-Node* walkdef(Node *n);
void walkexpr(Node **np, NodeList **init);
void walkexprlist(NodeList *l, NodeList **init);
void walkexprlistsafe(NodeList *l, NodeList **init);
@@ -1208,6 +1215,7 @@ EXTERN Prog* continpc;
EXTERN Prog* breakpc;
EXTERN Prog* pc;
EXTERN Prog* firstpc;
+EXTERN Prog* retpc;
EXTERN Node* nodfp;
@@ -1221,6 +1229,7 @@ void cgen_callinter(Node *n, Node *res, int proc);
void cgen_ret(Node *n);
void clearfat(Node *n);
void compile(Node*);
+void defframe(Prog*);
int dgostringptr(Sym*, int off, char *str);
int dgostrlitptr(Sym*, int off, Strlit*);
int dstringptr(Sym *s, int off, char *str);
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
index 7adfd002a..1278c2586 100644
--- a/src/cmd/gc/go.y
+++ b/src/cmd/gc/go.y
@@ -1380,6 +1380,7 @@ interfacedcl:
new_name indcl
{
$$ = nod(ODCLFIELD, $1, $2);
+ ifacedcl($$);
}
| packname
{
@@ -1791,24 +1792,12 @@ hidden_opt_sym:
}
hidden_dcl:
- hidden_opt_sym hidden_type
+ hidden_opt_sym hidden_type hidden_tag
{
$$ = nod(ODCLFIELD, $1, typenod($2));
+ $$->val = $3;
}
-| hidden_opt_sym LDDD
- {
- Type *t;
-
- yyerror("invalid variadic function type in import - recompile import");
-
- t = typ(TARRAY);
- t->bound = -1;
- t->type = typ(TINTER);
- $$ = nod(ODCLFIELD, $1, typenod(t));
- $$->isddd = 1;
- }
-
-| hidden_opt_sym LDDD hidden_type
+| hidden_opt_sym LDDD hidden_type hidden_tag
{
Type *t;
@@ -1817,6 +1806,7 @@ hidden_dcl:
t->type = $3;
$$ = nod(ODCLFIELD, $1, typenod(t));
$$->isddd = 1;
+ $$->val = $4;
}
hidden_structdcl:
diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c
index af4eb0336..8818db08c 100644
--- a/src/cmd/gc/init.c
+++ b/src/cmd/gc/init.c
@@ -182,11 +182,14 @@ fninit(NodeList *n)
// (11)
a = nod(ORETURN, N, N);
r = list(r, a);
-
exportsym(fn->nname);
fn->nbody = r;
funcbody(fn);
+
+ curfn = fn;
typecheck(&fn, Etop);
+ typechecklist(r, Etop);
+ curfn = nil;
funccompile(fn, 0);
}
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
index 04dd0d5b9..88acb60af 100644
--- a/src/cmd/gc/lex.c
+++ b/src/cmd/gc/lex.c
@@ -5,7 +5,7 @@
#define EXTERN
#include "go.h"
#include "y.tab.h"
-#include <ar.h>
+#include <ar.h>
#undef getc
#undef ungetc
@@ -235,13 +235,14 @@ main(int argc, char *argv[])
if(debug['f'])
frame(1);
- // Process top-level declarations in three phases.
+ // Process top-level declarations in four phases.
// Phase 1: const, type, and names and types of funcs.
// This will gather all the information about types
// and methods but doesn't depend on any of it.
// Phase 2: Variable assignments.
// To check interface assignments, depends on phase 1.
- // Phase 3: Function bodies.
+ // Phase 3: Type check function bodies.
+ // Phase 4: Compile function bodies.
defercheckwidth();
for(l=xtop; l; l=l->next)
if(l->n->op != ODCL && l->n->op != OAS)
@@ -251,18 +252,31 @@ main(int argc, char *argv[])
typecheck(&l->n, Etop);
resumetypecopy();
resumecheckwidth();
+
+ for(l=xtop; l; l=l->next)
+ if(l->n->op == ODCLFUNC) {
+ curfn = l->n;
+ typechecklist(l->n->nbody, Etop);
+ }
+ curfn = nil;
+
for(l=xtop; l; l=l->next)
if(l->n->op == ODCLFUNC)
funccompile(l->n, 0);
+
if(nerrors == 0)
fninit(xtop);
+
while(closures) {
l = closures;
closures = nil;
for(; l; l=l->next)
funccompile(l->n, 1);
}
- dclchecks();
+
+ for(l=externdcl; l; l=l->next)
+ if(l->n->op == ONAME)
+ typecheck(&l->n, Erv);
if(nerrors)
errorexit();
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
index 9f4b7b318..f34fc76c8 100644
--- a/src/cmd/gc/obj.c
+++ b/src/cmd/gc/obj.c
@@ -284,6 +284,7 @@ stringsym(char *s, int len)
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
ggloblsym(sym, off, 1);
text();
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
new file mode 100644
index 000000000..ab6186697
--- /dev/null
+++ b/src/cmd/gc/pgen.c
@@ -0,0 +1,224 @@
+// Copyright 2011 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 "gg.h"
+#include "opt.h"
+
+static void compactframe(Prog* p);
+
+void
+compile(Node *fn)
+{
+ Plist *pl;
+ Node nod1, *n;
+ Prog *ptxt;
+ int32 lno;
+ Type *t;
+ Iter save;
+ vlong oldstksize;
+
+ if(newproc == N) {
+ newproc = sysfunc("newproc");
+ deferproc = sysfunc("deferproc");
+ deferreturn = sysfunc("deferreturn");
+ panicindex = sysfunc("panicindex");
+ panicslice = sysfunc("panicslice");
+ throwreturn = sysfunc("throwreturn");
+ }
+
+ if(fn->nbody == nil)
+ return;
+
+ // set up domain for labels
+ clearlabels();
+
+ lno = setlineno(fn);
+
+ curfn = fn;
+ dowidth(curfn->type);
+
+ if(curfn->type->outnamed) {
+ // add clearing of the output parameters
+ t = structfirst(&save, getoutarg(curfn->type));
+ while(t != T) {
+ if(t->nname != N) {
+ n = nod(OAS, t->nname, N);
+ typecheck(&n, Etop);
+ curfn->nbody = concat(list1(n), curfn->nbody);
+ }
+ t = structnext(&save);
+ }
+ }
+
+ hasdefer = 0;
+ walk(curfn);
+ if(nerrors != 0 || isblank(curfn->nname))
+ goto ret;
+
+ allocparams();
+
+ continpc = P;
+ breakpc = P;
+
+ pl = newplist();
+ pl->name = curfn->nname;
+
+ setlineno(curfn);
+
+ nodconst(&nod1, types[TINT32], 0);
+ ptxt = gins(ATEXT, curfn->nname, &nod1);
+ afunclit(&ptxt->from);
+
+ ginit();
+ genlist(curfn->enter);
+
+ retpc = nil;
+ if(hasdefer || curfn->exit) {
+ Prog *p1;
+
+ p1 = gjmp(nil);
+ retpc = gjmp(nil);
+ patch(p1, pc);
+ }
+
+ genlist(curfn->nbody);
+ gclean();
+ checklabels();
+ if(nerrors != 0)
+ goto ret;
+ if(curfn->endlineno)
+ lineno = curfn->endlineno;
+
+ if(curfn->type->outtuple != 0)
+ ginscall(throwreturn, 0);
+
+ if(retpc)
+ patch(retpc, pc);
+ ginit();
+ if(hasdefer)
+ ginscall(deferreturn, 0);
+ if(curfn->exit)
+ genlist(curfn->exit);
+ gclean();
+ if(nerrors != 0)
+ goto ret;
+ pc->as = ARET; // overwrite AEND
+ pc->lineno = lineno;
+
+ if(!debug['N'] || debug['R'] || debug['P']) {
+ regopt(ptxt);
+ }
+
+ oldstksize = stksize;
+ if(thechar != '5')
+ compactframe(ptxt);
+ if(0)
+ print("compactframe: %ld to %ld\n", oldstksize, stksize);
+
+ defframe(ptxt);
+
+ if(0)
+ frame(0);
+
+ret:
+ lineno = lno;
+}
+
+
+// Sort the list of stack variables. autos after anything else,
+// within autos, unused after used, and within used on reverse alignment.
+// non-autos sort on offset.
+static int
+cmpstackvar(Node *a, Node *b)
+{
+ if (a->class != b->class)
+ return (a->class == PAUTO) ? 1 : -1;
+ if (a->class != PAUTO)
+ return a->xoffset - b->xoffset;
+ if ((a->used == 0) != (b->used == 0))
+ return b->used - a->used;
+ return b->type->align - a->type->align;
+
+}
+
+static void
+compactframe(Prog* ptxt)
+{
+ NodeList *ll;
+ Node* n;
+ Prog *p;
+ uint32 w;
+
+ if (stksize == 0)
+ return;
+
+ // Mark the PAUTO's unused.
+ for(ll=curfn->dcl; ll != nil; ll=ll->next)
+ if (ll->n->class == PAUTO && ll->n->op == ONAME)
+ ll->n->used = 0;
+
+ // Sweep the prog list to mark any used nodes.
+ for (p = ptxt; p; p = p->link) {
+ if (p->from.type == D_AUTO && p->from.node)
+ p->from.node->used++;
+
+ if (p->to.type == D_AUTO && p->to.node)
+ p->to.node->used++;
+ }
+
+ listsort(&curfn->dcl, cmpstackvar);
+
+ // Unused autos are at the end, chop 'em off.
+ ll = curfn->dcl;
+ n = ll->n;
+ if (n->class == PAUTO && n->op == ONAME && !n->used) {
+ curfn->dcl = nil;
+ stksize = 0;
+ return;
+ }
+
+ for(ll = curfn->dcl; ll->next != nil; ll=ll->next) {
+ n = ll->next->n;
+ if (n->class == PAUTO && n->op == ONAME && !n->used) {
+ ll->next = nil;
+ curfn->dcl->end = ll;
+ break;
+ }
+ }
+
+ // Reassign stack offsets of the locals that are still there.
+ stksize = 0;
+ for(ll = curfn->dcl; ll != nil; ll=ll->next) {
+ n = ll->n;
+ // TODO find out where the literal autos come from
+ if (n->class != PAUTO || n->op != ONAME)
+ continue;
+
+ w = n->type->width;
+ if((w >= MAXWIDTH) || (w < 1))
+ fatal("bad width");
+ stksize += w;
+ stksize = rnd(stksize, n->type->align);
+ if(thechar == '5')
+ stksize = rnd(stksize, widthptr);
+ n->stkdelta = -stksize - n->xoffset;
+ }
+
+ // Fixup instructions.
+ for (p = ptxt; p; p = p->link) {
+ if (p->from.type == D_AUTO && p->from.node)
+ p->from.offset += p->from.node->stkdelta;
+
+ if (p->to.type == D_AUTO && p->to.node)
+ p->to.offset += p->to.node->stkdelta;
+ }
+
+ // The debug information needs accurate offsets on the symbols.
+ for(ll = curfn->dcl ;ll != nil; ll=ll->next) {
+ if (ll->n->class != PAUTO || ll->n->op != ONAME)
+ continue;
+ ll->n->xoffset += ll->n->stkdelta;
+ ll->n->stkdelta = 0;
+ }
+}
diff --git a/src/cmd/gc/print.c b/src/cmd/gc/print.c
index e03a14080..e88e0f844 100644
--- a/src/cmd/gc/print.c
+++ b/src/cmd/gc/print.c
@@ -134,6 +134,10 @@ exprfmt(Fmt *f, Node *n, int prec)
fmtprint(f, "(node %O)", n->op);
break;
+ case OREGISTER:
+ fmtprint(f, "%R", n->val.u.reg);
+ break;
+
case OLITERAL:
if(n->sym != S) {
fmtprint(f, "%S", n->sym);
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
index 35d11eca9..00fc720b8 100644
--- a/src/cmd/gc/runtime.go
+++ b/src/cmd/gc/runtime.go
@@ -110,6 +110,7 @@ func selectgo(sel *byte)
func block()
func makeslice(typ *byte, nel int64, cap int64) (ary []any)
+func growslice(typ *byte, old []any, n int64) (ary []any)
func sliceslice1(old []any, lb uint64, width uint64) (ary []any)
func sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
func slicearray(old *any, nel uint64, lb uint64, hb uint64, width uint64) (ary []any)
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
index be96a1477..eb7ef31ec 100644
--- a/src/cmd/gc/sinit.c
+++ b/src/cmd/gc/sinit.c
@@ -173,10 +173,10 @@ initfix(NodeList *l)
/*
* from here down is the walk analysis
- * of composit literals.
+ * of composite literals.
* most of the work is to generate
* data statements for the constant
- * part of the composit literal.
+ * part of the composite literal.
*/
static void structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index bb2505694..49797f9df 100644
--- a/src/cmd/gc/subr.c
+++ b/src/cmd/gc/subr.c
@@ -105,7 +105,7 @@ hcrash(void)
flusherrors();
if(outfile)
unlink(outfile);
- *(int*)0 = 0;
+ *(volatile int*)0 = 0;
}
}
@@ -480,6 +480,7 @@ nod(int op, Node *nleft, Node *nright)
n->right = nright;
n->lineno = parserline();
n->xoffset = BADWIDTH;
+ n->orig = n;
return n;
}
@@ -1031,10 +1032,21 @@ Econv(Fmt *fp)
return fmtstrcpy(fp, etnames[et]);
}
+static const char* classnames[] = {
+ "Pxxx",
+ "PEXTERN",
+ "PAUTO",
+ "PPARAM",
+ "PPARAMOUT",
+ "PPARAMREF",
+ "PFUNC",
+};
+
int
Jconv(Fmt *fp)
{
Node *n;
+ char *s;
n = va_arg(fp->args, Node*);
if(n->ullman != 0)
@@ -1049,12 +1061,18 @@ Jconv(Fmt *fp)
if(n->lineno != 0)
fmtprint(fp, " l(%d)", n->lineno);
- if(n->xoffset != 0)
- fmtprint(fp, " x(%lld)", n->xoffset);
-
- if(n->class != 0)
- fmtprint(fp, " class(%d)", n->class);
+ if(n->xoffset != BADWIDTH)
+ fmtprint(fp, " x(%lld%+d)", n->xoffset, n->stkdelta);
+ if(n->class != 0) {
+ s = "";
+ if (n->class & PHEAP) s = ",heap";
+ if ((n->class & ~PHEAP) < nelem(classnames))
+ fmtprint(fp, " class(%s%s)", classnames[n->class&~PHEAP], s);
+ else
+ fmtprint(fp, " class(%d?%s)", n->class&~PHEAP, s);
+ }
+
if(n->colas != 0)
fmtprint(fp, " colas(%d)", n->colas);
@@ -1073,6 +1091,11 @@ Jconv(Fmt *fp)
if(n->implicit != 0)
fmtprint(fp, " implicit(%d)", n->implicit);
+ if(n->pun != 0)
+ fmtprint(fp, " pun(%d)", n->pun);
+
+ if(n->used != 0)
+ fmtprint(fp, " used(%d)", n->used);
return 0;
}
@@ -1141,7 +1164,7 @@ Tpretty(Fmt *fp, Type *t)
Type *t1;
Sym *s;
- if(debug['r']) {
+ if(0 && debug['r']) {
debug['r'] = 0;
fmtprint(fp, "%T (orig=%T)", t, t->orig);
debug['r'] = 1;
@@ -1454,6 +1477,8 @@ Nconv(Fmt *fp)
}
if(fp->flags & FmtSharp) {
+ if(n->orig != N)
+ n = n->orig;
exprfmt(fp, n, 0);
goto out;
}
@@ -3107,7 +3132,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
Type *tpad;
int isddd;
- if(debug['r'])
+ if(0 && debug['r'])
print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
rcvr, method, newnam);
@@ -3161,11 +3186,14 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
fn->nbody = list1(n);
}
- if(debug['r'])
+ if(0 && debug['r'])
dumplist("genwrapper body", fn->nbody);
funcbody(fn);
+ curfn = fn;
typecheck(&fn, Etop);
+ typechecklist(fn->nbody, Etop);
+ curfn = nil;
funccompile(fn, 0);
}
@@ -3256,8 +3284,9 @@ implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr)
// the method does not exist for value types.
rcvr = getthisx(tm->type)->type->type;
if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm->type)) {
- if(debug['r'])
+ if(0 && debug['r'])
yyerror("interface pointer mismatch");
+
*m = im;
*samename = nil;
*ptr = 1;
@@ -3330,6 +3359,64 @@ list(NodeList *l, Node *n)
return concat(l, list1(n));
}
+void
+listsort(NodeList** l, int(*f)(Node*, Node*))
+{
+ NodeList *l1, *l2, *le;
+
+ if(*l == nil || (*l)->next == nil)
+ return;
+
+ l1 = *l;
+ l2 = *l;
+ for(;;) {
+ l2 = l2->next;
+ if(l2 == nil)
+ break;
+ l2 = l2->next;
+ if(l2 == nil)
+ break;
+ l1 = l1->next;
+ }
+
+ l2 = l1->next;
+ l1->next = nil;
+ l2->end = (*l)->end;
+ (*l)->end = l1;
+
+ l1 = *l;
+ listsort(&l1, f);
+ listsort(&l2, f);
+
+ if ((*f)(l1->n, l2->n) < 0) {
+ *l = l1;
+ } else {
+ *l = l2;
+ l2 = l1;
+ l1 = *l;
+ }
+
+ // now l1 == *l; and l1 < l2
+
+ while ((l1 != nil) && (l2 != nil)) {
+ while ((l1->next != nil) && (*f)(l1->next->n, l2->n) < 0)
+ l1 = l1->next;
+
+ // l1 is last one from l1 that is < l2
+ le = l1->next; // le is the rest of l1, first one that is >= l2
+ if (le != nil)
+ le->end = (*l)->end;
+
+ (*l)->end = l1; // cut *l at l1
+ *l = concat(*l, l2); // glue l2 to *l's tail
+
+ l1 = l2; // l1 is the first element of *l that is < the new l2
+ l2 = le; // ... because l2 now is the old tail of l1
+ }
+
+ *l = concat(*l, l2); // any remainder
+}
+
NodeList*
listtreecopy(NodeList *l)
{
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c
index 6e8436c3c..c2968c44b 100644
--- a/src/cmd/gc/swt.c
+++ b/src/cmd/gc/swt.c
@@ -867,8 +867,11 @@ typecheckswitch(Node *n)
case Etype: // type switch
if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL))
;
- else if(ll->n->op != OTYPE && ll->n->type != T)
+ else if(ll->n->op != OTYPE && ll->n->type != T) {
yyerror("%#N is not a type", ll->n);
+ // reset to original type
+ ll->n = n->ntest->right;
+ }
break;
}
}
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
index c48bf7a29..04dc1a507 100644
--- a/src/cmd/gc/typecheck.c
+++ b/src/cmd/gc/typecheck.c
@@ -8,7 +8,6 @@
* evaluates compile time constants.
* marks variables that escape the local frame.
* rewrites n->op to be more specific in some cases.
- * sets n->walk to walking function.
*/
#include "go.h"
@@ -29,10 +28,12 @@ static void typecheckfunc(Node*);
static void checklvalue(Node*, char*);
static void checkassign(Node*);
static void checkassignlist(NodeList*);
-static void stringtoarraylit(Node**);
-static Node* resolve(Node*);
+static void stringtoarraylit(Node**);
+static Node* resolve(Node*);
static Type* getforwtype(Node*);
+static NodeList* typecheckdefstack;
+
/*
* resolve ONONAME to definition, if any.
*/
@@ -159,7 +160,7 @@ typecheck(Node **np, int top)
if(n->op == OTYPE && (ft = getforwtype(n->ntype)) != T)
defertypecopy(n, ft);
- walkdef(n);
+ typecheckdef(n);
n->realtype = n->type;
if(n->op == ONONAME)
goto error;
@@ -780,7 +781,7 @@ reswitch:
n = r;
goto reswitch;
}
- typecheck(&n->left, Erv | Etype | Ecall);
+ typecheck(&n->left, Erv | Etype | Ecall |(top&Eproc));
l = n->left;
if(l->op == ONAME && l->etype != 0) {
if(n->isddd && l->etype != OAPPEND)
@@ -794,7 +795,7 @@ reswitch:
defaultlit(&n->left, T);
l = n->left;
if(l->op == OTYPE) {
- if(n->isddd)
+ if(n->isddd || l->type->bound == -100)
yyerror("invalid use of ... in type conversion", l);
// pick off before type-checking arguments
ok |= Erv;
@@ -822,7 +823,13 @@ reswitch:
case ODOTMETH:
n->op = OCALLMETH;
- typecheckaste(OCALL, n->left, 0, getthisx(t), list1(l->left), "method receiver");
+ // typecheckaste was used here but there wasn't enough
+ // information further down the call chain to know if we
+ // were testing a method receiver for unexported fields.
+ // It isn't necessary, so just do a sanity check.
+ tp = getthisx(t)->type->type;
+ if(l->left == N || !eqtype(l->left->type, tp))
+ fatal("method receiver");
break;
default:
@@ -894,12 +901,20 @@ reswitch:
// might be constant
switch(t->etype) {
case TSTRING:
- if(isconst(l, CTSTR))
- nodconst(n, types[TINT], l->val.u.sval->len);
+ if(isconst(l, CTSTR)) {
+ r = nod(OXXX, N, N);
+ nodconst(r, types[TINT], l->val.u.sval->len);
+ r->orig = n;
+ n = r;
+ }
break;
case TARRAY:
- if(t->bound >= 0 && l->op == ONAME)
- nodconst(n, types[TINT], t->bound);
+ if(t->bound >= 0 && l->op == ONAME) {
+ r = nod(OXXX, N, N);
+ nodconst(r, types[TINT], t->bound);
+ r->orig = n;
+ n = r;
+ }
break;
}
n->type = types[TINT];
@@ -1013,9 +1028,9 @@ reswitch:
// copy([]byte, string)
if(isslice(n->left->type) && n->right->type->etype == TSTRING) {
- if (n->left->type->type ==types[TUINT8])
- goto ret;
- yyerror("arguments to copy have different element types: %lT and string", n->left->type);
+ if (n->left->type->type == types[TUINT8])
+ goto ret;
+ yyerror("arguments to copy have different element types: %lT and string", n->left->type);
goto error;
}
@@ -1203,7 +1218,7 @@ reswitch:
case OCLOSURE:
ok |= Erv;
- typecheckclosure(n);
+ typecheckclosure(n, top);
if(n->type == T)
goto error;
goto ret;
@@ -1232,11 +1247,15 @@ reswitch:
goto ret;
case ODEFER:
- case OPROC:
ok |= Etop;
typecheck(&n->left, Etop);
goto ret;
+ case OPROC:
+ ok |= Etop;
+ typecheck(&n->left, Etop|Eproc);
+ goto ret;
+
case OFOR:
ok |= Etop;
typechecklist(n->ninit, Etop);
@@ -1357,7 +1376,10 @@ ret:
goto error;
}
if((top & Etop) && !(top & (Ecall|Erv|Etype)) && !(ok & Etop)) {
- yyerror("%#N not used", n);
+ if(n->diag == 0) {
+ yyerror("%#N not used", n);
+ n->diag = 1;
+ }
goto error;
}
@@ -2148,7 +2170,9 @@ addrescapes(Node *n)
if(n->noescape)
break;
switch(n->class) {
- case PAUTO:
+ case PPARAMREF:
+ addrescapes(n->defn);
+ break;
case PPARAM:
case PPARAMOUT:
// if func param, need separate temporary
@@ -2156,16 +2180,17 @@ addrescapes(Node *n)
// the function type has already been checked
// (we're in the function body)
// so the param already has a valid xoffset.
- if(n->class == PPARAM || n->class == PPARAMOUT) {
- // expression to refer to stack copy
- n->stackparam = nod(OPARAM, n, N);
- n->stackparam->type = n->type;
- n->stackparam->addable = 1;
- if(n->xoffset == BADWIDTH)
- fatal("addrescapes before param assignment");
- n->stackparam->xoffset = n->xoffset;
- n->xoffset = 0;
- }
+
+ // expression to refer to stack copy
+ n->stackparam = nod(OPARAM, n, N);
+ n->stackparam->type = n->type;
+ n->stackparam->addable = 1;
+ if(n->xoffset == BADWIDTH)
+ fatal("addrescapes before param assignment");
+ n->stackparam->xoffset = n->xoffset;
+ n->xoffset = 0;
+ // fallthrough
+ case PAUTO:
n->class |= PHEAP;
n->addable = 0;
@@ -2178,7 +2203,9 @@ addrescapes(Node *n)
snprint(buf, sizeof buf, "&%S", n->sym);
n->heapaddr->sym = lookup(buf);
n->heapaddr->class = PHEAP-1; // defer tempname to allocparams
- curfn->dcl = list(curfn->dcl, n->heapaddr);
+ n->heapaddr->ullman = 1;
+ n->curfn->dcl = list(n->curfn->dcl, n->heapaddr);
+
break;
}
break;
@@ -2497,3 +2524,294 @@ getforwtype(Node *n)
}
}
}
+
+static int ntypecheckdeftype;
+static NodeList *methodqueue;
+
+static void
+domethod(Node *n)
+{
+ Node *nt;
+
+ nt = n->type->nname;
+ typecheck(&nt, Etype);
+ if(nt->type == T) {
+ // type check failed; leave empty func
+ n->type->etype = TFUNC;
+ n->type->nod = N;
+ return;
+ }
+ *n->type = *nt->type;
+ n->type->nod = N;
+ checkwidth(n->type);
+}
+
+typedef struct NodeTypeList NodeTypeList;
+struct NodeTypeList {
+ Node *n;
+ Type *t;
+ NodeTypeList *next;
+};
+
+static NodeTypeList *dntq;
+static NodeTypeList *dntend;
+
+void
+defertypecopy(Node *n, Type *t)
+{
+ NodeTypeList *ntl;
+
+ if(n == N || t == T)
+ return;
+
+ ntl = mal(sizeof *ntl);
+ ntl->n = n;
+ ntl->t = t;
+ ntl->next = nil;
+
+ if(dntq == nil)
+ dntq = ntl;
+ else
+ dntend->next = ntl;
+
+ dntend = ntl;
+}
+
+void
+resumetypecopy(void)
+{
+ NodeTypeList *l;
+
+ for(l=dntq; l; l=l->next)
+ copytype(l->n, l->t);
+}
+
+void
+copytype(Node *n, Type *t)
+{
+ *n->type = *t;
+
+ t = n->type;
+ t->sym = n->sym;
+ t->local = n->local;
+ t->vargen = n->vargen;
+ t->siggen = 0;
+ t->method = nil;
+ t->nod = N;
+ t->printed = 0;
+ t->deferwidth = 0;
+}
+
+static void
+typecheckdeftype(Node *n)
+{
+ int maplineno, embedlineno, lno;
+ Type *t;
+ NodeList *l;
+
+ ntypecheckdeftype++;
+ lno = lineno;
+ setlineno(n);
+ n->type->sym = n->sym;
+ n->typecheck = 1;
+ typecheck(&n->ntype, Etype);
+ if((t = n->ntype->type) == T) {
+ n->diag = 1;
+ goto ret;
+ }
+ if(n->type == T) {
+ n->diag = 1;
+ goto ret;
+ }
+
+ maplineno = n->type->maplineno;
+ embedlineno = n->type->embedlineno;
+
+ // copy new type and clear fields
+ // that don't come along.
+ // anything zeroed here must be zeroed in
+ // typedcl2 too.
+ copytype(n, t);
+
+ // double-check use of type as map key.
+ if(maplineno) {
+ lineno = maplineno;
+ maptype(n->type, types[TBOOL]);
+ }
+ if(embedlineno) {
+ lineno = embedlineno;
+ if(isptr[t->etype])
+ yyerror("embedded type cannot be a pointer");
+ }
+
+ret:
+ lineno = lno;
+
+ // if there are no type definitions going on, it's safe to
+ // try to resolve the method types for the interfaces
+ // we just read.
+ if(ntypecheckdeftype == 1) {
+ while((l = methodqueue) != nil) {
+ methodqueue = nil;
+ for(; l; l=l->next)
+ domethod(l->n);
+ }
+ }
+ ntypecheckdeftype--;
+}
+
+void
+queuemethod(Node *n)
+{
+ if(ntypecheckdeftype == 0) {
+ domethod(n);
+ return;
+ }
+ methodqueue = list(methodqueue, n);
+}
+
+Node*
+typecheckdef(Node *n)
+{
+ int lno;
+ Node *e;
+ Type *t;
+ NodeList *l;
+
+ lno = lineno;
+ setlineno(n);
+
+ if(n->op == ONONAME) {
+ if(!n->diag) {
+ n->diag = 1;
+ if(n->lineno != 0)
+ lineno = n->lineno;
+ yyerror("undefined: %S", n->sym);
+ }
+ return n;
+ }
+
+ if(n->walkdef == 1)
+ return n;
+
+ l = mal(sizeof *l);
+ l->n = n;
+ l->next = typecheckdefstack;
+ typecheckdefstack = l;
+
+ if(n->walkdef == 2) {
+ flusherrors();
+ print("typecheckdef loop:");
+ for(l=typecheckdefstack; l; l=l->next)
+ print(" %S", l->n->sym);
+ print("\n");
+ fatal("typecheckdef loop");
+ }
+ n->walkdef = 2;
+
+ if(n->type != T || n->sym == S) // builtin or no name
+ goto ret;
+
+ switch(n->op) {
+ default:
+ fatal("typecheckdef %O", n->op);
+
+ case OLITERAL:
+ if(n->ntype != N) {
+ typecheck(&n->ntype, Etype);
+ n->type = n->ntype->type;
+ n->ntype = N;
+ if(n->type == T) {
+ n->diag = 1;
+ goto ret;
+ }
+ }
+ e = n->defn;
+ n->defn = N;
+ if(e == N) {
+ lineno = n->lineno;
+ dump("typecheckdef nil defn", n);
+ yyerror("xxx");
+ }
+ typecheck(&e, Erv | Eiota);
+ if(e->type != T && e->op != OLITERAL) {
+ yyerror("const initializer must be constant");
+ goto ret;
+ }
+ if(isconst(e, CTNIL)) {
+ yyerror("const initializer cannot be nil");
+ goto ret;
+ }
+ t = n->type;
+ if(t != T) {
+ if(!okforconst[t->etype]) {
+ yyerror("invalid constant type %T", t);
+ goto ret;
+ }
+ if(!isideal(e->type) && !eqtype(t, e->type)) {
+ yyerror("cannot use %+N as type %T in const initializer", e, t);
+ goto ret;
+ }
+ convlit(&e, t);
+ }
+ n->val = e->val;
+ n->type = e->type;
+ break;
+
+ case ONAME:
+ if(n->ntype != N) {
+ typecheck(&n->ntype, Etype);
+ n->type = n->ntype->type;
+ if(n->type == T) {
+ n->diag = 1;
+ goto ret;
+ }
+ }
+ if(n->type != T)
+ break;
+ if(n->defn == N) {
+ if(n->etype != 0) // like OPRINTN
+ break;
+ if(nerrors > 0) {
+ // Can have undefined variables in x := foo
+ // that make x have an n->ndefn == nil.
+ // If there are other errors anyway, don't
+ // bother adding to the noise.
+ break;
+ }
+ fatal("var without type, init: %S", n->sym);
+ }
+ if(n->defn->op == ONAME) {
+ typecheck(&n->defn, Erv);
+ n->type = n->defn->type;
+ break;
+ }
+ typecheck(&n->defn, Etop); // fills in n->type
+ break;
+
+ case OTYPE:
+ if(curfn)
+ defercheckwidth();
+ n->walkdef = 1;
+ n->type = typ(TFORW);
+ n->type->sym = n->sym;
+ typecheckdeftype(n);
+ if(curfn)
+ resumecheckwidth();
+ break;
+
+ case OPACK:
+ // nothing to see here
+ break;
+ }
+
+ret:
+ if(typecheckdefstack->n != n)
+ fatal("typecheckdefstack mismatch");
+ l = typecheckdefstack;
+ typecheckdefstack = l->next;
+
+ lineno = lno;
+ n->walkdef = 1;
+ return n;
+}
diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c
index 33f375631..540994ddd 100644
--- a/src/cmd/gc/unsafe.c
+++ b/src/cmd/gc/unsafe.c
@@ -41,6 +41,7 @@ unsafenmagic(Node *nn)
tr = r->type;
if(tr == T)
goto bad;
+ dowidth(tr);
v = tr->width;
goto yes;
}
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
index 278eef414..65a504bff 100644
--- a/src/cmd/gc/walk.c
+++ b/src/cmd/gc/walk.c
@@ -18,12 +18,11 @@ static NodeList* paramstoheap(Type **argin, int out);
static NodeList* reorder1(NodeList*);
static NodeList* reorder3(NodeList*);
static Node* addstr(Node*, NodeList**);
+static Node* appendslice(Node*, NodeList**);
static Node* append(Node*, NodeList**);
-static NodeList* walkdefstack;
-
// can this code branch reach the end
-// without an undcontitional RETURN
+// without an unconditional RETURN
// this is hard, so it is conservative
static int
walkret(NodeList *l)
@@ -65,6 +64,7 @@ walk(Node *fn)
int lno;
curfn = fn;
+
if(debug['W']) {
snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym);
dumplist(s, curfn->nbody);
@@ -72,7 +72,7 @@ walk(Node *fn)
if(curfn->type->outtuple)
if(walkret(curfn->nbody))
yyerror("function ends without a return statement");
- typechecklist(curfn->nbody, Etop);
+
lno = lineno;
for(l=fn->dcl; l; l=l->next) {
n = l->n;
@@ -98,296 +98,6 @@ walk(Node *fn)
}
}
-static int nwalkdeftype;
-static NodeList *methodqueue;
-
-static void
-domethod(Node *n)
-{
- Node *nt;
-
- nt = n->type->nname;
- typecheck(&nt, Etype);
- if(nt->type == T) {
- // type check failed; leave empty func
- n->type->etype = TFUNC;
- n->type->nod = N;
- return;
- }
- *n->type = *nt->type;
- n->type->nod = N;
- checkwidth(n->type);
-}
-
-typedef struct NodeTypeList NodeTypeList;
-struct NodeTypeList {
- Node *n;
- Type *t;
- NodeTypeList *next;
-};
-
-static NodeTypeList *dntq;
-static NodeTypeList *dntend;
-
-void
-defertypecopy(Node *n, Type *t)
-{
- NodeTypeList *ntl;
-
- if(n == N || t == T)
- return;
-
- ntl = mal(sizeof *ntl);
- ntl->n = n;
- ntl->t = t;
- ntl->next = nil;
-
- if(dntq == nil)
- dntq = ntl;
- else
- dntend->next = ntl;
-
- dntend = ntl;
-}
-
-void
-resumetypecopy(void)
-{
- NodeTypeList *l;
-
- for(l=dntq; l; l=l->next)
- copytype(l->n, l->t);
-}
-
-void
-copytype(Node *n, Type *t)
-{
- *n->type = *t;
-
- t = n->type;
- t->sym = n->sym;
- t->local = n->local;
- t->vargen = n->vargen;
- t->siggen = 0;
- t->method = nil;
- t->nod = N;
- t->printed = 0;
- t->deferwidth = 0;
-}
-
-static void
-walkdeftype(Node *n)
-{
- int maplineno, embedlineno, lno;
- Type *t;
- NodeList *l;
-
- nwalkdeftype++;
- lno = lineno;
- setlineno(n);
- n->type->sym = n->sym;
- n->typecheck = 1;
- typecheck(&n->ntype, Etype);
- if((t = n->ntype->type) == T) {
- n->diag = 1;
- goto ret;
- }
- if(n->type == T) {
- n->diag = 1;
- goto ret;
- }
-
- maplineno = n->type->maplineno;
- embedlineno = n->type->embedlineno;
-
- // copy new type and clear fields
- // that don't come along.
- // anything zeroed here must be zeroed in
- // typedcl2 too.
- copytype(n, t);
-
- // double-check use of type as map key.
- if(maplineno) {
- lineno = maplineno;
- maptype(n->type, types[TBOOL]);
- }
- if(embedlineno) {
- lineno = embedlineno;
- if(isptr[t->etype])
- yyerror("embedded type cannot be a pointer");
- }
-
-ret:
- lineno = lno;
-
- // if there are no type definitions going on, it's safe to
- // try to resolve the method types for the interfaces
- // we just read.
- if(nwalkdeftype == 1) {
- while((l = methodqueue) != nil) {
- methodqueue = nil;
- for(; l; l=l->next)
- domethod(l->n);
- }
- }
- nwalkdeftype--;
-}
-
-void
-queuemethod(Node *n)
-{
- if(nwalkdeftype == 0) {
- domethod(n);
- return;
- }
- methodqueue = list(methodqueue, n);
-}
-
-Node*
-walkdef(Node *n)
-{
- int lno;
- Node *e;
- Type *t;
- NodeList *l;
-
- lno = lineno;
- setlineno(n);
-
- if(n->op == ONONAME) {
- if(!n->diag) {
- n->diag = 1;
- if(n->lineno != 0)
- lineno = n->lineno;
- yyerror("undefined: %S", n->sym);
- }
- return n;
- }
-
- if(n->walkdef == 1)
- return n;
-
- l = mal(sizeof *l);
- l->n = n;
- l->next = walkdefstack;
- walkdefstack = l;
-
- if(n->walkdef == 2) {
- flusherrors();
- print("walkdef loop:");
- for(l=walkdefstack; l; l=l->next)
- print(" %S", l->n->sym);
- print("\n");
- fatal("walkdef loop");
- }
- n->walkdef = 2;
-
- if(n->type != T || n->sym == S) // builtin or no name
- goto ret;
-
- switch(n->op) {
- default:
- fatal("walkdef %O", n->op);
-
- case OLITERAL:
- if(n->ntype != N) {
- typecheck(&n->ntype, Etype);
- n->type = n->ntype->type;
- n->ntype = N;
- if(n->type == T) {
- n->diag = 1;
- goto ret;
- }
- }
- e = n->defn;
- n->defn = N;
- if(e == N) {
- lineno = n->lineno;
- dump("walkdef nil defn", n);
- yyerror("xxx");
- }
- typecheck(&e, Erv | Eiota);
- if(e->type != T && e->op != OLITERAL) {
- yyerror("const initializer must be constant");
- goto ret;
- }
- if(isconst(e, CTNIL)) {
- yyerror("const initializer cannot be nil");
- goto ret;
- }
- t = n->type;
- if(t != T) {
- if(!okforconst[t->etype]) {
- yyerror("invalid constant type %T", t);
- goto ret;
- }
- if(!isideal(e->type) && !eqtype(t, e->type)) {
- yyerror("cannot use %+N as type %T in const initializer", e, t);
- goto ret;
- }
- convlit(&e, t);
- }
- n->val = e->val;
- n->type = e->type;
- break;
-
- case ONAME:
- if(n->ntype != N) {
- typecheck(&n->ntype, Etype);
- n->type = n->ntype->type;
- if(n->type == T) {
- n->diag = 1;
- goto ret;
- }
- }
- if(n->type != T)
- break;
- if(n->defn == N) {
- if(n->etype != 0) // like OPRINTN
- break;
- if(nerrors > 0) {
- // Can have undefined variables in x := foo
- // that make x have an n->ndefn == nil.
- // If there are other errors anyway, don't
- // bother adding to the noise.
- break;
- }
- fatal("var without type, init: %S", n->sym);
- }
- if(n->defn->op == ONAME) {
- typecheck(&n->defn, Erv);
- n->type = n->defn->type;
- break;
- }
- typecheck(&n->defn, Etop); // fills in n->type
- break;
-
- case OTYPE:
- if(curfn)
- defercheckwidth();
- n->walkdef = 1;
- n->type = typ(TFORW);
- n->type->sym = n->sym;
- walkdeftype(n);
- if(curfn)
- resumecheckwidth();
- break;
-
- case OPACK:
- // nothing to see here
- break;
- }
-
-ret:
- if(walkdefstack->n != n)
- fatal("walkdefstack mismatch");
- l = walkdefstack;
- walkdefstack = l->next;
-
- lineno = lno;
- n->walkdef = 1;
- return n;
-}
void
walkstmtlist(NodeList *l)
@@ -467,8 +177,10 @@ walkstmt(Node **np)
case OPANIC:
case OEMPTY:
case ORECOVER:
- if(n->typecheck == 0)
+ if(n->typecheck == 0) {
+ dump("missing typecheck:", n);
fatal("missing typecheck");
+ }
init = n->ninit;
n->ninit = nil;
walkexpr(&n, &init);
@@ -769,8 +481,15 @@ walkexpr(Node **np, NodeList **init)
t = n->left->type;
if(n->list && n->list->n->op == OAS)
goto ret;
- walkexpr(&n->left, init);
+
+ if(n->left->op == OCLOSURE) {
+ walkcallclosure(n, init);
+ t = n->left->type;
+ } else
+ walkexpr(&n->left, init);
+
walkexprlist(n->list, init);
+
ll = ascompatte(n->op, n->isddd, getinarg(t), n->list, 0, init);
n->list = reorder1(ll);
if(isselect(n)) {
@@ -805,18 +524,17 @@ walkexpr(Node **np, NodeList **init)
n->ninit = nil;
walkexpr(&n->left, init);
n->left = safeexpr(n->left, init);
+
if(oaslit(n, init))
goto ret;
+
walkexpr(&n->right, init);
- l = n->left;
- r = n->right;
- if(l == N || r == N)
- goto ret;
- r = ascompatee1(n->op, l, r, init);
- if(r != N) {
+ if(n->left != N && n->right != N) {
+ r = convas(nod(OAS, n->left, n->right), init);
r->dodata = n->dodata;
n = r;
}
+
goto ret;
case OAS2:
@@ -1134,6 +852,7 @@ walkexpr(Node **np, NodeList **init)
case OINDEXMAP:
if(n->etype == 1)
goto ret;
+
t = n->left->type;
n = mkcall1(mapfn("mapaccess1", t), t->type, init, n->left, n->right);
goto ret;
@@ -1188,6 +907,7 @@ walkexpr(Node **np, NodeList **init)
// sliceslice(old []any, lb uint64, hb uint64, width uint64) (ary []any)
// sliceslice1(old []any, lb uint64, width uint64) (ary []any)
t = n->type;
+ et = n->etype;
if(n->right->left == N)
l = nodintconst(0);
else
@@ -1210,6 +930,7 @@ walkexpr(Node **np, NodeList **init)
l,
nodintconst(t->type->width));
}
+ n->etype = et; // preserve no-typecheck flag from OSLICE to the slice* call.
goto ret;
slicearray:
@@ -1332,7 +1053,10 @@ walkexpr(Node **np, NodeList **init)
goto ret;
case OAPPEND:
- n = append(n, init);
+ if(n->isddd)
+ n = appendslice(n, init);
+ else
+ n = append(n, init);
goto ret;
case OCOPY:
@@ -1519,7 +1243,7 @@ ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init)
static int
fncall(Node *l, Type *rt)
{
- if(l->ullman >= UINF)
+ if(l->ullman >= UINF || l->op == OINDEXMAP)
return 1;
if(eqtype(l->type, rt))
return 0;
@@ -1953,23 +1677,18 @@ callnew(Type *t)
static Node*
convas(Node *n, NodeList **init)
{
- Node *l, *r;
Type *lt, *rt;
if(n->op != OAS)
fatal("convas: not OAS %O", n->op);
- n->typecheck = 1;
- lt = T;
- rt = T;
+ n->typecheck = 1;
- l = n->left;
- r = n->right;
- if(l == N || r == N)
+ if(n->left == N || n->right == N)
goto out;
- lt = l->type;
- rt = r->type;
+ lt = n->left->type;
+ rt = n->right->type;
if(lt == T || rt == T)
goto out;
@@ -1987,7 +1706,7 @@ convas(Node *n, NodeList **init)
if(eqtype(lt, rt))
goto out;
- n->right = assignconv(r, lt, "assignment");
+ n->right = assignconv(n->right, lt, "assignment");
walkexpr(&n->right, init);
out:
@@ -2365,42 +2084,85 @@ addstr(Node *n, NodeList **init)
}
static Node*
-append(Node *n, NodeList **init)
+appendslice(Node *n, NodeList **init)
{
- int i, j;
- Node *f, *r;
- NodeList *in, *args;
+ Node *f;
- if(n->isddd) {
- f = syslook("appendslice", 1);
- argtype(f, n->type);
- argtype(f, n->type->type);
- argtype(f, n->type);
- r = mkcall1(f, n->type, init, typename(n->type), n->list->n, n->list->next->n);
- return r;
+ f = syslook("appendslice", 1);
+ argtype(f, n->type);
+ argtype(f, n->type->type);
+ argtype(f, n->type);
+ return mkcall1(f, n->type, init, typename(n->type), n->list->n, n->list->next->n);
+}
+
+// expand append(src, a [, b]* ) to
+//
+// init {
+// s := src
+// const argc = len(args) - 1
+// if cap(s) - len(s) < argc {
+// s = growslice(s, argc)
+// }
+// n := len(s)
+// s = s[:n+argc]
+// s[n] = a
+// s[n+1] = b
+// ...
+// }
+// s
+static Node*
+append(Node *n, NodeList **init)
+{
+ NodeList *l, *a;
+ Node *nsrc, *ns, *nn, *na, *nx, *fn;
+ int argc;
+
+ walkexprlistsafe(n->list, init);
+
+ nsrc = n->list->n;
+ argc = count(n->list) - 1;
+ if (argc < 1) {
+ return nsrc;
}
- j = count(n->list) - 1;
- f = syslook("append", 1);
- f->type = T;
- f->ntype = nod(OTFUNC, N, N);
- in = list1(nod(ODCLFIELD, N, typenod(ptrto(types[TUINT8])))); // type
- in = list(in, nod(ODCLFIELD, N, typenod(types[TINT]))); // count
- in = list(in, nod(ODCLFIELD, N, typenod(n->type))); // slice
- for(i=0; i<j; i++)
- in = list(in, nod(ODCLFIELD, N, typenod(n->type->type)));
- f->ntype->list = in;
- f->ntype->rlist = list1(nod(ODCLFIELD, N, typenod(n->type)));
-
- args = list1(typename(n->type));
- args = list(args, nodintconst(j));
- args = concat(args, n->list);
-
- r = nod(OCALL, f, N);
- r->list = args;
- typecheck(&r, Erv);
- walkexpr(&r, init);
- r->type = n->type;
+ l = nil;
- return r;
+ ns = nod(OXXX, N, N); // var s
+ tempname(ns, nsrc->type);
+ l = list(l, nod(OAS, ns, nsrc)); // s = src
+
+ na = nodintconst(argc); // const argc
+ nx = nod(OIF, N, N); // if cap(s) - len(s) < argc
+ nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), na);
+
+ fn = syslook("growslice", 1); // growslice(<type>, old []T, n int64) (ret []T)
+ argtype(fn, ns->type->type); // 1 old []any
+ argtype(fn, ns->type->type); // 2 ret []any
+
+ nx->nbody = list1(nod(OAS, ns, mkcall1(fn, ns->type, &nx->ninit,
+ typename(ns->type),
+ ns,
+ conv(na, types[TINT64]))));
+ l = list(l, nx);
+
+ nn = nod(OXXX, N, N); // var n
+ tempname(nn, types[TINT]);
+ l = list(l, nod(OAS, nn, nod(OLEN, ns, N))); // n = len(s)
+
+ nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na))); // ...s[:n+argc]
+ nx->etype = 1; // disable bounds check
+ l = list(l, nod(OAS, ns, nx)); // s = s[:n+argc]
+
+ for (a = n->list->next; a != nil; a = a->next) {
+ nx = nod(OINDEX, ns, nn); // s[n] ...
+ nx->etype = 1; // disable bounds check
+ l = list(l, nod(OAS, nx, a->n)); // s[n] = arg
+ if (a->next != nil)
+ l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1)))); // n = n + 1
+ }
+
+ typechecklist(l, Etop);
+ walkstmtlist(l);
+ *init = concat(*init, l);
+ return ns;
}
diff --git a/src/cmd/godefs/a.h b/src/cmd/godefs/a.h
index 03ab91f65..9b4957467 100644
--- a/src/cmd/godefs/a.h
+++ b/src/cmd/godefs/a.h
@@ -75,6 +75,7 @@ extern Const *con;
extern int ncon;
extern Type **typ;
extern int ntyp;
+extern int kindsize[];
// Language output
typedef struct Lang Lang;
diff --git a/src/cmd/godefs/main.c b/src/cmd/godefs/main.c
index d4163421d..6a8630179 100644
--- a/src/cmd/godefs/main.c
+++ b/src/cmd/godefs/main.c
@@ -181,7 +181,7 @@ main(int argc, char **argv)
char **av, *q, *r, *tofree, *name;
char nambuf[100];
Biobuf *bin, *bout;
- Type *t;
+ Type *t, *tt;
Field *f;
int orig_output_fd;
@@ -373,8 +373,16 @@ Continue:
prefix = prefixlen(t);
for(j=0; j<t->nf; j++) {
f = &t->f[j];
- if(f->type->kind == 0)
- continue;
+ if(f->type->kind == 0 && f->size <= 64 && (f->size&(f->size-1)) == 0) {
+ // unknown type but <= 64 bits and bit size is a power of two.
+ // could be enum - make Uint64 and then let it reduce
+ tt = emalloc(sizeof *tt);
+ *tt = *f->type;
+ f->type = tt;
+ tt->kind = Uint64;
+ while(tt->kind > Uint8 && kindsize[tt->kind] > f->size)
+ tt->kind -= 2;
+ }
// padding
if(t->kind == Struct || lang == &go) {
if(f->offset%8 != 0 || f->size%8 != 0) {
diff --git a/src/cmd/godefs/stabs.c b/src/cmd/godefs/stabs.c
index 30a05fc70..2c3d431b8 100644
--- a/src/cmd/godefs/stabs.c
+++ b/src/cmd/godefs/stabs.c
@@ -149,7 +149,7 @@ Intrange intranges[] = {
16, 0, Void,
};
-static int kindsize[] = {
+int kindsize[] = {
0,
0,
8,
@@ -381,14 +381,6 @@ parsedef(char **pp, char *name)
while(f->type->kind == Typedef)
f->type = f->type->type;
- if(f->type->kind == 0 && f->size <= 64 && (f->size&(f->size-1)) == 0) {
- // unknown type but <= 64 bits and bit size is a power of two.
- // could be enum - make Uint64 and then let it reduce
- tt = emalloc(sizeof *tt);
- *tt = *f->type;
- f->type = tt;
- tt->kind = Uint64;
- }
// rewrite
// uint32 x : 8;
diff --git a/src/cmd/godoc/doc.go b/src/cmd/godoc/doc.go
index f0006e750..26d436d72 100644
--- a/src/cmd/godoc/doc.go
+++ b/src/cmd/godoc/doc.go
@@ -47,6 +47,9 @@ The flags are:
width of tabs in units of spaces
-timestamps=true
show timestamps with directory listings
+ -index
+ enable identifier and full text search index
+ (no search box is shown if -index is not set)
-maxresults=10000
maximum number of full text search results shown
(no full text index is built if maxresults <= 0)
diff --git a/src/cmd/godoc/godoc.go b/src/cmd/godoc/godoc.go
index b8e9dbc92..f97c764f9 100644
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -64,9 +64,12 @@ var (
// layout control
tabwidth = flag.Int("tabwidth", 4, "tab width")
showTimestamps = flag.Bool("timestamps", true, "show timestamps with directory listings")
- maxResults = flag.Int("maxresults", 10000, "maximum number of full text search results shown")
templateDir = flag.String("templates", "", "directory containing alternate template files")
+ // search index
+ indexEnabled = flag.Bool("index", false, "enable search index")
+ maxResults = flag.Int("maxresults", 10000, "maximum number of full text search results shown")
+
// file system mapping
fsMap Mapping // user-defined mapping
fsTree RWValue // *Directory tree of packages, updated with each sync
@@ -687,17 +690,19 @@ func readTemplates() {
func servePage(w http.ResponseWriter, title, subtitle, query string, content []byte) {
d := struct {
- Title string
- Subtitle string
- PkgRoots []string
- Query string
- Version string
- Menu []byte
- Content []byte
+ Title string
+ Subtitle string
+ PkgRoots []string
+ SearchBox bool
+ Query string
+ Version string
+ Menu []byte
+ Content []byte
}{
title,
subtitle,
fsMap.PrefixList(),
+ *indexEnabled,
query,
runtime.Version(),
nil,
@@ -1174,11 +1179,15 @@ func lookup(query string) (result SearchResult) {
}
// is the result accurate?
- if _, ts := fsModified.get(); timestamp < ts {
- // The index is older than the latest file system change
- // under godoc's observation. Indexing may be in progress
- // or start shortly (see indexer()).
- result.Alert = "Indexing in progress: result may be inaccurate"
+ if *indexEnabled {
+ if _, ts := fsModified.get(); timestamp < ts {
+ // The index is older than the latest file system change
+ // under godoc's observation. Indexing may be in progress
+ // or start shortly (see indexer()).
+ result.Alert = "Indexing in progress: result may be inaccurate"
+ }
+ } else {
+ result.Alert = "Search index disabled: no results available"
}
return
diff --git a/src/cmd/godoc/main.go b/src/cmd/godoc/main.go
index e426626b3..967ea8727 100644
--- a/src/cmd/godoc/main.go
+++ b/src/cmd/godoc/main.go
@@ -176,7 +176,7 @@ func remoteSearch(query string) (res *http.Response, err os.Error) {
// remote search
for _, addr := range addrs {
url := "http://" + addr + search
- res, _, err = http.Get(url)
+ res, err = http.Get(url)
if err == nil && res.StatusCode == http.StatusOK {
break
}
@@ -246,8 +246,13 @@ func main() {
log.Printf("address = %s", *httpAddr)
log.Printf("goroot = %s", *goroot)
log.Printf("tabwidth = %d", *tabwidth)
- if *maxResults > 0 {
- log.Printf("maxresults = %d (full text index enabled)", *maxResults)
+ switch {
+ case !*indexEnabled:
+ log.Print("search index disabled")
+ case *maxResults > 0:
+ log.Printf("full text index enabled (maxresults = %d)", *maxResults)
+ default:
+ log.Print("identifier search index enabled")
}
if !fsMap.IsEmpty() {
log.Print("user-defined mapping:")
@@ -284,7 +289,9 @@ func main() {
}
// Start indexing goroutine.
- go indexer()
+ if *indexEnabled {
+ go indexer()
+ }
// Start http server.
if err := http.ListenAndServe(*httpAddr, handler); err != nil {
diff --git a/src/cmd/godoc/spec.go b/src/cmd/godoc/spec.go
index f8b95e387..444e36e08 100644
--- a/src/cmd/godoc/spec.go
+++ b/src/cmd/godoc/spec.go
@@ -99,7 +99,8 @@ func (p *ebnfParser) parseTerm() bool {
case token.STRING:
p.next()
- if p.tok == token.ELLIPSIS {
+ const ellipsis = "…" // U+2026, the horizontal ellipsis character
+ if p.tok == token.ILLEGAL && p.lit == ellipsis {
p.next()
p.expect(token.STRING)
}
@@ -128,6 +129,9 @@ func (p *ebnfParser) parseTerm() bool {
func (p *ebnfParser) parseSequence() {
+ if !p.parseTerm() {
+ p.errorExpected(p.pos, "term")
+ }
for p.parseTerm() {
}
}
@@ -147,7 +151,9 @@ func (p *ebnfParser) parseExpression() {
func (p *ebnfParser) parseProduction() {
p.parseIdentifier(true)
p.expect(token.ASSIGN)
- p.parseExpression()
+ if p.tok != token.PERIOD {
+ p.parseExpression()
+ }
p.expect(token.PERIOD)
}
@@ -157,7 +163,7 @@ func (p *ebnfParser) parse(fset *token.FileSet, out io.Writer, src []byte) {
p.out = out
p.src = src
p.file = fset.AddFile("", fset.Base(), len(src))
- p.scanner.Init(p.file, src, p, 0)
+ p.scanner.Init(p.file, src, p, scanner.AllowIllegalChars)
p.next() // initializes pos, tok, lit
// process source
diff --git a/src/cmd/gofix/Makefile b/src/cmd/gofix/Makefile
index 12f09b4e4..c4127d93e 100644
--- a/src/cmd/gofix/Makefile
+++ b/src/cmd/gofix/Makefile
@@ -10,9 +10,11 @@ GOFILES=\
netdial.go\
main.go\
osopen.go\
+ httpfinalurl.go\
httpserver.go\
procattr.go\
reflect.go\
+ signal.go\
typecheck.go\
include ../../Make.cmd
diff --git a/src/cmd/gofix/fix.go b/src/cmd/gofix/fix.go
index 0852ce21e..c1c5a746c 100644
--- a/src/cmd/gofix/fix.go
+++ b/src/cmd/gofix/fix.go
@@ -10,6 +10,7 @@ import (
"go/token"
"os"
"strconv"
+ "strings"
)
type fix struct {
@@ -258,13 +259,28 @@ func walkBeforeAfter(x interface{}, before, after func(interface{})) {
// imports returns true if f imports path.
func imports(f *ast.File, path string) bool {
+ return importSpec(f, path) != nil
+}
+
+// importSpec returns the import spec if f imports path,
+// or nil otherwise.
+func importSpec(f *ast.File, path string) *ast.ImportSpec {
for _, s := range f.Imports {
- t, err := strconv.Unquote(s.Path.Value)
- if err == nil && t == path {
- return true
+ if importPath(s) == path {
+ return s
}
}
- return false
+ return nil
+}
+
+// importPath returns the unquoted import path of s,
+// or "" if the path is not properly quoted.
+func importPath(s *ast.ImportSpec) string {
+ t, err := strconv.Unquote(s.Path.Value)
+ if err == nil {
+ return t
+ }
+ return ""
}
// isPkgDot returns true if t is the expression "pkg.name"
@@ -420,3 +436,138 @@ func newPkgDot(pos token.Pos, pkg, name string) ast.Expr {
},
}
}
+
+// addImport adds the import path to the file f, if absent.
+func addImport(f *ast.File, path string) {
+ if imports(f, path) {
+ return
+ }
+
+ newImport := &ast.ImportSpec{
+ Path: &ast.BasicLit{
+ Kind: token.STRING,
+ Value: strconv.Quote(path),
+ },
+ }
+
+ var impdecl *ast.GenDecl
+
+ // Find an import decl to add to.
+ for _, decl := range f.Decls {
+ gen, ok := decl.(*ast.GenDecl)
+
+ if ok && gen.Tok == token.IMPORT {
+ impdecl = gen
+ break
+ }
+ }
+
+ // No import decl found. Add one.
+ if impdecl == nil {
+ impdecl = &ast.GenDecl{
+ Tok: token.IMPORT,
+ }
+ f.Decls = append(f.Decls, nil)
+ copy(f.Decls[1:], f.Decls)
+ f.Decls[0] = impdecl
+ }
+
+ // Ensure the import decl has parentheses, if needed.
+ if len(impdecl.Specs) > 0 && !impdecl.Lparen.IsValid() {
+ impdecl.Lparen = impdecl.Pos()
+ }
+
+ // Assume the import paths are alphabetically ordered.
+ // If they are not, the result is ugly, but legal.
+ insertAt := len(impdecl.Specs) // default to end of specs
+ for i, spec := range impdecl.Specs {
+ impspec := spec.(*ast.ImportSpec)
+ if importPath(impspec) > path {
+ insertAt = i
+ break
+ }
+ }
+
+ impdecl.Specs = append(impdecl.Specs, nil)
+ copy(impdecl.Specs[insertAt+1:], impdecl.Specs[insertAt:])
+ impdecl.Specs[insertAt] = newImport
+
+ f.Imports = append(f.Imports, newImport)
+}
+
+// deleteImport deletes the import path from the file f, if present.
+func deleteImport(f *ast.File, path string) {
+ oldImport := importSpec(f, path)
+
+ // Find the import node that imports path, if any.
+ for i, decl := range f.Decls {
+ gen, ok := decl.(*ast.GenDecl)
+ if !ok || gen.Tok != token.IMPORT {
+ continue
+ }
+ for j, spec := range gen.Specs {
+ impspec := spec.(*ast.ImportSpec)
+
+ if oldImport != impspec {
+ continue
+ }
+
+ // We found an import spec that imports path.
+ // Delete it.
+ copy(gen.Specs[j:], gen.Specs[j+1:])
+ gen.Specs = gen.Specs[:len(gen.Specs)-1]
+
+ // If this was the last import spec in this decl,
+ // delete the decl, too.
+ if len(gen.Specs) == 0 {
+ copy(f.Decls[i:], f.Decls[i+1:])
+ f.Decls = f.Decls[:len(f.Decls)-1]
+ } else if len(gen.Specs) == 1 {
+ gen.Lparen = token.NoPos // drop parens
+ }
+
+ break
+ }
+ }
+
+ // Delete it from f.Imports.
+ for i, imp := range f.Imports {
+ if imp == oldImport {
+ copy(f.Imports[i:], f.Imports[i+1:])
+ f.Imports = f.Imports[:len(f.Imports)-1]
+ break
+ }
+ }
+}
+
+func usesImport(f *ast.File, path string) (used bool) {
+ spec := importSpec(f, path)
+ if spec == nil {
+ return
+ }
+
+ name := spec.Name.String()
+ switch name {
+ case "<nil>":
+ // If the package name is not explicitly specified,
+ // make an educated guess. This is not guaranteed to be correct.
+ lastSlash := strings.LastIndex(path, "/")
+ if lastSlash == -1 {
+ name = path
+ } else {
+ name = path[lastSlash+1:]
+ }
+ case "_", ".":
+ // Not sure if this import is used - err on the side of caution.
+ return true
+ }
+
+ walk(f, func(n interface{}) {
+ sel, ok := n.(*ast.SelectorExpr)
+ if ok && isTopName(sel.X, name) {
+ used = true
+ }
+ })
+
+ return
+}
diff --git a/src/cmd/gofix/httpfinalurl.go b/src/cmd/gofix/httpfinalurl.go
new file mode 100644
index 000000000..53642b22f
--- /dev/null
+++ b/src/cmd/gofix/httpfinalurl.go
@@ -0,0 +1,56 @@
+// Copyright 2011 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.
+
+package main
+
+import (
+ "go/ast"
+)
+
+var httpFinalURLFix = fix{
+ "httpfinalurl",
+ httpfinalurl,
+ `Adapt http Get calls to not have a finalURL result parameter.
+
+ http://codereview.appspot.com/4535056/
+`,
+}
+
+func init() {
+ register(httpFinalURLFix)
+}
+
+func httpfinalurl(f *ast.File) bool {
+ if !imports(f, "http") {
+ return false
+ }
+
+ fixed := false
+ walk(f, func(n interface{}) {
+ // Fix up calls to http.Get.
+ //
+ // If they have blank identifiers, remove them:
+ // resp, _, err := http.Get(url)
+ // -> resp, err := http.Get(url)
+ //
+ // But if they're using the finalURL parameter, warn:
+ // resp, finalURL, err := http.Get(url)
+ as, ok := n.(*ast.AssignStmt)
+ if !ok || len(as.Lhs) != 3 || len(as.Rhs) != 1 {
+ return
+ }
+
+ if !isCall(as.Rhs[0], "http", "Get") {
+ return
+ }
+
+ if isBlank(as.Lhs[1]) {
+ as.Lhs = []ast.Expr{as.Lhs[0], as.Lhs[2]}
+ fixed = true
+ } else {
+ warn(as.Pos(), "call to http.Get records final URL")
+ }
+ })
+ return fixed
+}
diff --git a/src/cmd/gofix/httpfinalurl_test.go b/src/cmd/gofix/httpfinalurl_test.go
new file mode 100644
index 000000000..9e7d6242d
--- /dev/null
+++ b/src/cmd/gofix/httpfinalurl_test.go
@@ -0,0 +1,37 @@
+// Copyright 2011 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.
+
+package main
+
+func init() {
+ addTestCases(httpfinalurlTests)
+}
+
+var httpfinalurlTests = []testCase{
+ {
+ Name: "finalurl.0",
+ In: `package main
+
+import (
+ "http"
+)
+
+func f() {
+ resp, _, err := http.Get("http://www.google.com/")
+ _, _ = resp, err
+}
+`,
+ Out: `package main
+
+import (
+ "http"
+)
+
+func f() {
+ resp, err := http.Get("http://www.google.com/")
+ _, _ = resp, err
+}
+`,
+ },
+}
diff --git a/src/cmd/gofix/main.go b/src/cmd/gofix/main.go
index 4f7e923e3..1b091c18a 100644
--- a/src/cmd/gofix/main.go
+++ b/src/cmd/gofix/main.go
@@ -248,17 +248,11 @@ func diff(b1, b2 []byte) (data []byte, err os.Error) {
f1.Write(b1)
f2.Write(b2)
- diffcmd, err := exec.LookPath("diff")
- if err != nil {
- return nil, err
+ data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
+ if len(data) > 0 {
+ // diff exits with a non-zero status when the files don't match.
+ // Ignore that failure as long as we get output.
+ err = nil
}
-
- c, err := exec.Run(diffcmd, []string{"diff", f1.Name(), f2.Name()}, nil, "",
- exec.DevNull, exec.Pipe, exec.MergeWithStdout)
- if err != nil {
- return nil, err
- }
- defer c.Close()
-
- return ioutil.ReadAll(c.Stdout)
+ return
}
diff --git a/src/cmd/gofix/signal.go b/src/cmd/gofix/signal.go
new file mode 100644
index 000000000..53c338851
--- /dev/null
+++ b/src/cmd/gofix/signal.go
@@ -0,0 +1,49 @@
+// Copyright 2011 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.
+
+package main
+
+import (
+ "go/ast"
+ "strings"
+)
+
+func init() {
+ register(fix{
+ "signal",
+ signal,
+ `Adapt code to types moved from os/signal to signal.
+
+http://codereview.appspot.com/4437091
+`,
+ })
+}
+
+func signal(f *ast.File) (fixed bool) {
+ if !imports(f, "os/signal") {
+ return
+ }
+
+ walk(f, func(n interface{}) {
+ s, ok := n.(*ast.SelectorExpr)
+
+ if !ok || !isTopName(s.X, "signal") {
+ return
+ }
+
+ sel := s.Sel.String()
+ if sel == "Signal" || sel == "UnixSignal" || strings.HasPrefix(sel, "SIG") {
+ s.X = &ast.Ident{Name: "os"}
+ fixed = true
+ }
+ })
+
+ if fixed {
+ addImport(f, "os")
+ if !usesImport(f, "os/signal") {
+ deleteImport(f, "os/signal")
+ }
+ }
+ return
+}
diff --git a/src/cmd/gofix/signal_test.go b/src/cmd/gofix/signal_test.go
new file mode 100644
index 000000000..2500e9cee
--- /dev/null
+++ b/src/cmd/gofix/signal_test.go
@@ -0,0 +1,96 @@
+// Copyright 2011 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.
+
+package main
+
+func init() {
+ addTestCases(signalTests)
+}
+
+var signalTests = []testCase{
+ {
+ Name: "signal.0",
+ In: `package main
+
+import (
+ _ "a"
+ "os/signal"
+ _ "z"
+)
+
+type T1 signal.UnixSignal
+type T2 signal.Signal
+
+func f() {
+ _ = signal.SIGHUP
+ _ = signal.Incoming
+}
+`,
+ Out: `package main
+
+import (
+ _ "a"
+ "os"
+ "os/signal"
+ _ "z"
+)
+
+type T1 os.UnixSignal
+type T2 os.Signal
+
+func f() {
+ _ = os.SIGHUP
+ _ = signal.Incoming
+}
+`,
+ },
+ {
+ Name: "signal.1",
+ In: `package main
+
+import (
+ "os"
+ "os/signal"
+)
+
+func f() {
+ var _ os.Error
+ _ = signal.SIGHUP
+}
+`,
+ Out: `package main
+
+import "os"
+
+
+func f() {
+ var _ os.Error
+ _ = os.SIGHUP
+}
+`,
+ },
+ {
+ Name: "signal.2",
+ In: `package main
+
+import "os"
+import "os/signal"
+
+func f() {
+ var _ os.Error
+ _ = signal.SIGHUP
+}
+`,
+ Out: `package main
+
+import "os"
+
+
+func f() {
+ var _ os.Error
+ _ = os.SIGHUP
+}
+`,
+ },
+}
diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go
index 5dd801d90..ea1c1b00f 100644
--- a/src/cmd/gofmt/gofmt.go
+++ b/src/cmd/gofmt/gofmt.go
@@ -245,14 +245,14 @@ func gofmtMain() {
func diff(b1, b2 []byte) (data []byte, err os.Error) {
f1, err := ioutil.TempFile("", "gofmt")
if err != nil {
- return nil, err
+ return
}
defer os.Remove(f1.Name())
defer f1.Close()
f2, err := ioutil.TempFile("", "gofmt")
if err != nil {
- return nil, err
+ return
}
defer os.Remove(f2.Name())
defer f2.Close()
@@ -260,17 +260,12 @@ func diff(b1, b2 []byte) (data []byte, err os.Error) {
f1.Write(b1)
f2.Write(b2)
- diffcmd, err := exec.LookPath("diff")
- if err != nil {
- return nil, err
- }
-
- c, err := exec.Run(diffcmd, []string{"diff", "-u", f1.Name(), f2.Name()},
- nil, "", exec.DevNull, exec.Pipe, exec.MergeWithStdout)
- if err != nil {
- return nil, err
+ data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
+ if len(data) > 0 {
+ // diff exits with a non-zero status when the files don't match.
+ // Ignore that failure as long as we get output.
+ err = nil
}
- defer c.Close()
+ return
- return ioutil.ReadAll(c.Stdout)
}
diff --git a/src/cmd/gofmt/test.sh b/src/cmd/gofmt/test.sh
index 99ec76932..5dce2ed7a 100755
--- a/src/cmd/gofmt/test.sh
+++ b/src/cmd/gofmt/test.sh
@@ -36,13 +36,14 @@ apply1() {
# the following files are skipped because they are test cases
# for syntax errors and thus won't parse in the first place:
case `basename "$F"` in
- func3.go | const2.go | char_lit1.go | blank1.go | \
+ func3.go | const2.go | char_lit1.go | blank1.go | ddd1.go | \
bug014.go | bug050.go | bug068.go | bug083.go | bug088.go | \
bug106.go | bug121.go | bug125.go | bug133.go | bug160.go | \
bug163.go | bug166.go | bug169.go | bug217.go | bug222.go | \
bug226.go | bug228.go | bug248.go | bug274.go | bug280.go | \
bug282.go | bug287.go | bug298.go | bug299.go | bug300.go | \
- bug302.go | bug306.go | bug322.go | bug324.go ) return ;;
+ bug302.go | bug306.go | bug322.go | bug324.go | bug335.go | \
+ bug340.go ) return ;;
esac
# the following directories are skipped because they contain test
# cases for syntax errors and thus won't parse in the first place:
diff --git a/src/cmd/goinstall/doc.go b/src/cmd/goinstall/doc.go
index 15845b574..13c37d0a2 100644
--- a/src/cmd/goinstall/doc.go
+++ b/src/cmd/goinstall/doc.go
@@ -3,7 +3,6 @@
// license that can be found in the LICENSE file.
/*
-
Goinstall is an experiment in automatic package installation.
It installs packages, possibly downloading them from the internet.
It maintains a list of public Go packages at http://godashboard.appspot.com/package.
@@ -100,5 +99,59 @@ Instead, it invokes "make install" after locating the package sources.
For local packages without a Makefile and all remote packages,
goinstall creates and uses a temporary Makefile constructed from
the import path and the list of Go files in the package.
+
+
+The GOPATH Environment Variable
+
+GOPATH may be set to a colon-separated list of paths inside which Go code,
+package objects, and executables may be found.
+
+Set a GOPATH to use goinstall to build and install your own code and
+external libraries outside of the Go tree (and to avoid writing Makefiles).
+
+The top-level directory structure of a GOPATH is prescribed:
+
+The 'src' directory is for source code. The directory naming inside 'src'
+determines the package import path or executable name.
+
+The 'pkg' directory is for package objects. Like the Go tree, package objects
+are stored inside a directory named after the target operating system and
+processor architecture ('pkg/$GOOS_$GOARCH').
+A package whose source is located at '$GOPATH/src/foo/bar' would be imported
+as 'foo/bar' and installed as '$GOPATH/pkg/$GOOS_$GOARCH/foo/bar.a'.
+
+The 'bin' directory is for executable files.
+Goinstall installs program binaries using the name of the source folder.
+A binary whose source is at 'src/foo/qux' would be built and installed to
+'$GOPATH/bin/qux'. (Note 'bin/qux', not 'bin/foo/qux' - this is such that
+you can put the bin directory in your PATH.)
+
+Here's an example directory layout:
+
+ GOPATH=/home/user/gocode
+
+ /home/user/gocode/
+ src/foo/
+ bar/ (go code in package bar)
+ qux/ (go code in package main)
+ bin/qux (executable file)
+ pkg/linux_amd64/foo/bar.a (object file)
+
+Run 'goinstall foo/bar' to build and install the package 'foo/bar'
+(and its dependencies).
+Goinstall will search each GOPATH (in order) for 'src/foo/bar'.
+If the directory cannot be found, goinstall will attempt to fetch the
+source from a remote repository and write it to the 'src' directory of the
+first GOPATH (or $GOROOT/src/pkg if GOPATH is not set).
+
+Goinstall recognizes relative and absolute paths (paths beginning with / or .).
+The following commands would build our example packages:
+
+ goinstall /home/user/gocode/src/foo/bar # build and install foo/bar
+ cd /home/user/gocode/src/foo
+ goinstall ./bar # build and install foo/bar (again)
+ cd qux
+ goinstall . # build and install foo/qux
+
*/
package documentation
diff --git a/src/cmd/goinstall/download.go b/src/cmd/goinstall/download.go
index 7dad596ab..2edf85efd 100644
--- a/src/cmd/goinstall/download.go
+++ b/src/cmd/goinstall/download.go
@@ -31,23 +31,36 @@ func maybeReportToDashboard(path string) {
}
}
-var googlecode = regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/(svn|hg))(/[a-z0-9A-Z_.\-/]*)?$`)
-var github = regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`)
-var bitbucket = regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`)
-var launchpad = regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`)
+var vcsPatterns = map[string]*regexp.Regexp{
+ "googlecode": regexp.MustCompile(`^([a-z0-9\-]+\.googlecode\.com/(svn|hg))(/[a-z0-9A-Z_.\-/]*)?$`),
+ "github": regexp.MustCompile(`^(github\.com/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`),
+ "bitbucket": regexp.MustCompile(`^(bitbucket\.org/[a-z0-9A-Z_.\-]+/[a-z0-9A-Z_.\-]+)(/[a-z0-9A-Z_.\-/]*)?$`),
+ "launchpad": regexp.MustCompile(`^(launchpad\.net/([a-z0-9A-Z_.\-]+(/[a-z0-9A-Z_.\-]+)?|~[a-z0-9A-Z_.\-]+/(\+junk|[a-z0-9A-Z_.\-]+)/[a-z0-9A-Z_.\-]+))(/[a-z0-9A-Z_.\-/]+)?$`),
+}
+
+// isRemote returns true if the provided package path
+// matches one of the supported remote repositories.
+func isRemote(pkg string) bool {
+ for _, r := range vcsPatterns {
+ if r.MatchString(pkg) {
+ return true
+ }
+ }
+ return false
+}
// download checks out or updates pkg from the remote server.
func download(pkg, srcDir string) os.Error {
if strings.Contains(pkg, "..") {
return os.ErrorString("invalid path (contains ..)")
}
- if m := bitbucket.FindStringSubmatch(pkg); m != nil {
+ if m := vcsPatterns["bitbucket"].FindStringSubmatch(pkg); m != nil {
if err := vcsCheckout(&hg, srcDir, m[1], "http://"+m[1], m[1]); err != nil {
return err
}
return nil
}
- if m := googlecode.FindStringSubmatch(pkg); m != nil {
+ if m := vcsPatterns["googlecode"].FindStringSubmatch(pkg); m != nil {
var v *vcs
switch m[2] {
case "hg":
@@ -63,7 +76,7 @@ func download(pkg, srcDir string) os.Error {
}
return nil
}
- if m := github.FindStringSubmatch(pkg); m != nil {
+ if m := vcsPatterns["github"].FindStringSubmatch(pkg); m != nil {
if strings.HasSuffix(m[1], ".git") {
return os.ErrorString("repository " + pkg + " should not have .git suffix")
}
@@ -72,7 +85,7 @@ func download(pkg, srcDir string) os.Error {
}
return nil
}
- if m := launchpad.FindStringSubmatch(pkg); m != nil {
+ if m := vcsPatterns["launchpad"].FindStringSubmatch(pkg); m != nil {
// Either lp.net/<project>[/<series>[/<path>]]
// or lp.net/~<user or team>/<project>/<branch>[/<path>]
if err := vcsCheckout(&bzr, srcDir, m[1], "https://"+m[1], m[1]); err != nil {
diff --git a/src/cmd/goinstall/main.go b/src/cmd/goinstall/main.go
index 6cd92907a..721e719d2 100644
--- a/src/cmd/goinstall/main.go
+++ b/src/cmd/goinstall/main.go
@@ -12,7 +12,6 @@ import (
"flag"
"fmt"
"go/token"
- "io"
"io/ioutil"
"os"
"path/filepath"
@@ -32,9 +31,8 @@ var (
argv0 = os.Args[0]
errors = false
parents = make(map[string]string)
- root = runtime.GOROOT()
visit = make(map[string]status)
- logfile = filepath.Join(root, "goinstall.log")
+ logfile = filepath.Join(runtime.GOROOT(), "goinstall.log")
installedPkgs = make(map[string]bool)
allpkg = flag.Bool("a", false, "install all previously installed packages")
@@ -52,14 +50,30 @@ const (
done
)
+func logf(format string, args ...interface{}) {
+ format = "%s: " + format
+ args = append([]interface{}{argv0}, args...)
+ fmt.Fprintf(os.Stderr, format, args...)
+}
+
+func vlogf(format string, args ...interface{}) {
+ if *verbose {
+ logf(format, args...)
+ }
+}
+
+func errorf(format string, args ...interface{}) {
+ errors = true
+ logf(format, args...)
+}
+
func main() {
flag.Usage = usage
flag.Parse()
- if root == "" {
+ if runtime.GOROOT() == "" {
fmt.Fprintf(os.Stderr, "%s: no $GOROOT\n", argv0)
os.Exit(1)
}
- root += filepath.FromSlash("/src/pkg/")
// special case - "unsafe" is already installed
visit["unsafe"] = done
@@ -88,6 +102,11 @@ func main() {
usage()
}
for _, path := range args {
+ if strings.HasPrefix(path, "http://") {
+ errorf("'http://' used in remote path, try '%s'\n", path[7:])
+ continue
+ }
+
install(path, "")
}
if errors {
@@ -143,49 +162,44 @@ func install(pkg, parent string) {
}
visit[pkg] = visiting
parents[pkg] = parent
- if *verbose {
- fmt.Println(pkg)
- }
+
+ vlogf("%s: visit\n", pkg)
// Check whether package is local or remote.
// If remote, download or update it.
- var dir string
- proot := gopath[0] // default to GOROOT
- local := false
- if strings.HasPrefix(pkg, "http://") {
- fmt.Fprintf(os.Stderr, "%s: %s: 'http://' used in remote path, try '%s'\n", argv0, pkg, pkg[7:])
- errors = true
+ proot, pkg, err := findPackageRoot(pkg)
+ // Don't build the standard library.
+ if err == nil && proot.goroot && isStandardPath(pkg) {
+ if parent == "" {
+ errorf("%s: can not goinstall the standard library\n", pkg)
+ } else {
+ vlogf("%s: skipping standard library\n", pkg)
+ }
+ visit[pkg] = done
return
}
- if isLocalPath(pkg) {
- dir = pkg
- local = true
- } else if isStandardPath(pkg) {
- dir = filepath.Join(root, filepath.FromSlash(pkg))
- local = true
- } else {
- proot = findPkgroot(pkg)
- err := download(pkg, proot.srcDir())
- dir = filepath.Join(proot.srcDir(), pkg)
- if err != nil {
- fmt.Fprintf(os.Stderr, "%s: %s: %s\n", argv0, pkg, err)
- errors = true
- visit[pkg] = done
- return
- }
+ // Download remote packages if not found or forced with -u flag.
+ remote := isRemote(pkg)
+ if remote && (err == ErrPackageNotFound || (err == nil && *update)) {
+ vlogf("%s: download\n", pkg)
+ err = download(pkg, proot.srcDir())
}
+ if err != nil {
+ errorf("%s: %v\n", pkg, err)
+ visit[pkg] = done
+ return
+ }
+ dir := filepath.Join(proot.srcDir(), pkg)
// Install prerequisites.
dirInfo, err := scanDir(dir, parent == "")
if err != nil {
- fmt.Fprintf(os.Stderr, "%s: %s: %s\n", argv0, pkg, err)
- errors = true
+ errorf("%s: %v\n", pkg, err)
visit[pkg] = done
return
}
if len(dirInfo.goFiles) == 0 {
- fmt.Fprintf(os.Stderr, "%s: %s: package has no files\n", argv0, pkg)
- errors = true
+ errorf("%s: package has no files\n", pkg)
visit[pkg] = done
return
}
@@ -198,22 +212,16 @@ func install(pkg, parent string) {
// Install this package.
if !errors {
isCmd := dirInfo.pkgName == "main"
- if err := domake(dir, pkg, proot, local, isCmd); err != nil {
- fmt.Fprintf(os.Stderr, "%s: installing %s: %s\n", argv0, pkg, err)
- errors = true
- } else if !local && *logPkgs {
- // mark this package as installed in $GOROOT/goinstall.log
+ if err := domake(dir, pkg, proot, isCmd); err != nil {
+ errorf("installing: %v\n", err)
+ } else if remote && *logPkgs {
+ // mark package as installed in $GOROOT/goinstall.log
logPackage(pkg)
}
}
visit[pkg] = done
}
-// Is this a local path? /foo ./foo ../foo . ..
-func isLocalPath(s string) bool {
- const sep = string(filepath.Separator)
- return strings.HasPrefix(s, sep) || strings.HasPrefix(s, "."+sep) || strings.HasPrefix(s, ".."+sep) || s == "." || s == ".."
-}
// Is this a standard package path? strings container/vector etc.
// Assume that if the first element has a dot, it's a domain name
@@ -237,40 +245,22 @@ func quietRun(dir string, stdin []byte, cmd ...string) os.Error {
}
// genRun implements run and quietRun.
-func genRun(dir string, stdin []byte, cmd []string, quiet bool) os.Error {
- bin, err := exec.LookPath(cmd[0])
+func genRun(dir string, stdin []byte, arg []string, quiet bool) os.Error {
+ cmd := exec.Command(arg[0], arg[1:]...)
+ cmd.Stdin = bytes.NewBuffer(stdin)
+ cmd.Dir = dir
+ vlogf("%s: %s %s\n", dir, cmd.Path, strings.Join(arg[1:], " "))
+ out, err := cmd.CombinedOutput()
if err != nil {
- return err
- }
- p, err := exec.Run(bin, cmd, os.Environ(), dir, exec.Pipe, exec.Pipe, exec.MergeWithStdout)
- if *verbose {
- fmt.Fprintf(os.Stderr, "%s: %s; %s %s\n", argv0, dir, bin, strings.Join(cmd[1:], " "))
- }
- if err != nil {
- return err
- }
- go func() {
- p.Stdin.Write(stdin)
- p.Stdin.Close()
- }()
- var buf bytes.Buffer
- io.Copy(&buf, p.Stdout)
- io.Copy(&buf, p.Stdout)
- w, err := p.Wait(0)
- p.Close()
- if err != nil {
- return err
- }
- if !w.Exited() || w.ExitStatus() != 0 {
if !quiet || *verbose {
if dir != "" {
dir = "cd " + dir + "; "
}
- fmt.Fprintf(os.Stderr, "%s: === %s%s\n", argv0, dir, strings.Join(cmd, " "))
- os.Stderr.Write(buf.Bytes())
- fmt.Fprintf(os.Stderr, "--- %s\n", w)
+ fmt.Fprintf(os.Stderr, "%s: === %s%s\n", cmd.Path, dir, strings.Join(cmd.Args, " "))
+ os.Stderr.Write(out)
+ fmt.Fprintf(os.Stderr, "--- %s\n", err)
}
- return os.ErrorString("running " + cmd[0] + ": " + w.String())
+ return os.ErrorString("running " + arg[0] + ": " + err.String())
}
return nil
}
diff --git a/src/cmd/goinstall/make.go b/src/cmd/goinstall/make.go
index b2ca82b46..0c44481d7 100644
--- a/src/cmd/goinstall/make.go
+++ b/src/cmd/goinstall/make.go
@@ -14,26 +14,14 @@ import (
)
// domake builds the package in dir.
-// If local is false, the package was copied from an external system.
-// For non-local packages or packages without Makefiles,
// domake generates a standard Makefile and passes it
// to make on standard input.
-func domake(dir, pkg string, root *pkgroot, local, isCmd bool) (err os.Error) {
- needMakefile := true
- if local {
- _, err := os.Stat(dir + "/Makefile")
- if err == nil {
- needMakefile = false
- }
- }
- cmd := []string{"gomake"}
- var makefile []byte
- if needMakefile {
- if makefile, err = makeMakefile(dir, pkg, root, isCmd); err != nil {
- return err
- }
- cmd = append(cmd, "-f-")
+func domake(dir, pkg string, root *pkgroot, isCmd bool) (err os.Error) {
+ makefile, err := makeMakefile(dir, pkg, root, isCmd)
+ if err != nil {
+ return err
}
+ cmd := []string{"bash", "gomake", "-f-"}
if *clean {
cmd = append(cmd, "clean")
}
@@ -51,16 +39,8 @@ func makeMakefile(dir, pkg string, root *pkgroot, isCmd bool) ([]byte, os.Error)
targ := pkg
targDir := root.pkgDir()
if isCmd {
- // use the last part of the package name only
+ // use the last part of the package name for targ
_, targ = filepath.Split(pkg)
- // if building the working dir use the directory name
- if targ == "." {
- d, err := filepath.Abs(dir)
- if err != nil {
- return nil, os.NewError("finding path: " + err.String())
- }
- _, targ = filepath.Split(d)
- }
targDir = root.binDir()
}
dirInfo, err := scanDir(dir, isCmd)
diff --git a/src/cmd/goinstall/path.go b/src/cmd/goinstall/path.go
index 1153e0471..b8c392931 100644
--- a/src/cmd/goinstall/path.go
+++ b/src/cmd/goinstall/path.go
@@ -5,10 +5,12 @@
package main
import (
+ "fmt"
"log"
"os"
"path/filepath"
"runtime"
+ "strings"
)
var (
@@ -19,6 +21,7 @@ var (
// set up gopath: parse and validate GOROOT and GOPATH variables
func init() {
+ root := runtime.GOROOT()
p, err := newPkgroot(root)
if err != nil {
log.Fatalf("Invalid GOROOT %q: %v", root, err)
@@ -105,13 +108,42 @@ func (r *pkgroot) hasPkg(name string) bool {
// TODO(adg): check object version is consistent
}
-// findPkgroot searches each of the gopath roots
-// for the source code for the given import path.
-func findPkgroot(importPath string) *pkgroot {
+
+var ErrPackageNotFound = os.NewError("package could not be found locally")
+
+// findPackageRoot takes an import or filesystem path and returns the
+// root where the package source should be and the package import path.
+func findPackageRoot(path string) (root *pkgroot, pkg string, err os.Error) {
+ if isLocalPath(path) {
+ if path, err = filepath.Abs(path); err != nil {
+ return
+ }
+ for _, r := range gopath {
+ rpath := r.srcDir() + string(filepath.Separator)
+ if !strings.HasPrefix(path, rpath) {
+ continue
+ }
+ root = r
+ pkg = path[len(rpath):]
+ return
+ }
+ err = fmt.Errorf("path %q not inside a GOPATH", path)
+ return
+ }
+ root = defaultRoot
+ pkg = path
for _, r := range gopath {
- if r.hasSrcDir(importPath) {
- return r
+ if r.hasSrcDir(path) {
+ root = r
+ return
}
}
- return defaultRoot
+ err = ErrPackageNotFound
+ return
+}
+
+// Is this a local path? /foo ./foo ../foo . ..
+func isLocalPath(s string) bool {
+ const sep = string(filepath.Separator)
+ return strings.HasPrefix(s, sep) || strings.HasPrefix(s, "."+sep) || strings.HasPrefix(s, ".."+sep) || s == "." || s == ".."
}
diff --git a/src/cmd/gopack/ar.c b/src/cmd/gopack/ar.c
index 017978ced..0b5e608c7 100644
--- a/src/cmd/gopack/ar.c
+++ b/src/cmd/gopack/ar.c
@@ -1532,25 +1532,7 @@ arwrite(int fd, Armember *bp)
int
page(Arfile *ap)
{
- Armember *bp;
-
- bp = ap->head;
- if (!ap->paged) { /* not yet paged - create file */
- ap->fname = mktemp(ap->fname);
- ap->fd = create(ap->fname, ORDWR|ORCLOSE, 0600);
- if (ap->fd < 0) {
- fprint(2,"gopack: can't create temp file\n");
- return 0;
- }
- ap->paged = 1;
- }
- if (!arwrite(ap->fd, bp)) /* write member and free buffer block */
- return 0;
- ap->head = bp->next;
- if (ap->tail == bp)
- ap->tail = bp->next;
- free(bp->member);
- free(bp);
+ sysfatal("page");
return 1;
}
diff --git a/src/cmd/gotest/gotest.go b/src/cmd/gotest/gotest.go
index a7ba8dd11..4cb3da23c 100644
--- a/src/cmd/gotest/gotest.go
+++ b/src/cmd/gotest/gotest.go
@@ -52,7 +52,7 @@ var (
xFlag bool
)
-// elapsed returns time elapsed since gotest started.
+// elapsed returns the number of seconds since gotest started.
func elapsed() float64 {
return float64(time.Nanoseconds()-start) / 1e9
}
@@ -182,7 +182,7 @@ func getTestFileNames() {
}
}
-// parseFiles parses the files and remembers the packages we find.
+// parseFiles parses the files and remembers the packages we find.
func parseFiles() {
fileSet := token.NewFileSet()
for _, f := range files {
@@ -285,7 +285,8 @@ func doRun(argv []string, returnStdout bool) string {
}
cmd += `"` + v + `"`
}
- argv = []string{"sh", "-c", cmd}
+ command = "bash"
+ argv = []string{"bash", "-c", cmd}
}
var err os.Error
argv[0], err = exec.LookPath(argv[0])
diff --git a/src/cmd/gotype/gotype.go b/src/cmd/gotype/gotype.go
index 568467322..b6a23ae5f 100644
--- a/src/cmd/gotype/gotype.go
+++ b/src/cmd/gotype/gotype.go
@@ -178,8 +178,10 @@ func processPackage(fset *token.FileSet, files map[string]*ast.File) {
report(err)
return
}
- // TODO(gri): typecheck package
- _ = pkg
+ _, err = types.Check(fset, pkg)
+ if err != nil {
+ report(err)
+ }
}
diff --git a/src/cmd/hgpatch/main.go b/src/cmd/hgpatch/main.go
index 2dcb5234c..8ee3422e2 100644
--- a/src/cmd/hgpatch/main.go
+++ b/src/cmd/hgpatch/main.go
@@ -10,7 +10,6 @@ import (
"exec"
"flag"
"fmt"
- "io"
"io/ioutil"
"os"
"patch"
@@ -333,6 +332,7 @@ func run(argv []string, input []byte) (out string, err os.Error) {
err = os.EINVAL
goto Error
}
+
prog, ok := lookPathCache[argv[0]]
if !ok {
prog, err = exec.LookPath(argv[0])
@@ -341,40 +341,15 @@ func run(argv []string, input []byte) (out string, err os.Error) {
}
lookPathCache[argv[0]] = prog
}
- // fmt.Fprintf(os.Stderr, "%v\n", argv);
- var cmd *exec.Cmd
- if len(input) == 0 {
- cmd, err = exec.Run(prog, argv, os.Environ(), "", exec.DevNull, exec.Pipe, exec.MergeWithStdout)
- if err != nil {
- goto Error
- }
- } else {
- cmd, err = exec.Run(prog, argv, os.Environ(), "", exec.Pipe, exec.Pipe, exec.MergeWithStdout)
- if err != nil {
- goto Error
- }
- go func() {
- cmd.Stdin.Write(input)
- cmd.Stdin.Close()
- }()
- }
- defer cmd.Close()
- var buf bytes.Buffer
- _, err = io.Copy(&buf, cmd.Stdout)
- out = buf.String()
- if err != nil {
- cmd.Wait(0)
- goto Error
- }
- w, err := cmd.Wait(0)
- if err != nil {
- goto Error
+
+ cmd := exec.Command(prog, argv[1:]...)
+ if len(input) > 0 {
+ cmd.Stdin = bytes.NewBuffer(input)
}
- if !w.Exited() || w.ExitStatus() != 0 {
- err = w
- goto Error
+ bs, err := cmd.CombinedOutput()
+ if err == nil {
+ return string(bs), nil
}
- return
Error:
err = &runError{dup(argv), err}
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
index 0cb2b2138..3f3faade0 100644
--- a/src/cmd/ld/data.c
+++ b/src/cmd/ld/data.c
@@ -804,6 +804,10 @@ dodata(void)
diag("%s: no size", s->name);
t = 1;
}
+ if(t >= PtrSize)
+ t = rnd(t, PtrSize);
+ else if(t > 2)
+ t = rnd(t, 4);
if(t & 1)
;
else if(t & 2)
@@ -826,6 +830,10 @@ dodata(void)
diag("unexpected symbol type %d", s->type);
}
t = s->size;
+ if(t >= PtrSize)
+ t = rnd(t, PtrSize);
+ else if(t > 2)
+ t = rnd(t, 4);
if(t & 1)
;
else if(t & 2)
@@ -899,10 +907,8 @@ address(void)
segdata.fileoff = va - segtext.vaddr + segtext.fileoff;
if(HEADTYPE == Hwindows)
segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN);
- if(HEADTYPE == Hplan9x32) {
- segdata.vaddr = va = rnd(va, 4096);
+ if(HEADTYPE == Hplan9x32)
segdata.fileoff = segtext.fileoff + segtext.filelen;
- }
for(s=segdata.sect; s != nil; s=s->next) {
s->vaddr = va;
va += s->len;
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index 98b068008..50b42183e 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -529,8 +529,10 @@ find_or_diag(DWDie *die, char* name)
{
DWDie *r;
r = find(die, name);
- if (r == nil)
+ if (r == nil) {
diag("dwarf find: %s has no %s", getattr(die, DW_AT_name)->data, name);
+ errorexit();
+ }
return r;
}
@@ -613,7 +615,7 @@ putattr(int form, int cls, vlong value, char *data)
case DW_FORM_ref_addr: // reference to a DIE in the .info section
if (data == nil) {
- diag("null dwarf reference");
+ diag("dwarf: null reference");
LPUT(0); // invalid dwarf, gdb will complain.
} else {
if (((DWDie*)data)->offs == 0)
@@ -631,7 +633,7 @@ putattr(int form, int cls, vlong value, char *data)
case DW_FORM_strp: // string
case DW_FORM_indirect: // (see Section 7.5.3)
default:
- diag("Unsupported atribute form %d / class %d", form, cls);
+ diag("dwarf: unsupported attribute form %d / class %d", form, cls);
errorexit();
}
}
@@ -823,7 +825,7 @@ decode_inuxi(uchar* p, int sz)
inuxi = inuxi8;
break;
default:
- diag("decode inuxi %d", sz);
+ diag("dwarf: decode inuxi %d", sz);
errorexit();
}
for (i = 0; i < sz; i++)
@@ -1013,7 +1015,7 @@ defgotype(Sym *gotype)
return find_or_diag(&dwtypes, "<unspecified>");
if (strncmp("type.", gotype->name, 5) != 0) {
- diag("Type name doesn't start with \".type\": %s", gotype->name);
+ diag("dwarf: type name doesn't start with \".type\": %s", gotype->name);
return find_or_diag(&dwtypes, "<unspecified>");
}
name = gotype->name + 5; // could also decode from Type.string
@@ -1164,7 +1166,7 @@ defgotype(Sym *gotype)
break;
default:
- diag("definition of unknown kind %d: %s", kind, gotype->name);
+ diag("dwarf: definition of unknown kind %d: %s", kind, gotype->name);
die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name);
newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "<unspecified>"));
}
@@ -1346,7 +1348,7 @@ synthesizemaptypes(DWDie *die)
valtype = defptrto(valtype);
newrefattr(fld, DW_AT_type, valtype);
newmemberoffsetattr(fld, hashsize + datavo);
- newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, NULL);
+ newattr(dwhe, DW_AT_byte_size, DW_CLS_CONSTANT, hashsize + datsize, nil);
// Construct hash_subtable<hash_entry<K,V>>
dwhs = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
@@ -1357,7 +1359,7 @@ synthesizemaptypes(DWDie *die)
substitutetype(dwhs, "end", defptrto(dwhe));
substitutetype(dwhs, "entry", dwhe); // todo: []hash_entry with dynamic size
newattr(dwhs, DW_AT_byte_size, DW_CLS_CONSTANT,
- getattr(hash_subtable, DW_AT_byte_size)->value, NULL);
+ getattr(hash_subtable, DW_AT_byte_size)->value, nil);
// Construct hash<K,V>
dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
@@ -1367,7 +1369,7 @@ synthesizemaptypes(DWDie *die)
copychildren(dwh, hash);
substitutetype(dwh, "st", defptrto(dwhs));
newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
- getattr(hash, DW_AT_byte_size)->value, NULL);
+ getattr(hash, DW_AT_byte_size)->value, nil);
newrefattr(die, DW_AT_type, defptrto(dwh));
}
@@ -1399,30 +1401,30 @@ synthesizechantypes(DWDie *die)
// sudog<T>
dws = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
mkinternaltypename("sudog",
- getattr(elemtype, DW_AT_name)->data, NULL));
+ getattr(elemtype, DW_AT_name)->data, nil));
copychildren(dws, sudog);
substitutetype(dws, "elem", elemtype);
newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT,
- sudogsize + (elemsize > 8 ? elemsize - 8 : 0), NULL);
+ sudogsize + (elemsize > 8 ? elemsize - 8 : 0), nil);
// waitq<T>
dww = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
- mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, NULL));
+ mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, nil));
copychildren(dww, waitq);
substitutetype(dww, "first", defptrto(dws));
substitutetype(dww, "last", defptrto(dws));
newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT,
- getattr(waitq, DW_AT_byte_size)->value, NULL);
+ getattr(waitq, DW_AT_byte_size)->value, nil);
// hchan<T>
dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
- mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, NULL));
+ mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, nil));
copychildren(dwh, hchan);
substitutetype(dwh, "recvq", dww);
substitutetype(dwh, "sendq", dww);
substitutetype(dwh, "free", defptrto(dws));
newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
- getattr(hchan, DW_AT_byte_size)->value, NULL);
+ getattr(hchan, DW_AT_byte_size)->value, nil);
newrefattr(die, DW_AT_type, defptrto(dwh));
}
@@ -1434,6 +1436,7 @@ defdwsymb(Sym* sym, char *s, int t, vlong v, vlong size, int ver, Sym *gotype)
{
DWDie *dv, *dt;
+ USED(size);
if (strncmp(s, "go.string.", 10) == 0)
return;
@@ -1513,12 +1516,12 @@ decodez(char *s)
ss = s + 1; // first is 0
while((o = ((uint8)ss[0] << 8) | (uint8)ss[1]) != 0) {
if (o < 0 || o >= ftabsize) {
- diag("corrupt z entry");
+ diag("dwarf: corrupt z entry");
return 0;
}
f = ftab[o];
if (f == nil) {
- diag("corrupt z entry");
+ diag("dwarf: corrupt z entry");
return 0;
}
len += strlen(f) + 1; // for the '/'
@@ -1590,7 +1593,7 @@ addhistfile(char *zentry)
// if the histfile stack contains ..../runtime/runtime_defs.go
// use that to set gdbscript
static void
-finddebugruntimepath()
+finddebugruntimepath(void)
{
int i, l;
char *c;
@@ -1630,11 +1633,11 @@ checknesting(void)
int i;
if (includetop < 0) {
- diag("corrupt z stack");
+ diag("dwarf: corrupt z stack");
errorexit();
}
if (includetop >= nelem(includestack)) {
- diag("nesting too deep");
+ diag("dwarf: nesting too deep");
for (i = 0; i < nelem(includestack); i++)
diag("\t%s", histfile[includestack[i].file]);
errorexit();
@@ -1660,7 +1663,7 @@ inithist(Auto *a)
// We have a new history. They are guaranteed to come completely
// at the beginning of the compilation unit.
if (a->aoffset != 1) {
- diag("stray 'z' with offset %d", a->aoffset);
+ diag("dwarf: stray 'z' with offset %d", a->aoffset);
return 0;
}
@@ -1801,7 +1804,7 @@ mkvarname(char* name, int da)
// flush previous compilation unit.
static void
-flushunit(DWDie *dwinfo, vlong pc, vlong unitstart)
+flushunit(DWDie *dwinfo, vlong pc, vlong unitstart, int32 header_length)
{
vlong here;
@@ -1817,7 +1820,9 @@ flushunit(DWDie *dwinfo, vlong pc, vlong unitstart)
here = cpos();
seek(cout, unitstart, 0);
- LPUT(here - unitstart - sizeof(int32));
+ LPUT(here - unitstart - sizeof(int32)); // unit_length
+ WPUT(3); // dwarf version
+ LPUT(header_length); // header lenght starting here
cflush();
seek(cout, here, 0);
}
@@ -1829,7 +1834,7 @@ writelines(void)
Prog *q;
Sym *s;
Auto *a;
- vlong unitstart, offs;
+ vlong unitstart, headerend, offs;
vlong pc, epc, lc, llc, lline;
int currfile;
int i, lang, da, dt;
@@ -1839,7 +1844,9 @@ writelines(void)
char *n, *nn;
unitstart = -1;
- epc = pc = 0;
+ headerend = -1;
+ pc = 0;
+ epc = 0;
lc = 1;
llc = 1;
currfile = -1;
@@ -1855,7 +1862,7 @@ writelines(void)
// we're entering a new compilation unit
if (inithist(s->autom)) {
- flushunit(dwinfo, epc, unitstart);
+ flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10);
unitstart = cpos();
if(debug['v'] > 1) {
@@ -1876,10 +1883,10 @@ writelines(void)
// Write .debug_line Line Number Program Header (sec 6.2.4)
// Fields marked with (*) must be changed for 64-bit dwarf
- LPUT(0); // unit_length (*), will be filled in later.
+ LPUT(0); // unit_length (*), will be filled in by flushunit.
WPUT(3); // dwarf version (appendix F)
- LPUT(11); // header_length (*), starting here.
-
+ LPUT(0); // header_length (*), filled in by flushunit.
+ // cpos == unitstart + 4 + 2 + 4
cput(1); // minimum_instruction_length
cput(1); // default_is_stmt
cput(LINE_BASE); // line_base
@@ -1890,18 +1897,17 @@ writelines(void)
cput(1); // standard_opcode_lengths[3]
cput(1); // standard_opcode_lengths[4]
cput(0); // include_directories (empty)
- cput(0); // file_names (empty) (emitted by DW_LNE's below)
- // header_length ends here.
for (i=1; i < histfilesize; i++) {
- cput(0); // start extended opcode
- uleb128put(1 + strlen(histfile[i]) + 4);
- cput(DW_LNE_define_file);
strnput(histfile[i], strlen(histfile[i]) + 4);
// 4 zeros: the string termination + 3 fields.
}
- epc = pc = s->text->pc;
+ cput(0); // terminate file_names.
+ headerend = cpos();
+
+ pc = s->text->pc;
+ epc = pc;
currfile = 1;
lc = 1;
llc = 1;
@@ -1915,7 +1921,7 @@ writelines(void)
continue;
if (unitstart < 0) {
- diag("reachable code before seeing any history: %P", s->text);
+ diag("dwarf: reachable code before seeing any history: %P", s->text);
continue;
}
@@ -1932,7 +1938,7 @@ writelines(void)
for(q = s->text; q != P; q = q->link) {
lh = searchhist(q->line);
if (lh == nil) {
- diag("corrupt history or bad absolute line: %P", q);
+ diag("dwarf: corrupt history or bad absolute line: %P", q);
continue;
}
@@ -1990,7 +1996,7 @@ writelines(void)
newrefattr(dwvar, DW_AT_type, defgotype(a->gotype));
// push dwvar down dwfunc->child to preserve order
- newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, NULL);
+ newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, nil);
dwfunc->child = dwvar->link; // take dwvar out from the top of the list
for (dws = &dwfunc->child; *dws != nil; dws = &(*dws)->link)
if (offs > getattr(*dws, DW_AT_internal_location)->value)
@@ -2004,7 +2010,7 @@ writelines(void)
dwfunc->hash = nil;
}
- flushunit(dwinfo, epc, unitstart);
+ flushunit(dwinfo, epc, unitstart, headerend - unitstart - 10);
linesize = cpos() - lineo;
}
@@ -2066,7 +2072,7 @@ writeframes(void)
// 4 is to exclude the length field.
pad = CIERESERVE + frameo + 4 - cpos();
if (pad < 0) {
- diag("CIERESERVE too small by %lld bytes.", -pad);
+ diag("dwarf: CIERESERVE too small by %lld bytes.", -pad);
errorexit();
}
strnput("", pad);
@@ -2296,6 +2302,9 @@ dwarfemitdebugsections(void)
vlong infoe;
DWDie* die;
+ if(debug['w']) // disable dwarf
+ return;
+
// For diagnostic messages.
newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, strlen("dwtypes"), "dwtypes");
@@ -2340,7 +2349,11 @@ dwarfemitdebugsections(void)
infoo = cpos();
writeinfo();
- gdbscripto = arangeso = pubtypeso = pubnameso = infoe = cpos();
+ infoe = cpos();
+ pubnameso = infoe;
+ pubtypeso = infoe;
+ arangeso = infoe;
+ gdbscripto = infoe;
if (fwdcount > 0) {
if (debug['v'])
@@ -2348,11 +2361,11 @@ dwarfemitdebugsections(void)
seek(cout, infoo, 0);
writeinfo();
if (fwdcount > 0) {
- diag("unresolved references after first dwarf info pass");
+ diag("dwarf: unresolved references after first dwarf info pass");
errorexit();
}
if (infoe != cpos()) {
- diag("inconsistent second dwarf info pass");
+ diag("dwarf: inconsistent second dwarf info pass");
errorexit();
}
}
@@ -2401,6 +2414,9 @@ vlong elfstrdbg[NElfStrDbg];
void
dwarfaddshstrings(Sym *shstrtab)
{
+ if(debug['w']) // disable dwarf
+ return;
+
elfstrdbg[ElfStrDebugAbbrev] = addstring(shstrtab, ".debug_abbrev");
elfstrdbg[ElfStrDebugAranges] = addstring(shstrtab, ".debug_aranges");
elfstrdbg[ElfStrDebugFrame] = addstring(shstrtab, ".debug_frame");
@@ -2420,6 +2436,9 @@ dwarfaddelfheaders(void)
{
ElfShdr *sh;
+ if(debug['w']) // disable dwarf
+ return;
+
sh = newElfShdr(elfstrdbg[ElfStrDebugAbbrev]);
sh->type = SHT_PROGBITS;
sh->off = abbrevo;
@@ -2488,6 +2507,9 @@ dwarfaddmachoheaders(void)
vlong fakestart;
int nsect;
+ if(debug['w']) // disable dwarf
+ return;
+
// Zero vsize segments won't be loaded in memory, even so they
// have to be page aligned in the file.
fakestart = abbrevo & ~0xfff;
@@ -2562,7 +2584,9 @@ dwarfaddmachoheaders(void)
void
dwarfaddpeheaders(void)
{
- dwarfemitdebugsections();
+ if(debug['w']) // disable dwarf
+ return;
+
newPEDWARFSection(".debug_abbrev", abbrevsize);
newPEDWARFSection(".debug_line", linesize);
newPEDWARFSection(".debug_frame", framesize);
diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h
index 08583cc8f..d1370d28b 100644
--- a/src/cmd/ld/elf.h
+++ b/src/cmd/ld/elf.h
@@ -978,6 +978,10 @@ ElfShdr* elfshbits(Section*);
void elfsetstring(char*, int);
void elfaddverneed(Sym*);
+EXTERN int elfstrsize;
+EXTERN char* elfstrdat;
+EXTERN int elftextsh;
+
/*
* Total amount of space to reserve at the start of the file
* for Header, PHeaders, SHeaders, and interp.
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
index e52c5cb34..05d1cc136 100644
--- a/src/cmd/ld/go.c
+++ b/src/cmd/ld/go.c
@@ -415,8 +415,8 @@ loaddynimport(char *file, char *pkg, char *p, int n)
char *pend, *next, *name, *def, *p0, *lib, *q;
Sym *s;
+ USED(file);
pend = p + n;
- p0 = p;
for(; p<pend; p=next) {
next = strchr(p, '\n');
if(next == nil)
@@ -454,6 +454,7 @@ loaddynimport(char *file, char *pkg, char *p, int n)
if(strcmp(name, "_") == 0 && strcmp(def, "_") == 0) {
// allow #pragma dynimport _ _ "foo.so"
// to force a link of foo.so.
+ havedynamic = 1;
adddynlib(lib);
continue;
}
@@ -468,6 +469,7 @@ loaddynimport(char *file, char *pkg, char *p, int n)
s->dynimpname = def;
s->dynimpvers = q;
s->type = SDYNIMPORT;
+ havedynamic = 1;
}
}
return;
@@ -483,8 +485,8 @@ loaddynexport(char *file, char *pkg, char *p, int n)
char *pend, *next, *local, *elocal, *remote, *p0;
Sym *s;
+ USED(file);
pend = p + n;
- p0 = p;
for(; p<pend; p=next) {
next = strchr(p, '\n');
if(next == nil)
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
index d8b0a6fc2..d6aa267c4 100644
--- a/src/cmd/ld/ldpe.c
+++ b/src/cmd/ld/ldpe.c
@@ -147,7 +147,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
goto bad;
obj->sect[i].size = obj->sect[i].sh.SizeOfRawData;
obj->sect[i].name = (char*)obj->sect[i].sh.Name;
- // TODO return error if found .cormeta .rsrc
+ // TODO return error if found .cormeta
}
// load string table
Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
@@ -222,6 +222,8 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
etextp = s;
}
sect->sym = s;
+ if(strcmp(sect->name, ".rsrc") == 0)
+ setpersrc(sect->sym);
}
// load relocations
@@ -259,6 +261,7 @@ ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
rp->type = D_PCREL;
rp->add = 0;
break;
+ case IMAGE_REL_I386_DIR32NB:
case IMAGE_REL_I386_DIR32:
rp->type = D_ADDR;
// load addend from image
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
index 15219ba11..04ee790a4 100644
--- a/src/cmd/ld/lib.c
+++ b/src/cmd/ld/lib.c
@@ -69,7 +69,7 @@ libinit(void)
// add goroot to the end of the libdir list.
libdir[nlibdir++] = smprint("%s/pkg/%s_%s", goroot, goos, goarch);
- unlink(outfile);
+ remove(outfile);
cout = create(outfile, 1, 0775);
if(cout < 0) {
diag("cannot create %s", outfile);
@@ -235,30 +235,52 @@ addlibpath(char *srcref, char *objref, char *file, char *pkg)
}
void
-loadlib(void)
+loadinternal(char *name)
{
char pname[1024];
int i, found;
found = 0;
for(i=0; i<nlibdir; i++) {
- snprint(pname, sizeof pname, "%s/runtime.a", libdir[i]);
+ snprint(pname, sizeof pname, "%s/%s.a", libdir[i], name);
if(debug['v'])
- Bprint(&bso, "searching for runtime.a in %s\n", pname);
+ Bprint(&bso, "searching for %s.a in %s\n", name, pname);
if(access(pname, AEXIST) >= 0) {
- addlibpath("internal", "internal", pname, "runtime");
+ addlibpath("internal", "internal", pname, name);
found = 1;
break;
}
}
if(!found)
- Bprint(&bso, "warning: unable to find runtime.a\n");
+ Bprint(&bso, "warning: unable to find %s.a\n", name);
+}
+
+void
+loadlib(void)
+{
+ int i;
+
+ loadinternal("runtime");
+ if(thechar == '5')
+ loadinternal("math");
for(i=0; i<libraryp; i++) {
if(debug['v'])
Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i].file, library[i].objref);
objfile(library[i].file, library[i].pkg);
}
+
+ // We've loaded all the code now.
+ // If there are no dynamic libraries needed, gcc disables dynamic linking.
+ // Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
+ // assumes that a dynamic binary always refers to at least one dynamic library.
+ // Rather than be a source of test cases for glibc, disable dynamic linking
+ // the same way that gcc would.
+ //
+ // Exception: on OS X, programs such as Shark only work with dynamic
+ // binaries, so leave it enabled on OS X (Mach-O) binaries.
+ if(!havedynamic && HEADTYPE != Hdarwin)
+ debug['d'] = 1;
}
/*
@@ -386,9 +408,6 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
eof = Boffset(f) + len;
pn = strdup(pn);
-
- USED(c4);
- USED(magic);
c1 = Bgetc(f);
c2 = Bgetc(f);
@@ -398,7 +417,7 @@ ldobj(Biobuf *f, char *pkg, int64 len, char *pn, int whence)
Bungetc(f);
Bungetc(f);
Bungetc(f);
-
+
magic = c1<<24 | c2<<16 | c3<<8 | c4;
if(magic == 0x7f454c46) { // \x7F E L F
ldelf(f, pkg, len, pn);
@@ -486,7 +505,6 @@ _lookup(char *symb, int v, int creat)
// not if(h < 0) h = ~h, because gcc 4.3 -O2 miscompiles it.
h &= 0xffffff;
h %= NHASH;
- c = symb[0];
for(s = hash[h]; s != S; s = s->hash)
if(memcmp(s->name, symb, l) == 0)
return s;
@@ -511,7 +529,7 @@ _lookup(char *symb, int v, int creat)
s->size = 0;
hash[h] = s;
nsymbol++;
-
+
s->allsym = allsym;
allsym = s;
return s;
@@ -538,7 +556,6 @@ copyhistfrog(char *buf, int nbuf)
p = buf;
ep = buf + nbuf;
- i = 0;
for(i=0; i<histfrogp; i++) {
p = seprint(p, ep, "%s", histfrog[i]->name+1);
if(i+1<histfrogp && (p == buf || p[-1] != '/'))
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
index 8b603a04a..dfd18fbff 100644
--- a/src/cmd/ld/lib.h
+++ b/src/cmd/ld/lib.h
@@ -122,6 +122,7 @@ EXTERN char* outfile;
EXTERN int32 nsymbol;
EXTERN char* thestring;
EXTERN int ndynexp;
+EXTERN int havedynamic;
EXTERN Segment segtext;
EXTERN Segment segdata;
@@ -185,7 +186,7 @@ vlong addsize(Sym*, Sym*);
vlong adduint8(Sym*, uint8);
vlong adduint16(Sym*, uint16);
void asmsym(void);
-void asmelfsym64(void);
+void asmelfsym(void);
void asmplan9sym(void);
void strnput(char*, int);
void dodata(void);
@@ -200,6 +201,7 @@ void addexport(void);
void dostkcheck(void);
void undef(void);
void doweak(void);
+void setpersrc(Sym*);
int pathchar(void);
void* mal(uint32);
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
index 01349bb10..0b12ac17b 100644
--- a/src/cmd/ld/macho.c
+++ b/src/cmd/ld/macho.c
@@ -17,6 +17,14 @@ static MachoSeg seg[16];
static MachoDebug xdebug[16];
static int nload, mload, nseg, ndebug, nsect;
+// Amount of space left for adding load commands
+// that refer to dynamic libraries. Because these have
+// to go in the Mach-O header, we can't just pick a
+// "big enough" header size. The initial header is
+// one page, the non-dynamic library stuff takes
+// up about 1300 bytes; we overestimate that as 2k.
+static int load_budget = INITIAL_MACHO_HEADR - 2*1024;
+
void
machoinit(void)
{
@@ -267,6 +275,17 @@ domacho(void)
void
machoadddynlib(char *lib)
{
+ // Will need to store the library name rounded up
+ // and 24 bytes of header metadata. If not enough
+ // space, grab another page of initial space at the
+ // beginning of the output file.
+ load_budget -= (strlen(lib)+7)/8*8 + 24;
+ if(load_budget < 0) {
+ HEADR += 4096;
+ INITTEXT += 4096;
+ load_budget += 4096;
+ }
+
if(ndylib%32 == 0) {
dylib = realloc(dylib, (ndylib+32)*sizeof dylib[0]);
if(dylib == nil) {
@@ -463,8 +482,8 @@ asmbmacho(void)
}
a = machowrite();
- if(a > MACHORESERVE)
- diag("MACHORESERVE too small: %d > %d", a, MACHORESERVE);
+ if(a > HEADR)
+ diag("HEADR too small: %d > %d", a, HEADR);
}
vlong
diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h
index 4cc7edc80..f55104150 100644
--- a/src/cmd/ld/macho.h
+++ b/src/cmd/ld/macho.h
@@ -63,7 +63,7 @@ void machoinit(void);
* for Header, PHeaders, and SHeaders.
* May waste some.
*/
-#define MACHORESERVE 3*1024
+#define INITIAL_MACHO_HEADR 4*1024
enum {
MACHO_CPU_AMD64 = (1<<24)|7,
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
index d523ca9c5..91e15d343 100644
--- a/src/cmd/ld/pe.c
+++ b/src/cmd/ld/pe.c
@@ -34,6 +34,8 @@ static char dosstub[] =
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
+static Sym *rsrcsym;
+
static char symnames[256];
static int nextsymoff;
@@ -459,6 +461,48 @@ addsymtable(void)
}
void
+setpersrc(Sym *sym)
+{
+ if(rsrcsym != nil)
+ diag("too many .rsrc sections");
+
+ rsrcsym = sym;
+}
+
+void
+addpersrc(void)
+{
+ IMAGE_SECTION_HEADER *h;
+ uchar *p;
+ uint32 val;
+ Reloc *r;
+
+ if(rsrcsym == nil)
+ return;
+
+ h = addpesection(".rsrc", rsrcsym->size, rsrcsym->size, 0);
+ h->Characteristics = IMAGE_SCN_MEM_READ|
+ IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA;
+ // relocation
+ for(r=rsrcsym->r; r<rsrcsym->r+rsrcsym->nr; r++) {
+ p = rsrcsym->p + r->off;
+ val = h->VirtualAddress + r->add;
+ // 32-bit little-endian
+ p[0] = val;
+ p[1] = val>>8;
+ p[2] = val>>16;
+ p[3] = val>>24;
+ }
+ ewrite(cout, rsrcsym->p, rsrcsym->size);
+ strnput("", h->SizeOfRawData - rsrcsym->size);
+ cflush();
+
+ // update data directory
+ dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h->VirtualAddress;
+ dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize;
+}
+
+void
asmbpe(void)
{
IMAGE_SECTION_HEADER *t, *d;
@@ -484,15 +528,17 @@ asmbpe(void)
d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
+ if(!debug['s'])
+ dwarfaddpeheaders();
+
addimports(nextfileoff, d);
addexports(nextfileoff);
- if(!debug['s'])
- dwarfaddpeheaders();
-
addsymtable();
-
+
+ addpersrc();
+
fh.NumberOfSections = nsect;
fh.TimeDateStamp = time(0);
fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h
index 2180fb88c..7aa938829 100644
--- a/src/cmd/ld/pe.h
+++ b/src/cmd/ld/pe.h
@@ -175,3 +175,5 @@ typedef struct {
uint32 NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[16];
} PE64_IMAGE_OPTIONAL_HEADER;
+
+void setpersrc(Sym *sym);
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
index da698fcc0..e3093b2aa 100644
--- a/src/cmd/ld/symtab.c
+++ b/src/cmd/ld/symtab.c
@@ -61,49 +61,35 @@ putelfstr(char *s)
}
void
-putelfsym64(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
+putelfsyment(int off, vlong addr, vlong size, int info, int shndx)
{
- int bind, type, shndx, stroff;
-
- bind = STB_GLOBAL;
- switch(t) {
- default:
- return;
- case 'T':
- type = STT_FUNC;
- shndx = elftextsh + 0;
- break;
- case 'D':
- type = STT_OBJECT;
- shndx = elftextsh + 1;
+ switch(thechar) {
+ case '6':
+ LPUT(off);
+ cput(info);
+ cput(0);
+ WPUT(shndx);
+ VPUT(addr);
+ VPUT(size);
+ symsize += ELF64SYMSIZE;
break;
- case 'B':
- type = STT_OBJECT;
- shndx = elftextsh + 2;
+ default:
+ LPUT(off);
+ LPUT(addr);
+ LPUT(size);
+ cput(info);
+ cput(0);
+ WPUT(shndx);
+ symsize += ELF32SYMSIZE;
break;
}
-
- stroff = putelfstr(s);
- LPUT(stroff); // string
- cput((bind<<4)|(type&0xF));
- cput(0);
- WPUT(shndx);
- VPUT(addr);
- VPUT(size);
}
void
-asmelfsym64(void)
+putelfsym(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
{
- genasmsym(putelfsym64);
-}
+ int bind, type, shndx, off;
-void
-putelfsym32(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
-{
- int bind, type, shndx, stroff;
-
- bind = STB_GLOBAL;
switch(t) {
default:
return;
@@ -113,27 +99,27 @@ putelfsym32(Sym *x, char *s, int t, vlong addr, vlong size, int ver, Sym *go)
break;
case 'D':
type = STT_OBJECT;
- shndx = elftextsh + 1;
+ if((x->type&~SSUB) == SRODATA)
+ shndx = elftextsh + 1;
+ else
+ shndx = elftextsh + 2;
break;
case 'B':
type = STT_OBJECT;
- shndx = elftextsh + 2;
+ shndx = elftextsh + 3;
break;
}
-
- stroff = putelfstr(s);
- LPUT(stroff); // string
- LPUT(addr);
- LPUT(size);
- cput((bind<<4)|(type&0xF));
- cput(0);
- WPUT(shndx);
+ bind = ver ? STB_LOCAL : STB_GLOBAL;
+ off = putelfstr(s);
+ putelfsyment(off, addr, size, (bind<<4)|(type&0xf), shndx);
}
void
-asmelfsym32(void)
+asmelfsym(void)
{
- genasmsym(putelfsym32);
+ // the first symbol entry is reserved
+ putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0);
+ genasmsym(putelfsym);
}
void
diff --git a/src/cmd/prof/gopprof b/src/cmd/prof/gopprof
index 8863fc623..be5f84e9e 100755
--- a/src/cmd/prof/gopprof
+++ b/src/cmd/prof/gopprof
@@ -150,7 +150,8 @@ pprof [options] <profile>
The /<service> can be $HEAP_PAGE, $PROFILE_PAGE, /pprof/pmuprofile,
$GROWTH_PAGE, $CONTENTION_PAGE, /pprof/wall,
or /pprof/filteredprofile.
- For instance: "pprof http://myserver.com:80$HEAP_PAGE".
+ For instance:
+ pprof http://myserver.com:80$HEAP_PAGE
If /<service> is omitted, the service defaults to $PROFILE_PAGE (cpu profiling).
pprof --symbols <program>
Maps addresses to symbol names. In this mode, stdin should be a
@@ -532,7 +533,7 @@ sub Init() {
ConfigureObjTools($main::prog)
}
- # Break the opt_list_prefix into the prefix_list array
+ # Break the opt_lib_prefix into the prefix_list array
@prefix_list = split (',', $main::opt_lib_prefix);
# Remove trailing / from the prefixes, in the list to prevent
@@ -626,7 +627,7 @@ sub Main() {
if ($main::opt_disasm) {
PrintDisassembly($libs, $flat, $cumulative, $main::opt_disasm, $total);
} elsif ($main::opt_list) {
- PrintListing($libs, $flat, $cumulative, $main::opt_list);
+ PrintListing($total, $libs, $flat, $cumulative, $main::opt_list, 0);
} elsif ($main::opt_text) {
# Make sure the output is empty when have nothing to report
# (only matters when --heapcheck is given but we must be
@@ -814,7 +815,7 @@ sub InteractiveCommand {
my $ignore;
($routine, $ignore) = ParseInteractiveArgs($3);
- my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore);
+ my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
@@ -841,21 +842,22 @@ sub InteractiveCommand {
return 1;
}
- if (m/^\s*list\s*(.+)/) {
+ if (m/^\s*(web)?list\s*(.+)/) {
+ my $html = (defined($1) && ($1 eq "web"));
$main::opt_list = 1;
my $routine;
my $ignore;
- ($routine, $ignore) = ParseInteractiveArgs($1);
+ ($routine, $ignore) = ParseInteractiveArgs($2);
- my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore);
+ my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
my $flat = FlatProfile($reduced);
my $cumulative = CumulativeProfile($reduced);
- PrintListing($libs, $flat, $cumulative, $routine);
+ PrintListing($total, $libs, $flat, $cumulative, $routine, $html);
return 1;
}
if (m/^\s*disasm\s*(.+)/) {
@@ -866,7 +868,7 @@ sub InteractiveCommand {
($routine, $ignore) = ParseInteractiveArgs($1);
# Process current profile to account for various settings
- my $profile = ProcessProfile($orig_profile, $symbols, "", $ignore);
+ my $profile = ProcessProfile($total, $orig_profile, $symbols, "", $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
@@ -890,7 +892,7 @@ sub InteractiveCommand {
($focus, $ignore) = ParseInteractiveArgs($2);
# Process current profile to account for various settings
- my $profile = ProcessProfile($orig_profile, $symbols, $focus, $ignore);
+ my $profile = ProcessProfile($total, $orig_profile, $symbols, $focus, $ignore);
my $reduced = ReduceProfile($symbols, $profile);
# Get derived profiles
@@ -916,6 +918,7 @@ sub InteractiveCommand {
sub ProcessProfile {
+ my $total_count = shift;
my $orig_profile = shift;
my $symbols = shift;
my $focus = shift;
@@ -923,7 +926,6 @@ sub ProcessProfile {
# Process current profile to account for various settings
my $profile = $orig_profile;
- my $total_count = TotalProfile($profile);
printf("Total: %s %s\n", Unparse($total_count), Units());
if ($focus ne '') {
$profile = FocusProfile($symbols, $profile, $focus);
@@ -970,6 +972,11 @@ Commands:
list [routine_regexp] [-ignore1] [-ignore2]
Show source listing of routines whose names match "routine_regexp"
+ weblist [routine_regexp] [-ignore1] [-ignore2]
+ Displays a source listing of routines whose names match "routine_regexp"
+ in a web browser. You can click on source lines to view the
+ corresponding disassembly.
+
top [--cum] [-ignore1] [-ignore2]
top20 [--cum] [-ignore1] [-ignore2]
top37 [--cum] [-ignore1] [-ignore2]
@@ -1144,7 +1151,7 @@ sub PrintText {
$sym);
}
$lines++;
- last if ($line_limit >= 0 && $lines > $line_limit);
+ last if ($line_limit >= 0 && $lines >= $line_limit);
}
}
@@ -1291,11 +1298,32 @@ sub ByName {
# Print source-listing for all all routines that match $main::opt_list
sub PrintListing {
+ my $total = shift;
my $libs = shift;
my $flat = shift;
my $cumulative = shift;
my $list_opts = shift;
-
+ my $html = shift;
+
+ my $output = \*STDOUT;
+ my $fname = "";
+
+
+ if ($html) {
+ # Arrange to write the output to a temporary file
+ $fname = TempName($main::next_tmpfile, "html");
+ $main::next_tmpfile++;
+ if (!open(TEMP, ">$fname")) {
+ print STDERR "$fname: $!\n";
+ return;
+ }
+ $output = \*TEMP;
+ print $output HtmlListingHeader();
+ printf $output ("<div class=\"legend\">%s<br>Total: %s %s</div>\n",
+ $main::prog, Unparse($total), Units());
+ }
+
+ my $listed = 0;
foreach my $lib (@{$libs}) {
my $symbol_table = GetProcedureBoundaries($lib->[0], $list_opts);
my $offset = AddressSub($lib->[1], $lib->[3]);
@@ -1307,15 +1335,98 @@ sub PrintListing {
my $addr = AddressAdd($start_addr, $offset);
for (my $i = 0; $i < $length; $i++) {
if (defined($cumulative->{$addr})) {
- PrintSource($lib->[0], $offset,
- $routine, $flat, $cumulative,
- $start_addr, $end_addr);
+ $listed += PrintSource(
+ $lib->[0], $offset,
+ $routine, $flat, $cumulative,
+ $start_addr, $end_addr,
+ $html,
+ $output);
last;
}
$addr = AddressInc($addr);
}
}
}
+
+ if ($html) {
+ if ($listed > 0) {
+ print $output HtmlListingFooter();
+ close($output);
+ RunWeb($fname);
+ } else {
+ close($output);
+ unlink($fname);
+ }
+ }
+}
+
+sub HtmlListingHeader {
+ return <<'EOF';
+<DOCTYPE html>
+<html>
+<head>
+<title>Pprof listing</title>
+<style type="text/css">
+body {
+ font-family: sans-serif;
+}
+h1 {
+ font-size: 1.5em;
+ margin-bottom: 4px;
+}
+.legend {
+ font-size: 1.25em;
+}
+.line {
+ color: #aaaaaa;
+}
+.livesrc {
+ color: #0000ff;
+ cursor: pointer;
+}
+.livesrc:hover {
+ background-color: #cccccc;
+}
+.asm {
+ color: #888888;
+ display: none;
+}
+</style>
+<script type="text/javascript">
+function pprof_toggle_asm(e) {
+ var target;
+ if (!e) e = window.event;
+ if (e.target) target = e.target;
+ else if (e.srcElement) target = e.srcElement;
+
+ if (target && target.className == "livesrc") {
+ var asm = target.nextSibling;
+ if (asm && asm.className == "asm") {
+ asm.style.display = (asm.style.display == "block" ? "none" : "block");
+ e.preventDefault();
+ return false;
+ }
+ }
+}
+</script>
+</head>
+<body>
+EOF
+}
+
+sub HtmlListingFooter {
+ return <<'EOF';
+</body>
+</html>
+EOF
+}
+
+sub HtmlEscape {
+ my $text = shift;
+ $text =~ s/&/&amp;/g;
+ $text =~ s/</&lt;/g;
+ $text =~ s/>/&gt;/g;
+ return $text;
}
# Returns the indentation of the line, if it has any non-whitespace
@@ -1338,6 +1449,8 @@ sub PrintSource {
my $cumulative = shift;
my $start_addr = shift;
my $end_addr = shift;
+ my $html = shift;
+ my $output = shift;
# Disassemble all instructions (just to get line numbers)
my @instructions = Disassemble($prog, $offset, $start_addr, $end_addr);
@@ -1353,7 +1466,7 @@ sub PrintSource {
}
if (!defined($filename)) {
print STDERR "no filename found in $routine\n";
- return;
+ return 0;
}
# Hack 2: assume that the largest line number from $filename is the
@@ -1386,7 +1499,7 @@ sub PrintSource {
{
if (!open(FILE, "<$filename")) {
print STDERR "$filename: $!\n";
- return;
+ return 0;
}
my $l = 0;
my $first_indentation = -1;
@@ -1414,12 +1527,21 @@ sub PrintSource {
# Assign all samples to the range $firstline,$lastline,
# Hack 4: If an instruction does not occur in the range, its samples
# are moved to the next instruction that occurs in the range.
- my $samples1 = {};
- my $samples2 = {};
- my $running1 = 0; # Unassigned flat counts
- my $running2 = 0; # Unassigned cumulative counts
- my $total1 = 0; # Total flat counts
- my $total2 = 0; # Total cumulative counts
+ my $samples1 = {}; # Map from line number to flat count
+ my $samples2 = {}; # Map from line number to cumulative count
+ my $running1 = 0; # Unassigned flat counts
+ my $running2 = 0; # Unassigned cumulative counts
+ my $total1 = 0; # Total flat counts
+ my $total2 = 0; # Total cumulative counts
+ my %disasm = (); # Map from line number to disassembly
+ my $running_disasm = ""; # Unassigned disassembly
+ my $skip_marker = "---\n";
+ if ($html) {
+ $skip_marker = "";
+ for (my $l = $firstline; $l <= $lastline; $l++) {
+ $disasm{$l} = "";
+ }
+ }
foreach my $e (@instructions) {
# Add up counts for all address that fall inside this instruction
my $c1 = 0;
@@ -1428,6 +1550,15 @@ sub PrintSource {
$c1 += GetEntry($flat, $a);
$c2 += GetEntry($cumulative, $a);
}
+
+ if ($html) {
+ $running_disasm .= sprintf(" %6s %6s \t\t%8s: %s\n",
+ HtmlPrintNumber($c1),
+ HtmlPrintNumber($c2),
+ $e->[0],
+ CleanDisassembly($e->[3]));
+ }
+
$running1 += $c1;
$running2 += $c2;
$total1 += $c1;
@@ -1442,6 +1573,10 @@ sub PrintSource {
AddEntry($samples2, $line, $running2);
$running1 = 0;
$running2 = 0;
+ if ($html) {
+ $disasm{$line} .= $running_disasm;
+ $running_disasm = '';
+ }
}
}
@@ -1449,16 +1584,28 @@ sub PrintSource {
AddEntry($samples1, $lastline, $running1);
AddEntry($samples2, $lastline, $running2);
- printf("ROUTINE ====================== %s in %s\n" .
- "%6s %6s Total %s (flat / cumulative)\n",
- ShortFunctionName($routine),
- $filename,
- Units(),
- Unparse($total1),
- Unparse($total2));
+ if ($html) {
+ printf $output (
+ "<h1>%s</h1>%s\n<pre onClick=\"pprof_toggle_asm()\">\n" .
+ "Total:%6s %6s (flat / cumulative %s)\n",
+ HtmlEscape(ShortFunctionName($routine)),
+ HtmlEscape($filename),
+ Unparse($total1),
+ Unparse($total2),
+ Units());
+ } else {
+ printf $output (
+ "ROUTINE ====================== %s in %s\n" .
+ "%6s %6s Total %s (flat / cumulative)\n",
+ ShortFunctionName($routine),
+ $filename,
+ Unparse($total1),
+ Unparse($total2),
+ Units());
+ }
if (!open(FILE, "<$filename")) {
print STDERR "$filename: $!\n";
- return;
+ return 0;
}
my $l = 0;
while (<FILE>) {
@@ -1468,16 +1615,47 @@ sub PrintSource {
(($l <= $oldlastline + 5) || ($l <= $lastline))) {
chop;
my $text = $_;
- if ($l == $firstline) { printf("---\n"); }
- printf("%6s %6s %4d: %s\n",
- UnparseAlt(GetEntry($samples1, $l)),
- UnparseAlt(GetEntry($samples2, $l)),
- $l,
- $text);
- if ($l == $lastline) { printf("---\n"); }
+ if ($l == $firstline) { print $output $skip_marker; }
+ my $n1 = GetEntry($samples1, $l);
+ my $n2 = GetEntry($samples2, $l);
+ if ($html) {
+ my $dis = $disasm{$l};
+ if (!defined($dis) || $n1 + $n2 == 0) {
+ # No samples/disassembly for this source line
+ printf $output (
+ "<span class=\"line\">%5d</span> " .
+ "<span class=\"deadsrc\">%6s %6s %s</span>\n",
+ $l,
+ HtmlPrintNumber($n1),
+ HtmlPrintNumber($n2),
+ HtmlEscape($text));
+ } else {
+ printf $output (
+ "<span class=\"line\">%5d</span> " .
+ "<span class=\"livesrc\">%6s %6s %s</span>" .
+ "<span class=\"asm\">%s</span>\n",
+ $l,
+ HtmlPrintNumber($n1),
+ HtmlPrintNumber($n2),
+ HtmlEscape($text),
+ HtmlEscape($dis));
+ }
+ } else {
+ printf $output(
+ "%6s %6s %4d: %s\n",
+ UnparseAlt($n1),
+ UnparseAlt($n2),
+ $l,
+ $text);
+ }
+ if ($l == $lastline) { print $output $skip_marker; }
};
}
close(FILE);
+ if ($html) {
+ print $output "</pre>\n";
+ }
+ return 1;
}
# Return the source line for the specified file/linenumber.
@@ -1625,16 +1803,11 @@ sub PrintDisassembledFunction {
$address =~ s/^0x//;
$address =~ s/^0*//;
- # Trim symbols
- my $d = $e->[3];
- while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax)
- while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments
-
printf("%6s %6s %8s: %6s\n",
UnparseAlt($flat_count[$x]),
UnparseAlt($cum_count[$x]),
$address,
- $d);
+ CleanDisassembly($e->[3]));
}
}
}
@@ -2254,6 +2427,16 @@ sub UnparseAlt {
}
}
+# Alternate pretty-printed form: 0 maps to ""
+sub HtmlPrintNumber {
+ my $num = shift;
+ if ($num == 0) {
+ return "";
+ } else {
+ return Unparse($num);
+ }
+}
+
# Return output units
sub Units {
if ($main::profile_type eq 'heap' || $main::profile_type eq 'growth') {
@@ -2415,6 +2598,8 @@ sub RemoveUninterestingFrames {
'copyin',
'gostring',
'gostringsize',
+ 'growslice1',
+ 'appendslice1',
'hash_init',
'hash_subtable_new',
'hash_conv',
@@ -2422,6 +2607,8 @@ sub RemoveUninterestingFrames {
'hash_insert_internal',
'hash_insert',
'mapassign',
+ 'runtime.mapassign',
+ 'runtime.appendslice',
'runtime.mapassign1',
'makechan',
'makemap',
@@ -2433,11 +2620,13 @@ sub RemoveUninterestingFrames {
'unsafe.New',
'runtime.mallocgc',
'runtime.catstring',
+ 'runtime.growslice',
'runtime.ifaceT2E',
'runtime.ifaceT2I',
'runtime.makechan',
'runtime.makechan_c',
'runtime.makemap',
+ 'runtime.makemap_c',
'runtime.makeslice',
'runtime.mal',
'runtime.slicebytetostring',
@@ -4302,6 +4491,14 @@ sub ShortFunctionName {
return $function;
}
+# Trim overly long symbols found in disassembler output
+sub CleanDisassembly {
+ my $d = shift;
+ while ($d =~ s/\([^()%]*\)(\s*const)?//g) { } # Argument types, not (%rax)
+ while ($d =~ s/(\w+)<[^<>]*>/$1/g) { } # Remove template arguments
+ return $d;
+}
+
##### Miscellaneous #####
# Find the right versions of the above object tools to use. The