Commit 58ee1f5d authored by Kai Backman's avatar Kai Backman

shift for non-64 bit integers.

R=rsc
http://go/go-review/1015017
parent e3fd2e1e
......@@ -244,11 +244,14 @@ cgen(Node *n, Node *res)
// asymmetric binary
case OSUB:
case OLSH:
case ORSH:
a = optoas(n->op, nl->type);
goto abop;
case OLSH:
case ORSH:
cgen_shift(n->op, nl, nr, res);
break;
case OCONV:
if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
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);
void naddr(Node*, Addr*, int);
void cgen_aret(Node*, Node*);
void cgen_shift(int, Node*, Node*, Node*);
/*
* cgen64.c
......
......@@ -536,6 +536,95 @@ samereg(Node *a, Node *b)
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
clearfat(Node *nl)
{
......
......@@ -923,6 +923,7 @@ raddr(Node *n, Prog *p)
}
/* generate a comparison
TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites.
*/
Prog*
gcmp(int as, Node *lhs, Node *rhs)
......
......@@ -627,7 +627,7 @@ cgen_shift(int op, Node *nl, Node *nr, Node *res)
uvlong sc;
if(nl->type->width > 4)
fatal("cgen_shift %T", nl->type->width);
fatal("cgen_shift %T", nl->type);
w = nl->type->width * 8;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment