case OGE:
case OGT:
case ONOT:
- p1 = gbranch(AB, T);
+ p1 = gbranch(AB, T, 0);
p2 = pc;
gmove(nodbool(1), res);
- p3 = gbranch(AB, T);
+ p3 = gbranch(AB, T, 0);
patch(p1, pc);
- bgen(n, 1, p2);
+ bgen(n, 1, 0, p2);
gmove(nodbool(0), res);
patch(p3, pc);
goto ret;
gmove(&n2, &n3);
gcmp(optoas(OCMP, types[tptr]), &n1, &n3);
regfree(&n3);
- p1 = gbranch(optoas(OEQ, types[tptr]), T);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
n2 = n1;
n2.op = OINDREG;
gmove(&n2, &n3);
gcmp(optoas(OCMP, types[tptr]), &n1, &n3);
regfree(&n3);
- p1 = gbranch(optoas(OEQ, types[tptr]), T);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
n2 = n1;
n2.op = OINDREG;
regfree(&n2);
regfree(&n1);
splitclean();
- return gbranch(ABNE, T);
+ return gbranch(ABNE, T, -1);
}
/*
gcmp(optoas(OCMP, types[TUINT32]), &n4, &n5);
regfree(&n4);
regfree(&n5);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
+ p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
ginscall(panicindex, 0);
patch(p1, pc);
}
}
gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4);
regfree(&n4);
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
if(p2)
patch(p2, pc);
ginscall(panicindex, 0);
}
void
-gencmp0(Node *n, Type *t, int o, Prog *to)
+gencmp0(Node *n, Type *t, int o, int likely, Prog *to)
{
Node n1, n2, n3;
int a;
} else
gins(ATST, &n1, N);
a = optoas(o, t);
- patch(gbranch(a, t), to);
+ patch(gbranch(a, t, likely), to);
regfree(&n1);
}
* if(n == true) goto to;
*/
void
-bgen(Node *n, int true, Prog *to)
+bgen(Node *n, int true, int likely, Prog *to)
{
int et, a;
Node *nl, *nr, *r;
a = ONE;
if(!true)
a = OEQ;
- gencmp0(n, n->type, a, to);
+ gencmp0(n, n->type, a, likely, to);
goto ret;
case OLITERAL:
// need to ask if it is bool?
if(!true == !n->val.u.bval)
- patch(gbranch(AB, T), to);
+ patch(gbranch(AB, T, 0), to);
goto ret;
case OANDAND:
goto caseor;
caseand:
- p1 = gbranch(AB, T);
- p2 = gbranch(AB, T);
+ p1 = gbranch(AB, T, 0);
+ p2 = gbranch(AB, T, 0);
patch(p1, pc);
- bgen(n->left, !true, p2);
- bgen(n->right, !true, p2);
- p1 = gbranch(AB, T);
+ bgen(n->left, !true, -likely, p2);
+ bgen(n->right, !true, -likely, p2);
+ p1 = gbranch(AB, T, 0);
patch(p1, to);
patch(p2, pc);
goto ret;
goto caseand;
caseor:
- bgen(n->left, true, to);
- bgen(n->right, true, to);
+ bgen(n->left, true, likely, to);
+ bgen(n->right, true, likely, to);
goto ret;
case OEQ:
switch(n->op) {
case ONOT:
- bgen(nl, !true, to);
+ bgen(nl, !true, likely, to);
goto ret;
case OEQ:
if(!true) {
if(isfloat[nl->type->etype]) {
// brcom is not valid on floats when NaN is involved.
- p1 = gbranch(AB, T);
- p2 = gbranch(AB, T);
+ p1 = gbranch(AB, T, 0);
+ p2 = gbranch(AB, T, 0);
patch(p1, pc);
ll = n->ninit;
n->ninit = nil;
- bgen(n, 1, p2);
+ bgen(n, 1, -likely, p2);
n->ninit = ll;
- patch(gbranch(AB, T), to);
+ patch(gbranch(AB, T, 0), to);
patch(p2, pc);
goto ret;
}
n2 = n1;
n2.op = OINDREG;
n2.xoffset = Array_array;
- gencmp0(&n2, types[tptr], a, to);
+ gencmp0(&n2, types[tptr], a, likely, to);
regfree(&n1);
break;
nodconst(&tmp, types[tptr], 0);
gmove(&tmp, &n3);
gcmp(optoas(OCMP, types[tptr]), &n4, &n3);
- patch(gbranch(a, types[tptr]), to);
+ patch(gbranch(a, types[tptr], likely), to);
regfree(&n4);
regfree(&n3);
regfree(&n1);
n2 = n1;
n2.op = OINDREG;
n2.xoffset = 0;
- gencmp0(&n2, types[tptr], a, to);
+ gencmp0(&n2, types[tptr], a, likely, to);
regfree(&n1);
break;
nodconst(&tmp, types[tptr], 0);
gmove(&tmp, &n3);
gcmp(optoas(OCMP, types[tptr]), &n4, &n3);
- patch(gbranch(a, types[tptr]), to);
+ patch(gbranch(a, types[tptr], likely), to);
regfree(&n1);
regfree(&n3);
regfree(&n4);
}
if(iscomplex[nl->type->etype]) {
- complexbool(a, nl, nr, true, to);
+ complexbool(a, nl, nr, true, likely, to);
break;
}
cgen(nr, &n2);
nr = &n2;
}
- cmp64(nl, nr, a, to);
+ cmp64(nl, nr, a, likely, to);
break;
}
if(nr->op == OLITERAL) {
if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) == 0) {
- gencmp0(nl, nl->type, a, to);
+ gencmp0(nl, nl->type, a, likely, to);
break;
}
if(nr->val.ctype == CTNIL) {
- gencmp0(nl, nl->type, a, to);
+ gencmp0(nl, nl->type, a, likely, to);
break;
}
}
cgen(&tmp, &n1);
gcmp(optoas(OCMP, nr->type), &n1, &n2);
- patch(gbranch(a, nr->type), to);
+ patch(gbranch(a, nr->type, likely), to);
regfree(&n1);
regfree(&n2);
gcmp(optoas(OCMP, nr->type), &n1, &n2);
if(isfloat[nl->type->etype]) {
- p1 = gbranch(ABVS, nr->type);
- patch(gbranch(a, nr->type), to);
- if(n->op == ONE)
+ if(n->op == ONE) {
+ p1 = gbranch(ABVS, nr->type, likely);
+ patch(gbranch(a, nr->type, likely), to);
patch(p1, to);
- else
+ } else {
+ p1 = gbranch(ABVS, nr->type, -likely);
+ patch(gbranch(a, nr->type, likely), to);
patch(p1, pc);
+ }
} else {
- patch(gbranch(a, nr->type), to);
+ patch(gbranch(a, nr->type, likely), to);
}
regfree(&n1);
regfree(&n2);
p = gins(ACMP, &src, N);
raddr(&nend, p);
- patch(gbranch(ABNE, T), ploop);
+ patch(gbranch(ABNE, T, 0), ploop);
regfree(&nend);
} else {
while(c-- > 0) {
split64(r, &cl, &ch);
gmove(&ch, &s);
gins(ATST, &s, N);
- p6 = gbranch(ABNE, T);
+ p6 = gbranch(ABNE, T, 0);
gmove(&cl, &s);
splitclean();
} else {
p1->scond = C_SCOND_EQ;
p1 = gins(AMOVW, &bh, &ah);
p1->scond = C_SCOND_EQ;
- p2 = gbranch(ABEQ, T);
+ p2 = gbranch(ABEQ, T, 0);
// shift is < 32
nodconst(&n1, types[TUINT32], 32);
p1->scond = C_SCOND_LO;
// BLO end
- p3 = gbranch(ABLO, T);
+ p3 = gbranch(ABLO, T, 0);
// shift == 32
p1 = gins(AEOR, &al, &al);
p1->scond = C_SCOND_EQ;
p1 = gins(AMOVW, &bl, &ah);
p1->scond = C_SCOND_EQ;
- p4 = gbranch(ABEQ, T);
+ p4 = gbranch(ABEQ, T, 0);
// shift is < 64
nodconst(&n1, types[TUINT32], 64);
p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &ah);
p1->scond = C_SCOND_LO;
- p5 = gbranch(ABLO, T);
+ p5 = gbranch(ABLO, T, 0);
// shift >= 64
if (p6 != P) patch(p6, pc);
else
p1 = gins(AEOR, &ah, &ah);
p1->scond = C_SCOND_NE;
- p6 = gbranch(ABNE, T);
+ p6 = gbranch(ABNE, T, 0);
gmove(&cl, &s);
splitclean();
} else {
p1->scond = C_SCOND_EQ;
p1 = gins(AMOVW, &bh, &ah);
p1->scond = C_SCOND_EQ;
- p2 = gbranch(ABEQ, T);
+ p2 = gbranch(ABEQ, T, 0);
// check if shift is < 32
nodconst(&n1, types[TUINT32], 32);
p1->scond = C_SCOND_LO;
// BLO end
- p3 = gbranch(ABLO, T);
+ p3 = gbranch(ABLO, T, 0);
// shift == 32
p1 = gins(AMOVW, &bh, &al);
gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
else
gins(AEOR, &ah, &ah);
- p4 = gbranch(ABEQ, T);
+ p4 = gbranch(ABEQ, T, 0);
// check if shift is < 64
nodconst(&n1, types[TUINT32], 64);
}
// BLO end
- p5 = gbranch(ABLO, T);
+ p5 = gbranch(ABLO, T, 0);
// s >= 64
if(p6 != P)
* nl is memory; nr is constant or memory.
*/
void
-cmp64(Node *nl, Node *nr, int op, Prog *to)
+cmp64(Node *nl, Node *nr, int op, int likely, Prog *to)
{
Node lo1, hi1, lo2, hi2, r1, r2;
Prog *br;
// cmp lo
// beq to
// L:
- br = gbranch(ABNE, T);
+ br = gbranch(ABNE, T, -likely);
break;
case ONE:
// cmp hi
// bne to
// cmp lo
// bne to
- patch(gbranch(ABNE, T), to);
+ patch(gbranch(ABNE, T, likely), to);
break;
case OGE:
case OGT:
// cmp lo
// bge to (or bgt to)
// L:
- patch(gbranch(optoas(OGT, t), T), to);
- br = gbranch(optoas(OLT, t), T);
+ patch(gbranch(optoas(OGT, t), T, likely), to);
+ br = gbranch(optoas(OLT, t), T, -likely);
break;
case OLE:
case OLT:
// cmp lo
// ble to (or jlt to)
// L:
- patch(gbranch(optoas(OLT, t), T), to);
- br = gbranch(optoas(OGT, t), T);
+ patch(gbranch(optoas(OLT, t), T, likely), to);
+ br = gbranch(optoas(OGT, t), T, -likely);
break;
}
regfree(&r2);
// jump again
- patch(gbranch(optoas(op, t), T), to);
+ patch(gbranch(optoas(op, t), T, likely), to);
// point first branch down here if appropriate
if(br != P)
void igen(Node*, Node*, Node*);
void agenr(Node *n, Node *a, Node *res);
vlong fieldoffset(Type*, Node*);
-void bgen(Node*, int, Prog*);
void sgen(Node*, Node*, int64);
void gmove(Node*, Node*);
Prog* gins(int, Node*, Node*);
/*
* cgen64.c
*/
-void cmp64(Node*, Node*, int, Prog*);
+void cmp64(Node*, Node*, int, int, Prog*);
void cgen64(Node*, Node*);
/*
*/
void clearp(Prog*);
void proglist(void);
-Prog* gbranch(int, Type*);
+Prog* gbranch(int, Type*, int);
Prog* prog(int);
void gaddoffset(Node*);
void gconv(int, int);
nodconst(&con, types[TINT32], 0);
p = gins(ACMP, &con, N);
p->reg = 0;
- patch(gbranch(ABNE, T), retpc);
+ patch(gbranch(ABNE, T, -1), retpc);
}
break;
}
// test for shift being 0
gins(ATST, &n1, N);
- p3 = gbranch(ABEQ, T);
+ p3 = gbranch(ABEQ, T, -1);
// test and fix up large shifts
// TODO: if(!bounded), don't emit some of this.
p = gins(ACMP, &dst, N);
raddr(&end, p);
- patch(gbranch(ABNE, T), pl);
+ patch(gbranch(ABNE, T, 0), pl);
regfree(&end);
} else
if(nl == &n2)
regfree(&n2);
if(throwpc == nil) {
- p1 = gbranch(optoas(op, types[TUINT32]), T);
+ p1 = gbranch(optoas(op, types[TUINT32]), T, +1);
throwpc = pc;
ginscall(panicslice, 0);
patch(p1, pc);
} else {
op = brcom(op);
- p1 = gbranch(optoas(op, types[TUINT32]), T);
+ p1 = gbranch(optoas(op, types[TUINT32]), T, -1);
patch(p1, throwpc);
}
}
/*
* 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;
USED(t);
+ USED(likely); // TODO: record this for linker
p = prog(as);
p->to.type = D_BRANCH;
p3 = p;
p = gins(ACMP, &dst, N);
raddr(&end, p);
- patch(gbranch(ABNE, T), p3);
+ patch(gbranch(ABNE, T, 0), p3);
// continue with original code.
gins(ANOP, N, N)->link = p2;
{
Prog *p;
- p = gbranch(AB, T);
+ p = gbranch(AB, T, 0);
if(to != P)
patch(p, to);
return p;
cgen(&n2, &n3);
gcmp(optoas(OCMP, types[TUINT32]), reg1, &n3);
regfree(&n3);
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
if(p2)
patch(p2, pc);
ginscall(panicindex, 0);
gcmp(optoas(OCMP, types[TUINT32]), &n4, &n3);
regfree(&n4);
regfree(&n3);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
+ p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
ginscall(panicindex, 0);
patch(p1, pc);
}
case OGE:
case OGT:
case ONOT:
- p1 = gbranch(AJMP, T);
+ p1 = gbranch(AJMP, T, 0);
p2 = pc;
gmove(nodbool(1), res);
- p3 = gbranch(AJMP, T);
+ p3 = gbranch(AJMP, T, 0);
patch(p1, pc);
- bgen(n, 1, p2);
+ bgen(n, 1, 0, p2);
gmove(nodbool(0), res);
patch(p3, pc);
goto ret;
nodconst(&n2, types[tptr], 0);
gins(optoas(OCMP, types[tptr]), &n1, &n2);
- p1 = gbranch(optoas(OEQ, types[tptr]), T);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T, 0);
n2 = n1;
n2.op = OINDREG;
nodconst(&n2, types[tptr], 0);
gins(optoas(OCMP, types[tptr]), &n1, &n2);
- p1 = gbranch(optoas(OEQ, types[tptr]), T);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T, 0);
n2 = n1;
n2.op = OINDREG;
n1.xoffset = Array_nel;
nodconst(&n2, types[TUINT32], v);
gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
- expecttaken(p1, 1);
- ginscall(panicindex, 0);
+ p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
+ ginscall(panicindex, -1);
patch(p1, pc);
}
nodconst(&n1, t, nl->type->bound);
}
gins(optoas(OCMP, t), &n2, &n1);
- p1 = gbranch(optoas(OLT, t), T);
- expecttaken(p1, 1);
+ p1 = gbranch(optoas(OLT, t), T, +1);
if(n5.op != OXXX)
regfree(&n5);
- ginscall(panicindex, 0);
+ ginscall(panicindex, -1);
patch(p1, pc);
}
* if(n == true) goto to;
*/
void
-bgen(Node *n, int true, Prog *to)
+bgen(Node *n, int true, int likely, Prog *to)
{
int et, a;
Node *nl, *nr, *l, *r;
a = AJNE;
if(!true)
a = AJEQ;
- patch(gbranch(a, n->type), to);
+ patch(gbranch(a, n->type, likely), to);
regfree(&n1);
goto ret;
case OLITERAL:
// need to ask if it is bool?
if(!true == !n->val.u.bval)
- patch(gbranch(AJMP, T), to);
+ patch(gbranch(AJMP, T, likely), to);
goto ret;
case ONAME:
a = AJNE;
if(!true)
a = AJEQ;
- patch(gbranch(a, n->type), to);
+ patch(gbranch(a, n->type, likely), to);
goto ret;
case OANDAND:
goto caseor;
caseand:
- p1 = gbranch(AJMP, T);
- p2 = gbranch(AJMP, T);
+ p1 = gbranch(AJMP, T, 0);
+ p2 = gbranch(AJMP, T, 0);
patch(p1, pc);
- bgen(n->left, !true, p2);
- bgen(n->right, !true, p2);
- p1 = gbranch(AJMP, T);
+ bgen(n->left, !true, -likely, p2);
+ bgen(n->right, !true, -likely, p2);
+ p1 = gbranch(AJMP, T, 0);
patch(p1, to);
patch(p2, pc);
goto ret;
goto caseand;
caseor:
- bgen(n->left, true, to);
- bgen(n->right, true, to);
+ bgen(n->left, true, likely, to);
+ bgen(n->right, true, likely, to);
goto ret;
case OEQ:
switch(n->op) {
case ONOT:
- bgen(nl, !true, to);
+ bgen(nl, !true, likely, to);
goto ret;
case OEQ:
if(!true) {
if(isfloat[nr->type->etype]) {
// brcom is not valid on floats when NaN is involved.
- p1 = gbranch(AJMP, T);
- p2 = gbranch(AJMP, T);
+ p1 = gbranch(AJMP, T, 0);
+ p2 = gbranch(AJMP, T, 0);
patch(p1, pc);
ll = n->ninit; // avoid re-genning ninit
n->ninit = nil;
- bgen(n, 1, p2);
+ bgen(n, 1, -likely, p2);
n->ninit = ll;
- patch(gbranch(AJMP, T), to);
+ patch(gbranch(AJMP, T, 0), to);
patch(p2, pc);
goto ret;
}
n2.type = types[tptr];
nodconst(&tmp, types[tptr], 0);
gins(optoas(OCMP, types[tptr]), &n2, &tmp);
- patch(gbranch(a, types[tptr]), to);
+ patch(gbranch(a, types[tptr], likely), to);
regfree(&n1);
break;
}
n2.xoffset = 0;
nodconst(&tmp, types[tptr], 0);
gins(optoas(OCMP, types[tptr]), &n2, &tmp);
- patch(gbranch(a, types[tptr]), to);
+ patch(gbranch(a, types[tptr], likely), to);
regfree(&n1);
break;
}
if(iscomplex[nl->type->etype]) {
- complexbool(a, nl, nr, true, to);
+ complexbool(a, nl, nr, true, likely, to);
break;
}
if(smallintconst(nr)) {
gins(optoas(OCMP, nr->type), &n1, nr);
- patch(gbranch(optoas(a, nr->type), nr->type), to);
+ patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
regfree(&n1);
break;
}
if(isfloat[nr->type->etype] && (n->op == OEQ || n->op == ONE)) {
if(n->op == OEQ) {
// neither NE nor P
- p1 = gbranch(AJNE, T);
- p2 = gbranch(AJPS, T);
- patch(gbranch(AJMP, T), to);
+ p1 = gbranch(AJNE, T, -likely);
+ p2 = gbranch(AJPS, T, -likely);
+ patch(gbranch(AJMP, T, 0), to);
patch(p1, pc);
patch(p2, pc);
} else {
// either NE or P
- patch(gbranch(AJNE, T), to);
- patch(gbranch(AJPS, T), to);
+ patch(gbranch(AJNE, T, likely), to);
+ patch(gbranch(AJPS, T, likely), to);
}
} else
- patch(gbranch(optoas(a, nr->type), nr->type), to);
+ patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
regfree(&n1);
regfree(&n2);
break;
void agen(Node*, Node*);
void igen(Node*, Node*, Node*);
vlong fieldoffset(Type*, Node*);
-void bgen(Node*, int, Prog*);
void sgen(Node*, Node*, int64);
void gmove(Node*, Node*);
Prog* gins(int, Node*, Node*);
*/
void clearp(Prog*);
void proglist(void);
-Prog* gbranch(int, Type*);
-void expecttaken(Prog*, int);
+Prog* gbranch(int, Type*, int);
Prog* prog(int);
void gaddoffset(Node*);
void gconv(int, int);
int complexop(Node*, Node*);
void complexmove(Node*, Node*);
void complexgen(Node*, Node*);
-void complexbool(int, Node*, Node*, int, Prog*);
/*
* gobj.c
break;
case 0: // normal call
+ case -1: // normal call but no return
p = gins(ACALL, N, f);
afunclit(&p->to);
+ if(proc == -1)
+ gins(AUNDEF, N, N);
break;
case 1: // call in new proc (go)
if(proc == 2) {
nodreg(®, types[TINT64], D_AX);
gins(ATESTQ, ®, ®);
- patch(gbranch(AJNE, T), retpc);
+ patch(gbranch(AJNE, T, -1), retpc);
}
break;
}
if(check) {
nodconst(&n4, t, -1);
gins(optoas(OCMP, t), &n3, &n4);
- p1 = gbranch(optoas(ONE, t), T);
- expecttaken(p1, 1);
+ p1 = gbranch(optoas(ONE, t), T, +1);
nodconst(&n4, t, -1LL<<(t->width*8-1));
if(t->width == 8) {
n5 = n4;
gins(AMOVQ, &n5, &n4);
}
gins(optoas(OCMP, t), &ax, &n4);
- p2 = gbranch(optoas(ONE, t), T);
- expecttaken(p2, 1);
+ p2 = gbranch(optoas(ONE, t), T, +1);
if(op == ODIV)
gmove(&n4, res);
if(t->width == 8)
nodconst(&n4, t, 0);
gmove(&n4, res);
}
- p3 = gbranch(AJMP, T);
+ p3 = gbranch(AJMP, T, 0);
patch(p1, pc);
patch(p2, pc);
}
if(!bounded) {
nodconst(&n3, tcount, nl->type->width*8);
gins(optoas(OCMP, tcount), &n1, &n3);
- p1 = gbranch(optoas(OLT, tcount), T);
- expecttaken(p1, 1);
+ p1 = gbranch(optoas(OLT, tcount), T, +1);
if(op == ORSH && issigned[nl->type->etype]) {
nodconst(&n3, types[TUINT32], nl->type->width*8-1);
gins(a, &n3, &n2);
if(n1.op != OXXX)
regfree(&n1);
if(throwpc == nil) {
- p1 = gbranch(optoas(op, t), T);
- expecttaken(p1, 1);
+ p1 = gbranch(optoas(op, t), T, +1);
throwpc = pc;
- ginscall(panicslice, 0);
+ ginscall(panicslice, -1);
patch(p1, pc);
} else {
op = brcom(op);
- p1 = gbranch(optoas(op, t), T);
- expecttaken(p1, 0);
+ p1 = gbranch(optoas(op, t), T, -1);
patch(p1, throwpc);
}
}
/*
* 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;
p = prog(as);
p->to.type = D_BRANCH;
p->to.branch = P;
+ if(as != AJMP && likely != 0) {
+ p->from.type = D_CONST;
+ p->from.offset = likely > 0;
+ }
return p;
}
-/*
- * mark branch as expected taken or not.
- */
-void
-expecttaken(Prog *p, int taken)
-{
- p->from.type = D_CONST;
- p->from.offset = taken;
-}
-
/*
* patch previous branch to jump to to.
*/
{
Prog *p;
- p = gbranch(AJMP, T);
+ p = gbranch(AJMP, T, 0);
if(to != P)
patch(p, to);
return p;
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);
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);
nodconst(&n2, types[TUINT64], l->type->bound);
}
gins(optoas(OCMP, t), reg1, &n2);
- p1 = gbranch(optoas(OLT, t), T);
- expecttaken(p1, 1);
+ p1 = gbranch(optoas(OLT, t), T, +1);
if(n4.op != OXXX)
regfree(&n4);
- ginscall(panicindex, 0);
+ ginscall(panicindex, -1);
patch(p1, pc);
}
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);
+ p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
+ ginscall(panicindex, -1);
patch(p1, pc);
}
nodconst(&n2, types[TUINT64], v);
p1 = gins(optoas(OCMP, types[TUINT32]), N, &n2);
p1->from = *a;
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
- expecttaken(p1, 1);
- ginscall(panicindex, 0);
+ p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
+ ginscall(panicindex, -1);
patch(p1, pc);
a->offset -= Array_nel;
}
p->reg = alive;
if(p->as != ACALL && p->to.type == D_BRANCH && p->to.branch)
mark(p->to.branch);
- if(p->as == AJMP || p->as == ARET || (p->as == ACALL && noreturn(p)))
+ if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
break;
}
}
case OGE:
case OGT:
case ONOT:
- p1 = gbranch(AJMP, T);
+ p1 = gbranch(AJMP, T, 0);
p2 = pc;
gmove(nodbool(1), res);
- p3 = gbranch(AJMP, T);
+ p3 = gbranch(AJMP, T, 0);
patch(p1, pc);
- bgen(n, 1, p2);
+ bgen(n, 1, 0, p2);
gmove(nodbool(0), res);
patch(p3, pc);
return;
nodconst(&n2, types[tptr], 0);
gins(optoas(OCMP, types[tptr]), &n1, &n2);
- p1 = gbranch(optoas(OEQ, types[tptr]), T);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
n2 = n1;
n2.op = OINDREG;
nodconst(&n2, types[tptr], 0);
gins(optoas(OCMP, types[tptr]), &n1, &n2);
- p1 = gbranch(optoas(OEQ, types[tptr]), T);
+ p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
n2 = n1;
n2.op = OINDREG;
nodconst(&zero, types[TINT32], 0);
gins(ACMPL, &hi, &zero);
splitclean();
- return gbranch(AJNE, T);
+ return gbranch(AJNE, T, +1);
}
/*
n1.xoffset = Array_nel;
nodconst(&n2, types[TUINT32], v);
gins(optoas(OCMP, types[TUINT32]), &n1, &n2);
- p1 = gbranch(optoas(OGT, types[TUINT32]), T);
- expecttaken(p1, 1);
- ginscall(panicindex, 0);
+ p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
+ ginscall(panicindex, -1);
patch(p1, pc);
}
} else
nodconst(&n1, types[TUINT32], nl->type->bound);
gins(optoas(OCMP, types[TUINT32]), &n2, &n1);
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
- expecttaken(p1, 1);
+ p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
if(p2)
patch(p2, pc);
- ginscall(panicindex, 0);
+ ginscall(panicindex, -1);
patch(p1, pc);
}
* if(n == true) goto to;
*/
void
-bgen(Node *n, int true, Prog *to)
+bgen(Node *n, int true, int likely, Prog *to)
{
int et, a;
Node *nl, *nr, *r;
a = AJNE;
if(!true)
a = AJEQ;
- patch(gbranch(a, n->type), to);
+ patch(gbranch(a, n->type, likely), to);
regfree(&n1);
return;
case OLITERAL:
// need to ask if it is bool?
if(!true == !n->val.u.bval)
- patch(gbranch(AJMP, T), to);
+ patch(gbranch(AJMP, T, 0), to);
return;
case ONAME:
a = AJNE;
if(!true)
a = AJEQ;
- patch(gbranch(a, n->type), to);
+ patch(gbranch(a, n->type, likely), to);
return;
case OANDAND:
goto caseor;
caseand:
- p1 = gbranch(AJMP, T);
- p2 = gbranch(AJMP, T);
+ p1 = gbranch(AJMP, T, 0);
+ p2 = gbranch(AJMP, T, 0);
patch(p1, pc);
- bgen(n->left, !true, p2);
- bgen(n->right, !true, p2);
- p1 = gbranch(AJMP, T);
+ bgen(n->left, !true, -likely, p2);
+ bgen(n->right, !true, -likely, p2);
+ p1 = gbranch(AJMP, T, 0);
patch(p1, to);
patch(p2, pc);
return;
goto caseand;
caseor:
- bgen(n->left, true, to);
- bgen(n->right, true, to);
+ bgen(n->left, true, likely, to);
+ bgen(n->right, true, likely, to);
return;
case OEQ:
switch(n->op) {
case ONOT:
- bgen(nl, !true, to);
+ bgen(nl, !true, likely, to);
break;
case OEQ:
if(!true) {
if(isfloat[nl->type->etype]) {
// brcom is not valid on floats when NaN is involved.
- p1 = gbranch(AJMP, T);
- p2 = gbranch(AJMP, T);
+ p1 = gbranch(AJMP, T, 0);
+ p2 = gbranch(AJMP, T, 0);
patch(p1, pc);
ll = n->ninit; // avoid re-genning ninit
n->ninit = nil;
- bgen(n, 1, p2);
+ bgen(n, 1, -likely, p2);
n->ninit = ll;
- patch(gbranch(AJMP, T), to);
+ patch(gbranch(AJMP, T, 0), to);
patch(p2, pc);
break;
}
n2.type = types[tptr];
nodconst(&tmp, types[tptr], 0);
gins(optoas(OCMP, types[tptr]), &n2, &tmp);
- patch(gbranch(a, types[tptr]), to);
+ patch(gbranch(a, types[tptr], likely), to);
regfree(&n1);
break;
}
n2.xoffset = 0;
nodconst(&tmp, types[tptr], 0);
gins(optoas(OCMP, types[tptr]), &n2, &tmp);
- patch(gbranch(a, types[tptr]), to);
+ patch(gbranch(a, types[tptr], likely), to);
regfree(&n1);
break;
}
}
if(a == OEQ) {
// neither NE nor P
- p1 = gbranch(AJNE, T);
- p2 = gbranch(AJPS, T);
- patch(gbranch(AJMP, T), to);
+ p1 = gbranch(AJNE, T, -likely);
+ p2 = gbranch(AJPS, T, -likely);
+ patch(gbranch(AJMP, T, 0), to);
patch(p1, pc);
patch(p2, pc);
} else if(a == ONE) {
// either NE or P
- patch(gbranch(AJNE, T), to);
- patch(gbranch(AJPS, T), to);
+ patch(gbranch(AJNE, T, likely), to);
+ patch(gbranch(AJPS, T, likely), to);
} else
- patch(gbranch(optoas(a, nr->type), T), to);
+ patch(gbranch(optoas(a, nr->type), T, likely), to);
break;
}
if(iscomplex[nl->type->etype]) {
- complexbool(a, nl, nr, true, to);
+ complexbool(a, nl, nr, true, likely, to);
break;
}
cgen(nr, &n2);
nr = &n2;
}
- cmp64(nl, nr, a, to);
+ cmp64(nl, nr, a, likely, to);
break;
}
if(smallintconst(nr)) {
gins(optoas(OCMP, nr->type), &n1, nr);
- patch(gbranch(a, nr->type), to);
+ patch(gbranch(a, nr->type, likely), to);
break;
}
cmp:
gins(optoas(OCMP, nr->type), &n1, &n2);
- patch(gbranch(a, nr->type), to);
+ patch(gbranch(a, nr->type, likely), to);
regfree(&n2);
break;
}
// if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply.
gins(AMOVL, &dx, &fx);
gins(AORL, &ex, &fx);
- p1 = gbranch(AJNE, T);
+ p1 = gbranch(AJNE, T, 0);
gins(AMULL, &cx, N); // implicit &ax
- p2 = gbranch(AJMP, T);
+ p2 = gbranch(AJMP, T, 0);
patch(p1, pc);
// full 64x64 -> 64, from 32x32 -> 64.
p1 = P;
if(is64(r->type)) {
gins(ACMPL, &hi2, ncon(0));
- p1 = gbranch(AJNE, T);
+ p1 = gbranch(AJNE, T, +1);
gins(AMOVL, &lo2, &cx);
} else {
cx.type = types[TUINT32];
// if shift count is >=64, zero value
gins(ACMPL, &cx, ncon(64));
- p2 = gbranch(optoas(OLT, types[TUINT32]), T);
+ p2 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
if(p1 != P)
patch(p1, pc);
gins(AXORL, &dx, &dx);
// if shift count is >= 32, zero low.
gins(ACMPL, &cx, ncon(32));
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
gins(AMOVL, &ax, &dx);
gins(ASHLL, &cx, &dx); // SHLL only uses bottom 5 bits of count
gins(AXORL, &ax, &ax);
- p2 = gbranch(AJMP, T);
+ p2 = gbranch(AJMP, T, 0);
patch(p1, pc);
// general shift
p1 = P;
if(is64(r->type)) {
gins(ACMPL, &hi2, ncon(0));
- p1 = gbranch(AJNE, T);
+ p1 = gbranch(AJNE, T, +1);
gins(AMOVL, &lo2, &cx);
} else {
cx.type = types[TUINT32];
// if shift count is >=64, zero or sign-extend value
gins(ACMPL, &cx, ncon(64));
- p2 = gbranch(optoas(OLT, types[TUINT32]), T);
+ p2 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
if(p1 != P)
patch(p1, pc);
if(hi1.type->etype == TINT32) {
// if shift count is >= 32, sign-extend hi.
gins(ACMPL, &cx, ncon(32));
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
gins(AMOVL, &dx, &ax);
if(hi1.type->etype == TINT32) {
gins(ASARL, &cx, &ax); // SARL only uses bottom 5 bits of count
gins(ASHRL, &cx, &ax);
gins(AXORL, &dx, &dx);
}
- p2 = gbranch(AJMP, T);
+ p2 = gbranch(AJMP, T, 0);
patch(p1, pc);
// general shift
* nl is memory; nr is constant or memory.
*/
void
-cmp64(Node *nl, Node *nr, int op, Prog *to)
+cmp64(Node *nl, Node *nr, int op, int likely, Prog *to)
{
Node lo1, hi1, lo2, hi2, rr;
Prog *br;
// cmp lo
// jeq to
// L:
- br = gbranch(AJNE, T);
+ br = gbranch(AJNE, T, -likely);
break;
case ONE:
// cmp hi
// jne to
// cmp lo
// jne to
- patch(gbranch(AJNE, T), to);
+ patch(gbranch(AJNE, T, likely), to);
break;
case OGE:
case OGT:
// cmp lo
// jge to (or jgt to)
// L:
- patch(gbranch(optoas(OGT, t), T), to);
- br = gbranch(optoas(OLT, t), T);
+ patch(gbranch(optoas(OGT, t), T, likely), to);
+ br = gbranch(optoas(OLT, t), T, -likely);
break;
case OLE:
case OLT:
// cmp lo
// jle to (or jlt to)
// L:
- patch(gbranch(optoas(OLT, t), T), to);
- br = gbranch(optoas(OGT, t), T);
+ patch(gbranch(optoas(OLT, t), T, likely), to);
+ br = gbranch(optoas(OGT, t), T, -likely);
break;
}
}
// jump again
- patch(gbranch(optoas(op, t), T), to);
+ patch(gbranch(optoas(op, t), T, likely), to);
// point first branch down here if appropriate
if(br != P)
void agenr(Node *n, Node *a, Node *res);
void igen(Node*, Node*, Node*);
vlong fieldoffset(Type*, Node*);
-void bgen(Node*, int, Prog*);
void sgen(Node*, Node*, int64);
void gmove(Node*, Node*);
Prog* gins(int, Node*, Node*);
/*
* cgen64.c
*/
-void cmp64(Node*, Node*, int, Prog*);
+void cmp64(Node*, Node*, int, int, Prog*);
void cgen64(Node*, Node*);
/*
*/
void clearp(Prog*);
void proglist(void);
-Prog* gbranch(int, Type*);
-void expecttaken(Prog*, int);
+Prog* gbranch(int, Type*, int);
Prog* prog(int);
void gaddoffset(Node*);
void gconv(int, int);
int complexop(Node*, Node*);
void complexmove(Node*, Node*);
void complexgen(Node*, Node*);
-void complexbool(int, Node*, Node*, int, Prog*);
/*
* list.c
break;
case 0: // normal call
+ case -1: // normal call but no return
p = gins(ACALL, N, f);
afunclit(&p->to);
+ if(proc == -1)
+ gins(AUNDEF, N, N);
break;
case 1: // call in new proc (go)
if(proc == 2) {
nodreg(®, types[TINT64], D_AX);
gins(ATESTL, ®, ®);
- patch(gbranch(AJNE, T), retpc);
+ patch(gbranch(AJNE, T, -1), retpc);
}
break;
}
if(check) {
nodconst(&n4, t, -1);
gins(optoas(OCMP, t), &n1, &n4);
- p1 = gbranch(optoas(ONE, t), T);
+ p1 = gbranch(optoas(ONE, t), T, +1);
nodconst(&n4, t, -1LL<<(t->width*8-1));
gins(optoas(OCMP, t), ax, &n4);
- p2 = gbranch(optoas(ONE, t), T);
+ p2 = gbranch(optoas(ONE, t), T, +1);
if(op == ODIV)
gmove(&n4, res);
if(op == OMOD) {
nodconst(&n4, t, 0);
gmove(&n4, res);
}
- p3 = gbranch(AJMP, T);
+ p3 = gbranch(AJMP, T, 0);
patch(p1, pc);
patch(p2, pc);
}
split64(&nt, &lo, &hi);
gmove(&lo, &n1);
gins(optoas(OCMP, types[TUINT32]), &hi, ncon(0));
- p2 = gbranch(optoas(ONE, types[TUINT32]), T);
+ p2 = gbranch(optoas(ONE, types[TUINT32]), T, +1);
gins(optoas(OCMP, types[TUINT32]), &n1, ncon(w));
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
patch(p2, pc);
} else {
gins(optoas(OCMP, nr->type), &n1, ncon(w));
- p1 = gbranch(optoas(OLT, types[TUINT32]), T);
+ p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
}
if(op == ORSH && issigned[nl->type->etype]) {
gins(a, ncon(w-1), &n2);
if(n1.op != OXXX)
regfree(&n1);
if(throwpc == nil) {
- p1 = gbranch(optoas(op, t), T);
- expecttaken(p1, 1);
+ p1 = gbranch(optoas(op, t), T, +1);
throwpc = pc;
- ginscall(panicslice, 0);
+ ginscall(panicslice, -1);
patch(p1, pc);
} else {
op = brcom(op);
- p1 = gbranch(optoas(op, t), T);
- expecttaken(p1, 0);
+ p1 = gbranch(optoas(op, t), T, -1);
patch(p1, throwpc);
}
}
/*
* 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;
p = prog(as);
p->to.type = D_BRANCH;
p->to.branch = P;
+ if(likely != 0) {
+ p->from.type = D_CONST;
+ p->from.offset = likely > 0;
+ }
return p;
}
-void
-expecttaken(Prog *p, int taken)
-{
- p->from.type = D_CONST;
- p->from.offset = taken;
-}
-
/*
* patch previous branch to jump to to.
*/
{
Prog *p;
- p = gbranch(AJMP, T);
+ p = gbranch(AJMP, T, 0);
if(to != P)
patch(p, to);
return p;
fatal("gmove %T", t);
case TINT8:
gins(ACMPL, &t1, ncon(-0x80));
- p1 = gbranch(optoas(OLT, types[TINT32]), T);
+ p1 = gbranch(optoas(OLT, types[TINT32]), T, -1);
gins(ACMPL, &t1, ncon(0x7f));
- p2 = gbranch(optoas(OGT, types[TINT32]), T);
- p3 = gbranch(AJMP, T);
+ p2 = gbranch(optoas(OGT, types[TINT32]), T, -1);
+ p3 = gbranch(AJMP, T, 0);
patch(p1, pc);
patch(p2, pc);
gmove(ncon(-0x80), &t1);
break;
case TUINT8:
gins(ATESTL, ncon(0xffffff00), &t1);
- p1 = gbranch(AJEQ, T);
+ p1 = gbranch(AJEQ, T, +1);
gins(AMOVL, ncon(0), &t1);
patch(p1, pc);
gmove(&t1, t);
break;
case TUINT16:
gins(ATESTL, ncon(0xffff0000), &t1);
- p1 = gbranch(AJEQ, T);
+ p1 = gbranch(AJEQ, T, +1);
gins(AMOVL, ncon(0), &t1);
patch(p1, pc);
gmove(&t1, t);
gmove(f, &t1);
split64(&t1, &tlo, &thi);
gins(ACMPL, &thi, ncon(0));
- p1 = gbranch(AJEQ, T);
+ p1 = gbranch(AJEQ, T, +1);
gins(AMOVL, ncon(0), &tlo);
patch(p1, pc);
gmove(&tlo, t);
// if 0 > v { answer = 0 }
gmove(&zerof, &f0);
gins(AFUCOMIP, &f0, &f1);
- p1 = gbranch(optoas(OGT, types[tt]), T);
+ p1 = gbranch(optoas(OGT, types[tt]), T, 0);
// if 1<<64 <= v { answer = 0 too }
gmove(&two64f, &f0);
gins(AFUCOMIP, &f0, &f1);
- p2 = gbranch(optoas(OGT, types[tt]), T);
+ p2 = gbranch(optoas(OGT, types[tt]), T, 0);
patch(p1, pc);
gins(AFMOVVP, &f0, t); // don't care about t, but will pop the stack
split64(t, &tlo, &thi);
gins(AMOVL, ncon(0), &tlo);
gins(AMOVL, ncon(0), &thi);
splitclean();
- p1 = gbranch(AJMP, T);
+ p1 = gbranch(AJMP, T, 0);
patch(p2, pc);
// in range; algorithm is:
// actual work
gmove(&two63f, &f0);
gins(AFUCOMIP, &f0, &f1);
- p2 = gbranch(optoas(OLE, types[tt]), T);
+ p2 = gbranch(optoas(OLE, types[tt]), T, 0);
gins(AFMOVVP, &f0, t);
- p3 = gbranch(AJMP, T);
+ p3 = gbranch(AJMP, T, 0);
patch(p2, pc);
gmove(&two63f, &f0);
gins(AFSUBDP, &f0, &f1);
split64(&t1, &tlo, &thi);
gmove(f, &t1);
gins(ACMPL, &thi, ncon(0));
- p1 = gbranch(AJLT, T);
+ p1 = gbranch(AJLT, T, 0);
// native
t1.type = types[TINT64];
gmove(&t1, t);
- p2 = gbranch(AJMP, T);
+ p2 = gbranch(AJMP, T, 0);
// simulated
patch(p1, pc);
gmove(&tlo, &ax);
p->reg = alive;
if(p->as != ACALL && p->to.type == D_BRANCH && p->to.branch)
mark(p->to.branch);
- if(p->as == AJMP || p->as == ARET || (p->as == ACALL && noreturn(p)))
+ if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
break;
}
}
}
void
-complexbool(int op, Node *nl, Node *nr, int true, Prog *to)
+complexbool(int op, Node *nl, Node *nr, int true, int likely, Prog *to)
{
Node tnl, tnr;
Node n1, n2, n3, n4;
if(op == ONE)
true = !true;
- bgen(&na, true, to);
+ bgen(&na, true, likely, to);
}
void
}
gen(n->nincr); // contin: incr
patch(p1, pc); // test:
- bgen(n->ntest, 0, breakpc); // if(!test) goto break
+ bgen(n->ntest, 0, -1, breakpc); // if(!test) goto break
genlist(n->nbody); // body
gjmp(continpc);
patch(breakpc, pc); // done:
p1 = gjmp(P); // goto test
p2 = gjmp(P); // p2: goto else
patch(p1, pc); // test:
- bgen(n->ntest, 0, p2); // if(!test) goto p2
+ bgen(n->ntest, 0, 0, p2); // if(!test) goto p2
genlist(n->nbody); // then
p3 = gjmp(P); // goto done
patch(p2, pc); // else:
* cplx.c
*/
void complexadd(int op, Node *nl, Node *nr, Node *res);
-void complexbool(int op, Node *nl, Node *nr, int true, Prog *to);
+void complexbool(int op, Node *nl, Node *nr, int true, int likely, Prog *to);
void complexgen(Node *n, Node *res);
void complexminus(Node *nl, Node *res);
void complexmove(Node *f, Node *t);
int anyregalloc(void);
void betypeinit(void);
-void bgen(Node *n, int true, Prog *to);
+void bgen(Node *n, int true, int likely, Prog *to);
void cgen(Node*, Node*);
void cgen_asop(Node *n);
void cgen_call(Node *n, int proc);