summaryrefslogtreecommitdiff
path: root/src/cmd/6g/gsubr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/6g/gsubr.c')
-rw-r--r--src/cmd/6g/gsubr.c297
1 files changed, 181 insertions, 116 deletions
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index ededcf673..fc5407a1f 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -103,9 +103,13 @@ dumpdata(void)
/*
* generate a branch.
* t is ignored.
+ * likely values are for branch prediction:
+ * -1 unlikely
+ * 0 no opinion
+ * +1 likely
*/
Prog*
-gbranch(int as, Type *t)
+gbranch(int as, Type *t, int likely)
{
Prog *p;
@@ -113,7 +117,11 @@ gbranch(int as, Type *t)
p = prog(as);
p->to.type = D_BRANCH;
- p->to.branch = P;
+ p->to.u.branch = P;
+ if(as != AJMP && likely != 0) {
+ p->from.type = D_CONST;
+ p->from.offset = likely > 0;
+ }
return p;
}
@@ -125,7 +133,7 @@ patch(Prog *p, Prog *to)
{
if(p->to.type != D_BRANCH)
fatal("patch: not a branch");
- p->to.branch = to;
+ p->to.u.branch = to;
p->to.offset = to->loc;
}
@@ -136,8 +144,8 @@ unpatch(Prog *p)
if(p->to.type != D_BRANCH)
fatal("unpatch: not a branch");
- q = p->to.branch;
- p->to.branch = P;
+ q = p->to.u.branch;
+ p->to.u.branch = P;
p->to.offset = 0;
return q;
}
@@ -165,44 +173,6 @@ newplist(void)
}
void
-clearstk(void)
-{
- Plist *pl;
- Prog *p1, *p2;
- Node sp, di, cx, con, ax;
-
- if((uint32)plast->firstpc->to.offset <= 0)
- return;
-
- // reestablish context for inserting code
- // at beginning of function.
- pl = plast;
- p1 = pl->firstpc;
- p2 = p1->link;
- pc = mal(sizeof(*pc));
- clearp(pc);
- p1->link = pc;
-
- // zero stack frame
- nodreg(&sp, types[tptr], D_SP);
- nodreg(&di, types[tptr], D_DI);
- nodreg(&cx, types[TUINT64], D_CX);
- nodconst(&con, types[TUINT64], (uint32)p1->to.offset / widthptr);
- gins(ACLD, N, N);
- gins(AMOVQ, &sp, &di);
- gins(AMOVQ, &con, &cx);
- nodconst(&con, types[TUINT64], 0);
- nodreg(&ax, types[TUINT64], D_AX);
- gins(AMOVQ, &con, &ax);
- gins(AREP, N, N);
- gins(ASTOSQ, N, N);
-
- // continue with original code.
- gins(ANOP, N, N)->link = p2;
- pc = P;
-}
-
-void
gused(Node *n)
{
gins(ANOP, n, N); // used
@@ -213,22 +183,23 @@ gjmp(Prog *to)
{
Prog *p;
- p = gbranch(AJMP, T);
+ p = gbranch(AJMP, T, 0);
if(to != P)
patch(p, to);
return p;
}
void
-ggloblnod(Node *nam, int32 width)
+ggloblnod(Node *nam)
{
Prog *p;
p = gins(AGLOBL, nam, N);
p->lineno = nam->lineno;
+ p->from.gotype = ngotype(nam);
p->to.sym = S;
p->to.type = D_CONST;
- p->to.offset = width;
+ p->to.offset = nam->type->width;
if(nam->readonly)
p->from.scale = RODATA;
if(nam->type != T && !haspointers(nam->type))
@@ -236,7 +207,18 @@ ggloblnod(Node *nam, int32 width)
}
void
-ggloblsym(Sym *s, int32 width, int dupok)
+gtrack(Sym *s)
+{
+ Prog *p;
+
+ p = gins(AUSEFIELD, N, N);
+ p->from.type = D_EXTERN;
+ p->from.index = D_NONE;
+ p->from.sym = s;
+}
+
+void
+ggloblsym(Sym *s, int32 width, int dupok, int rodata)
{
Prog *p;
@@ -248,8 +230,9 @@ ggloblsym(Sym *s, int32 width, int dupok)
p->to.index = D_NONE;
p->to.offset = width;
if(dupok)
- p->from.scale = DUPOK;
- p->from.scale |= RODATA;
+ p->from.scale |= DUPOK;
+ if(rodata)
+ p->from.scale |= RODATA;
}
int
@@ -272,11 +255,12 @@ isfat(Type *t)
* call afunclit to fix up the argument.
*/
void
-afunclit(Addr *a)
+afunclit(Addr *a, Node *n)
{
if(a->type == D_ADDR && a->index == D_EXTERN) {
a->type = D_EXTERN;
a->index = D_NONE;
+ a->sym = n->sym;
}
}
@@ -300,7 +284,7 @@ ginit(void)
reg[i] = 1;
for(i=D_AX; i<=D_R15; i++)
reg[i] = 0;
- for(i=D_X0; i<=D_X7; i++)
+ for(i=D_X0; i<=D_X15; i++)
reg[i] = 0;
for(i=0; i<nelem(resvd); i++)
@@ -318,7 +302,7 @@ gclean(void)
for(i=D_AX; i<=D_R15; i++)
if(reg[i])
yyerror("reg %R left allocated\n", i);
- for(i=D_X0; i<=D_X7; i++)
+ for(i=D_X0; i<=D_X15; i++)
if(reg[i])
yyerror("reg %R left allocated\n", i);
}
@@ -388,10 +372,10 @@ regalloc(Node *n, Type *t, Node *o)
case TFLOAT64:
if(o != N && o->op == OREGISTER) {
i = o->val.u.reg;
- if(i >= D_X0 && i <= D_X7)
+ if(i >= D_X0 && i <= D_X15)
goto out;
}
- for(i=D_X0; i<=D_X7; i++)
+ for(i=D_X0; i<=D_X15; i++)
if(reg[i] == 0)
goto out;
fatal("out of floating registers");
@@ -572,6 +556,10 @@ ismem(Node *n)
case ONAME:
case OPARAM:
return 1;
+ case OADDR:
+ if(flag_largemodel)
+ return 1;
+ break;
}
return 0;
}
@@ -616,7 +604,7 @@ gmove(Node *f, Node *t)
Prog *p1, *p2;
if(debug['M'])
- print("gmove %N -> %N\n", f, t);
+ print("gmove %lN -> %lN\n", f, t);
ft = simsimtype(f->type);
tt = simsimtype(t->type);
@@ -706,11 +694,14 @@ gmove(Node *f, Node *t)
case CASE(TINT32, TUINT32):
case CASE(TUINT32, TINT32):
case CASE(TUINT32, TUINT32):
+ a = AMOVL;
+ break;
+
case CASE(TINT64, TINT32): // truncate
case CASE(TUINT64, TINT32):
case CASE(TINT64, TUINT32):
case CASE(TUINT64, TUINT32):
- a = AMOVL;
+ a = AMOVQL;
break;
case CASE(TINT64, TINT64): // same size
@@ -822,9 +813,9 @@ gmove(Node *f, Node *t)
// algorithm is:
// if small enough, use native float64 -> int64 conversion.
// otherwise, subtract 2^63, convert, and add it back.
- a = ACVTSS2SQ;
+ a = ACVTTSS2SQ;
if(ft == TFLOAT64)
- a = ACVTSD2SQ;
+ a = ACVTTSD2SQ;
bignodes();
regalloc(&r1, types[ft], N);
regalloc(&r2, types[tt], t);
@@ -832,9 +823,9 @@ gmove(Node *f, Node *t)
regalloc(&r4, types[tt], N);
gins(optoas(OAS, f->type), f, &r1);
gins(optoas(OCMP, f->type), &bigf, &r1);
- p1 = gbranch(optoas(OLE, f->type), T);
+ p1 = gbranch(optoas(OLE, f->type), T, +1);
gins(a, &r1, &r2);
- p2 = gbranch(AJMP, T);
+ p2 = gbranch(AJMP, T, 0);
patch(p1, pc);
gins(optoas(OAS, f->type), &bigf, &r3);
gins(optoas(OSUB, f->type), &r3, &r1);
@@ -903,9 +894,9 @@ gmove(Node *f, Node *t)
regalloc(&r4, f->type, N);
gmove(f, &r1);
gins(ACMPQ, &r1, &zero);
- p1 = gbranch(AJLT, T);
+ p1 = gbranch(AJLT, T, +1);
gins(a, &r1, &r2);
- p2 = gbranch(AJMP, T);
+ p2 = gbranch(AJMP, T, 0);
patch(p1, pc);
gmove(&r1, &r3);
gins(ASHRQ, &one, &r3);
@@ -1016,6 +1007,13 @@ gins(int as, Node *f, Node *t)
case AMOVSD:
if(f != N && t != N && samaddr(f, t))
return nil;
+ break;
+
+ case ALEAQ:
+ if(f != N && isconst(f, CTNIL)) {
+ fatal("gins LEAQ nil %T", f->type);
+ }
+ break;
}
memset(&af, 0, sizeof af);
@@ -1047,13 +1045,34 @@ gins(int as, Node *f, Node *t)
w = 8;
break;
}
- if(w != 0 && f != N && (af.width > w || at.width > w)) {
+ if(w != 0 && ((f != N && af.width < w) || (t != N && at.width > w))) {
+ dump("f", f);
+ dump("t", t);
fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
}
return p;
}
+// Generate an instruction referencing *n
+// to force segv on nil pointer dereference.
+void
+checkref(Node *n)
+{
+ Node m;
+
+ if(n->type->type->width < unmappedzero)
+ return;
+
+ regalloc(&m, types[TUINTPTR], n);
+ cgen(n, &m);
+ m.xoffset = 0;
+ m.op = OINDREG;
+ m.type = types[TUINT8];
+ gins(ATESTB, nodintconst(0), &m);
+ regfree(&m);
+}
+
static void
checkoffset(Addr *a, int canemitcode)
{
@@ -1079,14 +1098,22 @@ checkoffset(Addr *a, int canemitcode)
void
naddr(Node *n, Addr *a, int canemitcode)
{
+ Prog *p;
+
a->scale = 0;
a->index = D_NONE;
a->type = D_NONE;
a->gotype = S;
a->node = N;
+ a->width = 0;
if(n == N)
return;
+ if(n->type != T && n->type->etype != TIDEAL) {
+ dowidth(n->type);
+ a->width = n->type->width;
+ }
+
switch(n->op) {
default:
fatal("naddr: bad %O %D", n->op, a);
@@ -1134,15 +1161,27 @@ naddr(Node *n, Addr *a, int canemitcode)
a->type = D_PARAM;
a->node = n->left->orig;
break;
+
+ case OCLOSUREVAR:
+ if(!canemitcode)
+ fatal("naddr OCLOSUREVAR cannot emit code");
+ p = gins(AMOVQ, N, N);
+ p->from.type = D_DX+D_INDIR;
+ p->from.offset = n->xoffset;
+ p->to.type = D_BX;
+ a->type = D_BX;
+ a->sym = S;
+ break;
+
+ case OCFUNC:
+ naddr(n->left, a, canemitcode);
+ a->sym = n->left->sym;
+ break;
case ONAME:
a->etype = 0;
- a->width = 0;
- if(n->type != T) {
+ if(n->type != T)
a->etype = simtype[n->type->etype];
- a->width = n->type->width;
- a->gotype = ngotype(n);
- }
a->offset = n->xoffset;
a->sym = n->sym;
a->node = n->orig;
@@ -1173,6 +1212,8 @@ naddr(Node *n, Addr *a, int canemitcode)
case PFUNC:
a->index = D_EXTERN;
a->type = D_ADDR;
+ a->width = widthptr;
+ a->sym = funcsym(a->sym);
break;
}
break;
@@ -1184,7 +1225,7 @@ naddr(Node *n, Addr *a, int canemitcode)
break;
case CTFLT:
a->type = D_FCONST;
- a->dval = mpgetflt(n->val.u.fval);
+ a->u.dval = mpgetflt(n->val.u.fval);
break;
case CTINT:
case CTRUNE:
@@ -1210,6 +1251,7 @@ naddr(Node *n, Addr *a, int canemitcode)
case OADDR:
naddr(n->left, a, canemitcode);
+ a->width = widthptr;
if(a->type >= D_INDIR) {
a->type -= D_INDIR;
break;
@@ -1239,9 +1281,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 = TUINT32;
+ a->etype = simtype[TUINT];
a->offset += Array_nel;
- a->width = 4;
+ a->width = widthint;
if(a->offset >= unmappedzero && a->offset-Array_nel < unmappedzero)
checkoffset(a, canemitcode);
break;
@@ -1251,9 +1293,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 = TUINT32;
+ a->etype = simtype[TUINT];
a->offset += Array_cap;
- a->width = 4;
+ a->width = widthint;
if(a->offset >= unmappedzero && a->offset-Array_cap < unmappedzero)
checkoffset(a, canemitcode);
break;
@@ -1645,6 +1687,28 @@ optoas(int op, Type *t)
a = AXORQ;
break;
+ case CASE(OLROT, TINT8):
+ case CASE(OLROT, TUINT8):
+ a = AROLB;
+ break;
+
+ case CASE(OLROT, TINT16):
+ case CASE(OLROT, TUINT16):
+ a = AROLW;
+ break;
+
+ case CASE(OLROT, TINT32):
+ case CASE(OLROT, TUINT32):
+ case CASE(OLROT, TPTR32):
+ a = AROLL;
+ break;
+
+ case CASE(OLROT, TINT64):
+ case CASE(OLROT, TUINT64):
+ case CASE(OLROT, TPTR64):
+ a = AROLQ;
+ break;
+
case CASE(OLSH, TINT8):
case CASE(OLSH, TUINT8):
a = ASHLB;
@@ -1701,23 +1765,23 @@ optoas(int op, Type *t)
a = ASARQ;
break;
- case CASE(ORRC, TINT8):
- case CASE(ORRC, TUINT8):
+ case CASE(ORROTC, TINT8):
+ case CASE(ORROTC, TUINT8):
a = ARCRB;
break;
- case CASE(ORRC, TINT16):
- case CASE(ORRC, TUINT16):
+ case CASE(ORROTC, TINT16):
+ case CASE(ORROTC, TUINT16):
a = ARCRW;
break;
- case CASE(ORRC, TINT32):
- case CASE(ORRC, TUINT32):
+ case CASE(ORROTC, TINT32):
+ case CASE(ORROTC, TUINT32):
a = ARCRL;
break;
- case CASE(ORRC, TINT64):
- case CASE(ORRC, TUINT64):
+ case CASE(ORROTC, TINT64):
+ case CASE(ORROTC, TUINT64):
a = ARCRQ;
break;
@@ -1919,6 +1983,9 @@ sudoaddable(int as, Node *n, Addr *a)
goto odot;
case OINDEX:
+ return 0;
+ // disabled: OINDEX case is now covered by agenr
+ // for a more suitable register allocation pattern.
if(n->left->type->etype == TSTRING)
return 0;
goto oindex;
@@ -2053,32 +2120,20 @@ oindex:
}
// check bounds
- if(!debug['B'] && !n->etype) {
+ if(!debug['B'] && !n->bounded) {
// check bounds
n4.op = OXXX;
- t = types[TUINT32];
+ t = types[simtype[TUINT]];
if(o & ODynam) {
if(o & OAddable) {
n2 = *l;
n2.xoffset += Array_nel;
- n2.type = types[TUINT32];
- if(is64(r->type)) {
- t = types[TUINT64];
- regalloc(&n4, t, N);
- gmove(&n2, &n4);
- n2 = n4;
- }
+ n2.type = types[simtype[TUINT]];
} else {
n2 = *reg;
n2.xoffset = Array_nel;
n2.op = OINDREG;
- n2.type = types[TUINT32];
- if(is64(r->type)) {
- t = types[TUINT64];
- regalloc(&n4, t, N);
- gmove(&n2, &n4);
- n2 = n4;
- }
+ n2.type = types[simtype[TUINT]];
}
} else {
if(is64(r->type))
@@ -2086,10 +2141,10 @@ oindex:
nodconst(&n2, types[TUINT64], l->type->bound);
}
gins(optoas(OCMP, t), reg1, &n2);
- p1 = gbranch(optoas(OLT, t), T);
+ p1 = gbranch(optoas(OLT, t), T, +1);
if(n4.op != OXXX)
regfree(&n4);
- ginscall(panicindex, 0);
+ ginscall(panicindex, -1);
patch(p1, pc);
}
@@ -2140,19 +2195,19 @@ oindex_const:
reg->op = OEMPTY;
reg1->op = OEMPTY;
- regalloc(reg, types[tptr], N);
- agen(l, reg);
-
if(o & ODynam) {
- if(!debug['B'] && !n->etype) {
+ regalloc(reg, types[tptr], N);
+ agen(l, reg);
+
+ if(!debug['B'] && !n->bounded) {
n1 = *reg;
n1.op = OINDREG;
n1.type = types[tptr];
n1.xoffset = Array_nel;
nodconst(&n2, types[TUINT64], v);
- gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
- ginscall(panicindex, 0);
+ gins(optoas(OCMP, types[simtype[TUINT]]), &n1, &n2);
+ p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1);
+ ginscall(panicindex, -1);
patch(p1, pc);
}
@@ -2162,14 +2217,24 @@ oindex_const:
n1.xoffset = Array_array;
gmove(&n1, reg);
+ n2 = *reg;
+ n2.op = OINDREG;
+ n2.xoffset = v*w;
+ a->type = D_NONE;
+ a->index = D_NONE;
+ naddr(&n2, a, 1);
+ goto yes;
}
-
- n2 = *reg;
- n2.op = OINDREG;
- n2.xoffset = v*w;
+
+ igen(l, &n1, N);
+ if(n1.op == OINDREG) {
+ *reg = n1;
+ reg->op = OREGISTER;
+ }
+ n1.xoffset += v*w;
a->type = D_NONE;
- a->index = D_NONE;
- naddr(&n2, a, 1);
+ a->index= D_NONE;
+ naddr(&n1, a, 1);
goto yes;
oindex_const_sudo:
@@ -2180,13 +2245,13 @@ oindex_const_sudo:
}
// slice indexed by a constant
- if(!debug['B'] && !n->etype) {
+ if(!debug['B'] && !n->bounded) {
a->offset += Array_nel;
nodconst(&n2, types[TUINT64], v);
- p1 = gins(optoas(OCMP, types[TUINT32]), N, &n2);
+ p1 = gins(optoas(OCMP, types[simtype[TUINT]]), N, &n2);
p1->from = *a;
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
- ginscall(panicindex, 0);
+ p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1);
+ ginscall(panicindex, -1);
patch(p1, pc);
a->offset -= Array_nel;
}