diff options
-rw-r--r-- | src/cmd/5g/cgen64.c | 283 | ||||
-rw-r--r-- | src/cmd/5g/gsubr.c | 5 | ||||
-rwxr-xr-x | src/pkg/runtime/arm/vlrt.c | 12 |
3 files changed, 180 insertions, 120 deletions
diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c index a732991db..02ffe3276 100644 --- a/src/cmd/5g/cgen64.c +++ b/src/cmd/5g/cgen64.c @@ -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); diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c index e9131b436..d22d4b468 100644 --- a/src/cmd/5g/gsubr.c +++ b/src/cmd/5g/gsubr.c @@ -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; diff --git a/src/pkg/runtime/arm/vlrt.c b/src/pkg/runtime/arm/vlrt.c index 276a91f20..8e3aa624c 100755 --- a/src/pkg/runtime/arm/vlrt.c +++ b/src/pkg/runtime/arm/vlrt.c @@ -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) |