mirror of
https://github.com/golang/go
synced 2024-11-26 01:17:57 -07:00
parent
e3fd2e1ec6
commit
58ee1f5d54
@ -244,11 +244,14 @@ cgen(Node *n, Node *res)
|
|||||||
|
|
||||||
// asymmetric binary
|
// asymmetric binary
|
||||||
case OSUB:
|
case OSUB:
|
||||||
case OLSH:
|
|
||||||
case ORSH:
|
|
||||||
a = optoas(n->op, nl->type);
|
a = optoas(n->op, nl->type);
|
||||||
goto abop;
|
goto abop;
|
||||||
|
|
||||||
|
case OLSH:
|
||||||
|
case ORSH:
|
||||||
|
cgen_shift(n->op, nl, nr, res);
|
||||||
|
break;
|
||||||
|
|
||||||
case OCONV:
|
case OCONV:
|
||||||
if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
|
if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
|
||||||
cgen(nl, res);
|
cgen(nl, res);
|
||||||
|
@ -102,6 +102,7 @@ Prog* gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs);
|
|||||||
Prog * gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs);
|
Prog * gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs);
|
||||||
void naddr(Node*, Addr*, int);
|
void naddr(Node*, Addr*, int);
|
||||||
void cgen_aret(Node*, Node*);
|
void cgen_aret(Node*, Node*);
|
||||||
|
void cgen_shift(int, Node*, Node*, Node*);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* cgen64.c
|
* cgen64.c
|
||||||
|
@ -536,6 +536,95 @@ samereg(Node *a, Node *b)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* generate shift according to op, one of:
|
||||||
|
* res = nl << nr
|
||||||
|
* res = nl >> nr
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
cgen_shift(int op, Node *nl, Node *nr, Node *res)
|
||||||
|
{
|
||||||
|
Node n1, n2, n3, t;
|
||||||
|
int w;
|
||||||
|
Prog *p1, *p2, *p3;
|
||||||
|
uvlong sc;
|
||||||
|
|
||||||
|
if(nl->type->width > 4)
|
||||||
|
fatal("cgen_shift %T", nl->type);
|
||||||
|
|
||||||
|
w = nl->type->width * 8;
|
||||||
|
|
||||||
|
if(nr->op == OLITERAL) {
|
||||||
|
regalloc(&n1, nl->type, res);
|
||||||
|
cgen(nl, &n1);
|
||||||
|
sc = mpgetfix(nr->val.u.xval);
|
||||||
|
if(sc == 0) {
|
||||||
|
return;
|
||||||
|
} else if(sc >= nl->type->width*8) {
|
||||||
|
if(op == ORSH && issigned[nl->type->etype])
|
||||||
|
gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
|
||||||
|
else
|
||||||
|
gins(AEOR, &n1, &n1);
|
||||||
|
} else {
|
||||||
|
if(op == ORSH && issigned[nl->type->etype])
|
||||||
|
gshift(AMOVW, &n1, SHIFT_AR, sc, &n1);
|
||||||
|
else if(op == ORSH)
|
||||||
|
gshift(AMOVW, &n1, SHIFT_LR, sc, &n1);
|
||||||
|
else // OLSH
|
||||||
|
gshift(AMOVW, &n1, SHIFT_LL, sc, &n1);
|
||||||
|
}
|
||||||
|
gmove(&n1, res);
|
||||||
|
regfree(&n1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nl->ullman >= nr->ullman) {
|
||||||
|
regalloc(&n2, nl->type, res);
|
||||||
|
cgen(nl, &n2);
|
||||||
|
regalloc(&n1, nr->type, N);
|
||||||
|
cgen(nr, &n1);
|
||||||
|
} else {
|
||||||
|
regalloc(&n1, nr->type, N);
|
||||||
|
cgen(nr, &n1);
|
||||||
|
regalloc(&n2, nl->type, res);
|
||||||
|
cgen(nl, &n2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// test for shift being 0
|
||||||
|
p1 = gins(AMOVW, &n1, &n1);
|
||||||
|
p1->scond |= C_SBIT;
|
||||||
|
p3 = gbranch(ABEQ, T);
|
||||||
|
|
||||||
|
// test and fix up large shifts
|
||||||
|
regalloc(&n3, nr->type, N);
|
||||||
|
nodconst(&t, types[TUINT32], w);
|
||||||
|
gmove(&t, &n3);
|
||||||
|
gcmp(ACMP, &n1, &n3);
|
||||||
|
if(op == ORSH) {
|
||||||
|
if(issigned[nl->type->etype]) {
|
||||||
|
p1 = gshift(AMOVW, &n2, SHIFT_AR, w-1, &n2);
|
||||||
|
p2 = gregshift(AMOVW, &n2, SHIFT_AR, &n1, &n2);
|
||||||
|
} else {
|
||||||
|
p1 = gins(AEOR, &n2, &n2);
|
||||||
|
p2 = gregshift(AMOVW, &n2, SHIFT_LR, &n1, &n2);
|
||||||
|
}
|
||||||
|
p1->scond = C_SCOND_HS;
|
||||||
|
p2->scond = C_SCOND_LO;
|
||||||
|
} else {
|
||||||
|
p1 = gins(AEOR, &n2, &n2);
|
||||||
|
p2 = gregshift(AMOVW, &n2, SHIFT_LL, &n1, &n2);
|
||||||
|
p1->scond = C_SCOND_HS;
|
||||||
|
p2->scond = C_SCOND_LO;
|
||||||
|
}
|
||||||
|
regfree(&n3);
|
||||||
|
|
||||||
|
patch(p3, pc);
|
||||||
|
gmove(&n2, res);
|
||||||
|
|
||||||
|
regfree(&n1);
|
||||||
|
regfree(&n2);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
clearfat(Node *nl)
|
clearfat(Node *nl)
|
||||||
{
|
{
|
||||||
|
@ -923,6 +923,7 @@ raddr(Node *n, Prog *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* generate a comparison
|
/* generate a comparison
|
||||||
|
TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites.
|
||||||
*/
|
*/
|
||||||
Prog*
|
Prog*
|
||||||
gcmp(int as, Node *lhs, Node *rhs)
|
gcmp(int as, Node *lhs, Node *rhs)
|
||||||
|
@ -627,7 +627,7 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res)
|
|||||||
uvlong sc;
|
uvlong sc;
|
||||||
|
|
||||||
if(nl->type->width > 4)
|
if(nl->type->width > 4)
|
||||||
fatal("cgen_shift %T", nl->type->width);
|
fatal("cgen_shift %T", nl->type);
|
||||||
|
|
||||||
w = nl->type->width * 8;
|
w = nl->type->width * 8;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user