Commit 222a15c8 authored by Kai Backman's avatar Kai Backman

test/64bit.go passes but doesn't generate properly yet.

R=rsc
APPROVED=rsc
DELTA=235  (98 added, 38 deleted, 99 changed)
OCL=35789
CL=35813
parent 3f427bc9
......@@ -15,7 +15,7 @@ cgen64(Node *n, Node *res)
Node t1, t2, *l, *r;
Node lo1, lo2, hi1, hi2;
Node al, ah, bl, bh, cl, ch, s, n1, creg;
Prog *p1, *p2, *p3;
Prog *p1, *p2, *p3, *p4, *p5, *p6;
uint64 v;
......@@ -48,13 +48,13 @@ cgen64(Node *n, Node *res)
gins(AMOVW, &hi1, &ah);
gmove(ncon(0), &t1);
p1 = gins(ASUB, &t1, &al);
p1 = gins(ASUB, &al, &t1);
p1->scond |= C_SBIT;
gins(ASBC, &t1, &ah);
gins(AMOVW, &t1, &lo2);
gins(AMOVW, &al, &lo2);
gins(AMOVW, &ah, &hi2);
gmove(ncon(0), &t1);
gins(ASBC, &ah, &t1);
gins(AMOVW, &t1, &hi2);
regfree(&t1);
regfree(&al);
......@@ -204,85 +204,117 @@ cgen64(Node *n, Node *res)
// here and below (verify it optimizes to EOR)
gins(AEOR, &al, &al);
gins(AEOR, &ah, &ah);
goto olsh_break;
}
if(v >= 32) {
} else if(v > 32) {
gins(AEOR, &al, &al);
// MOVW bl<<(v-32), ah
gshift(AMOVW, &bl, SHIFT_LL, v-32, &ah);
goto olsh_break;
}
// general literal left shift
// MOVW bl<<v, al
gshift(AMOVW, &bl, SHIFT_LL, v, &al);
// MOVW bh<<v, ah
gshift(AMOVW, &bh, SHIFT_LL, v, &ah);
gshift(AMOVW, &bl, SHIFT_LL, (v-32), &ah);
} else if(v == 32) {
gins(AEOR, &al, &al);
gins(AMOVW, &bl, &ah);
} else if(v > 0) {
// MOVW bl<<v, al
gshift(AMOVW, &bl, SHIFT_LL, v, &al);
// OR bl>>(32-v), ah
gshift(AORR, &bl, SHIFT_LR, 32-v, &ah);
// MOVW bh<<v, ah
gshift(AMOVW, &bh, SHIFT_LL, v, &ah);
// OR bl>>(32-v), ah
gshift(AORR, &bl, SHIFT_LR, 32-v, &ah);
} else {
gins(AMOVW, &bl, &al);
gins(AMOVW, &bh, &ah);
}
goto olsh_break;
}
regalloc(&s, types[TUINT32], N);
regalloc(&creg, types[TUINT32], N);
gmove(r, &s);
if (is64(r->type)) {
// shift is >= 1<<32
split64(r, &cl, &ch);
gmove(&ch, &s);
p1 = gins(AMOVW, &s, &s);
p1->scond |= C_SBIT;
p6 = gbranch(ABNE, T);
gmove(&cl, &s);
splitclean();
} else {
gmove(r, &s);
p6 = P;
}
p1 = gins(AMOVW, &s, &s);
p1->scond |= C_SBIT;
// check if shift is < 32
// shift == 0
p1 = gins(AMOVW, &bl, &al);
p1->scond = C_SCOND_EQ;
p1 = gins(AMOVW, &bh, &ah);
p1->scond = C_SCOND_EQ;
p2 = gbranch(ABEQ, T);
// shift is < 32
nodconst(&n1, types[TUINT32], 32);
gmove(&n1, &creg);
gcmp(ACMP, &s, &creg);
// MOVW.LT bl<<s, al
// MOVW.LO bl<<s, al
p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &al);
p1->scond = C_SCOND_LT;
p1->scond = C_SCOND_LO;
// MOVW.LT bh<<s, ah
// MOVW.LO bh<<s, ah
p1 = gregshift(AMOVW, &bh, SHIFT_LL, &s, &ah);
p1->scond = C_SCOND_LT;
p1->scond = C_SCOND_LO;
// SUB.LT creg, s
p1 = gins(ASUB, &creg, &s);
p1->scond = C_SCOND_LT;
// SUB.LO s, creg
p1 = gins(ASUB, &s, &creg);
p1->scond = C_SCOND_LO;
// OR.LT bl>>creg, ah
// OR.LO bl>>creg, ah
p1 = gregshift(AORR, &bl, SHIFT_LR, &creg, &ah);
p1->scond = C_SCOND_LT;
p1->scond = C_SCOND_LO;
// BLT end
p2 = gbranch(ABLT, T);
// BLO end
p3 = gbranch(ABLO, T);
// check if shift is < 64
// 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);
// shift is < 64
nodconst(&n1, types[TUINT32], 64);
gmove(&n1, &creg);
gcmp(ACMP, &s, &creg);
// EOR.LT al, al
// EOR.LO al, al
p1 = gins(AEOR, &al, &al);
p1->scond = C_SCOND_LT;
p1->scond = C_SCOND_LO;
// MOVW.LT creg>>1, creg
// MOVW.LO creg>>1, creg
p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg);
p1->scond = C_SCOND_LT;
p1->scond = C_SCOND_LO;
// SUB.LT creg, s
p1 = gins(ASUB, &s, &creg);
p1->scond = C_SCOND_LT;
// SUB.LO creg, s
p1 = gins(ASUB, &creg, &s);
p1->scond = C_SCOND_LO;
// MOVW bl<<s, ah
p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &ah);
p1->scond = C_SCOND_LT;
p1->scond = C_SCOND_LO;
p3 = gbranch(ABLT, T);
p5 = gbranch(ABLO, T);
// shift >= 64
if (p6 != P) patch(p6, pc);
gins(AEOR, &al, &al);
gins(AEOR, &ah, &ah);
patch(p2, pc);
patch(p3, pc);
patch(p4, pc);
patch(p5, pc);
regfree(&s);
regfree(&creg);
......@@ -311,9 +343,7 @@ olsh_break:
gins(AEOR, &al, &al);
gins(AEOR, &ah, &ah);
}
goto orsh_break;
}
if(v >= 32) {
} else if(v > 32) {
if(bh.type->etype == TINT32) {
// MOVW bh->(v-32), al
gshift(AMOVW, &bh, SHIFT_AR, v-32, &al);
......@@ -325,121 +355,140 @@ olsh_break:
gshift(AMOVW, &bh, SHIFT_LR, v-32, &al);
gins(AEOR, &ah, &ah);
}
goto orsh_break;
}
// general literal right shift
// MOVW bl>>v, al
gshift(AMOVW, &bl, SHIFT_LR, v, &al);
// OR bh<<(32-v), al
gshift(AORR, &bh, SHIFT_LL, 32-v, &al);
} else if(v == 32) {
gins(AMOVW, &bh, &al);
if(bh.type->etype == TINT32) {
// MOVW bh->31, ah
gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
} else {
gins(AEOR, &ah, &ah);
}
} else if( v > 0) {
// MOVW bl>>v, al
gshift(AMOVW, &bl, SHIFT_LR, v, &al);
// OR bh<<(32-v), al
gshift(AORR, &bh, SHIFT_LL, 32-v, &al);
if(bh.type->etype == TINT32) {
// MOVW bh->v, ah
gshift(AMOVW, &bh, SHIFT_AR, v, &ah);
if(bh.type->etype == TINT32) {
// MOVW bh->v, ah
gshift(AMOVW, &bh, SHIFT_AR, v, &ah);
} else {
// MOVW bh>>v, ah
gshift(AMOVW, &bh, SHIFT_LR, v, &ah);
}
} else {
// MOVW bh>>v, ah
gshift(AMOVW, &bh, SHIFT_LR, v, &ah);
gins(AMOVW, &bl, &al);
gins(AMOVW, &bh, &ah);
}
goto orsh_break;
}
regalloc(&s, types[TUINT32], N);
regalloc(&creg, types[TUINT32], N);
gmove(r, &s);
if (is64(r->type)) {
// shift is >= 1<<32
split64(r, &cl, &ch);
gmove(&ch, &s);
p1 = gins(AMOVW, &s, &s);
p1->scond |= C_SBIT;
p6 = gbranch(ABNE, T);
gmove(&cl, &s);
splitclean();
} else {
gmove(r, &s);
p6 = P;
}
p1 = gins(AMOVW, &s, &s);
p1->scond |= C_SBIT;
// shift == 0
p1 = gins(AMOVW, &bl, &al);
p1->scond = C_SCOND_EQ;
p1 = gins(AMOVW, &bh, &ah);
p1->scond = C_SCOND_EQ;
p2 = gbranch(ABEQ, T);
// check if shift is < 32
nodconst(&n1, types[TUINT32], 32);
gmove(&n1, &creg);
gcmp(ACMP, &s, &creg);
// MOVW.LT bl>>s, al
p1 = gins(AMOVW, N, &al);
p1->from.type = D_SHIFT;
p1->from.offset = SHIFT_LR | s.val.u.reg << 8 | 1<<4 | bl.val.u.reg;
p1->scond = C_SCOND_LT;
// MOVW.LO bl>>s, al
p1 = gregshift(AMOVW, &bl, SHIFT_LR, &s, &al);
p1->scond = C_SCOND_LO;
// SUB.LT creg, s
p1 = gins(ASUB, &creg, &s);
p1->scond = C_SCOND_LT;
// SUB.LO s,creg
p1 = gins(ASUB, &s, &creg);
p1->scond = C_SCOND_LO;
// OR.LT bh<<(32-s), al, al
p1 = gins(AORR, N, &al);
p1->from.type = D_SHIFT;
p1->from.offset = SHIFT_LL | creg.val.u.reg << 8 | 1<<4 | bh.val.u.reg;
p1->reg = al.val.u.reg;
p1->scond = C_SCOND_LT;
// OR.LO bh<<(32-s), al
p1 = gregshift(AORR, &bh, SHIFT_LL, &creg, &al);
p1->scond = C_SCOND_LO;
if(bh.type->etype == TINT32) {
// MOVW bh->s, ah
p1 = gins(AMOVW, N, &ah);
p1->from.type = D_SHIFT;
p1->from.offset = SHIFT_AR | s.val.u.reg << 8 | 1<<4 | bh.val.u.reg;
p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &ah);
} else {
// MOVW bh>>s, ah
p1 = gins(AMOVW, N, &ah);
p1->from.type = D_SHIFT;
p1->from.offset = SHIFT_LR | s.val.u.reg << 8 | 1<<4 | bh.val.u.reg;
p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &ah);
}
p1->scond = C_SCOND_LT;
p1->scond = C_SCOND_LO;
// BLO end
p3 = gbranch(ABLO, T);
// BLT end
p2 = gbranch(ABLT, T);
// shift == 32
if(bh.type->etype == TINT32)
p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
else
p1 = gins(AEOR, &al, &al);
p1->scond = C_SCOND_EQ;
p1 = gins(AMOVW, &bh, &al);
p1->scond = C_SCOND_EQ;
p4 = gbranch(ABEQ, T);
// check if shift is < 64
nodconst(&n1, types[TUINT32], 64);
gmove(&n1, &creg);
gcmp(ACMP, &s, &creg);
// MOVW.LT creg>>1, creg
p1 = gins(AMOVW, N, &creg);
p1->from.type = D_SHIFT;
p1->from.offset = SHIFT_LR | 1<<7 | creg.val.u.reg;
p1->scond = C_SCOND_LT;
// MOVW.LO creg>>1, creg
p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg);
p1->scond = C_SCOND_LO;
// SUB.LT s, creg
p1 = gins(ASUB, &s, &creg);
p1->scond = C_SCOND_LT;
// SUB.LO creg, s
p1 = gins(ASUB, &creg, &s);
p1->scond = C_SCOND_LO;
if(bh.type->etype == TINT32) {
// MOVW bh->(s-32), al
p1 = gins(AMOVW, N, &al);
p1->from.type = D_SHIFT;
p1->from.offset = SHIFT_AR | s.val.u.reg <<8 | 1<<4 | bh.val.u.reg;
p1->scond = C_SCOND_LT;
p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &al);
p1->scond = C_SCOND_LO;
// MOVW bh->31, ah
p1 = gins(AMOVW, N, &ah);
p1->from.type = D_SHIFT;
p1->from.offset = SHIFT_AR | 31<<7 | bh.val.u.reg;
p1->scond = C_SCOND_LT;
p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
p1->scond = C_SCOND_LO;
} else {
// MOVW bh>>(v-32), al
p1 = gins(AMOVW, N, &al);
p1->from.type = D_SHIFT;
p1->from.offset = SHIFT_LR | s.val.u.reg<<8 | 1<<4 | bh.val.u.reg;
p1->scond = C_SCOND_LT;
p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &al);
p1->scond = C_SCOND_LO;
p1 = gins(AEOR, &ah, &ah);
p1->scond = C_SCOND_LT;
p1->scond = C_SCOND_LO;
}
// BLT end
p3 = gbranch(ABLT, T);
// BLO end
p5 = gbranch(ABLO, T);
// s >= 64
if (p6 != P) patch(p6, pc);
if(bh.type->etype == TINT32) {
// MOVW bh->31, al
p1 = gins(AMOVW, N, &al);
p1->from.type = D_SHIFT;
p1->from.offset = SHIFT_AR | 31 << 7 | bh.val.u.reg;
gshift(AMOVW, &bh, SHIFT_AR, 31, &al);
// MOVW bh->31, ah
p1 = gins(AMOVW, N, &ah);
p1->from.type = D_SHIFT;
p1->from.offset = SHIFT_AR | 31 << 7 | bh.val.u.reg;
gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
} else {
gins(AEOR, &al, &al);
gins(AEOR, &ah, &ah);
......@@ -447,6 +496,8 @@ olsh_break:
patch(p2, pc);
patch(p3, pc);
patch(p4, pc);
patch(p5, pc);
regfree(&s);
regfree(&creg);
......
......@@ -965,15 +965,18 @@ gcmp(int as, Node *lhs, Node *rhs)
}
/* generate a constant shift
* arm encodes a shift by 32 as 0, thus asking for 0 shift is illegal.
*/
Prog*
gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs)
{
Prog *p;
if (sval < 0 || sval > 31)
if (sval <= 0 || sval > 32)
fatal("bad shift value: %d", sval);
sval = sval&0x1f;
p = gins(as, N, rhs);
p->from.type = D_SHIFT;
p->from.offset = stype | sval<<7 | lhs->val.u.reg;
......
......@@ -291,9 +291,15 @@ _divv(Vlong *q, Vlong n, Vlong d)
long nneg, dneg;
if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
q->lo = (long)n.lo / (long)d.lo;
q->hi = ((long)q->lo) >> 31;
return;
if((long)n.lo == -0x80000000 && (long)d.lo == -1) {
// special case: 32-bit -0x80000000 / -1 causes wrong sign
q->lo = 0x80000000;
q->hi = 0;
return;
}
q->lo = (long)n.lo / (long)d.lo;
q->hi = ((long)q->lo) >> 31;
return;
}
nneg = n.hi >> 31;
if(nneg)
......
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