diff options
Diffstat (limited to 'src/cmd')
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(®, types[TINT64], D_AX); gins(ATESTQ, ®, ®); - 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(®, types[TINT64], D_AX); gins(ATESTL, ®, ®); - 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/&/&/g; + $text =~ s/</</g; + $text =~ s/>/>/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 |