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