diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2012-07-30 19:11:16 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2012-07-30 19:11:16 +0200 |
commit | 4f33c88a51587681b7be1ae57cfbc43b627c6bc4 (patch) | |
tree | 25560404dc80007e5dc268811242c9071f6a1017 /sys/src/cmd/6c/div.c | |
parent | fcc5e75d07e5bc6cb3ddac6d9a437e7ec62d0d95 (diff) |
import updated compilers from sources
Diffstat (limited to 'sys/src/cmd/6c/div.c')
-rw-r--r-- | sys/src/cmd/6c/div.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/sys/src/cmd/6c/div.c b/sys/src/cmd/6c/div.c new file mode 100644 index 000000000..cb5886789 --- /dev/null +++ b/sys/src/cmd/6c/div.c @@ -0,0 +1,206 @@ +#include "gc.h" + +/* + * Based on: Granlund, T.; Montgomery, P.L. + * "Division by Invariant Integers using Multiplication". + * SIGPLAN Notices, Vol. 29, June 1994, page 61. + */ + +#define TN(n) ((uvlong)1 << (n)) +#define T31 TN(31) +#define T32 TN(32) + +int +multiplier(ulong d, int p, uvlong *mp) +{ + int l; + uvlong mlo, mhi, tlo, thi; + + l = topbit(d - 1) + 1; + mlo = (((TN(l) - d) << 32) / d) + T32; + if(l + p == 64) + mhi = (((TN(l) + 1 - d) << 32) / d) + T32; + else + mhi = (TN(32 + l) + TN(32 + l - p)) / d; + /*assert(mlo < mhi);*/ + while(l > 0) { + tlo = mlo >> 1; + thi = mhi >> 1; + if(tlo == thi) + break; + mlo = tlo; + mhi = thi; + l--; + } + *mp = mhi; + return l; +} + +int +sdiv(ulong d, ulong *mp, int *sp) +{ + int s; + uvlong m; + + s = multiplier(d, 32 - 1, &m); + *mp = m; + *sp = s; + if(m >= T31) + return 1; + else + return 0; +} + +int +udiv(ulong d, ulong *mp, int *sp, int *pp) +{ + int p, s; + uvlong m; + + s = multiplier(d, 32, &m); + p = 0; + if(m >= T32) { + while((d & 1) == 0) { + d >>= 1; + p++; + } + s = multiplier(d, 32 - p, &m); + } + *mp = m; + *pp = p; + if(m >= T32) { + /*assert(p == 0);*/ + *sp = s - 1; + return 1; + } + else { + *sp = s; + return 0; + } +} + +void +sdivgen(Node *l, Node *r, Node *ax, Node *dx) +{ + int a, s; + ulong m; + vlong c; + + c = r->vconst; + if(c < 0) + c = -c; + a = sdiv(c, &m, &s); +//print("a=%d i=%ld s=%d m=%lux\n", a, (long)r->vconst, s, m); + gins(AMOVL, nodconst(m), ax); + gins(AIMULL, l, Z); + gins(AMOVL, l, ax); + if(a) + gins(AADDL, ax, dx); + gins(ASHRL, nodconst(31), ax); + gins(ASARL, nodconst(s), dx); + gins(AADDL, ax, dx); + if(r->vconst < 0) + gins(ANEGL, Z, dx); +} + +void +udivgen(Node *l, Node *r, Node *ax, Node *dx) +{ + int a, s, t; + ulong m; + Node nod; + + a = udiv(r->vconst, &m, &s, &t); +//print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (long)r->vconst, t, s, m); + if(t != 0) { + gins(AMOVL, l, ax); + gins(ASHRL, nodconst(t), ax); + gins(AMOVL, nodconst(m), dx); + gins(AMULL, dx, Z); + } + else if(a) { + if(l->op != OREGISTER) { + regalloc(&nod, l, Z); + gins(AMOVL, l, &nod); + l = &nod; + } + gins(AMOVL, nodconst(m), ax); + gins(AMULL, l, Z); + gins(AADDL, l, dx); + gins(ARCRL, nodconst(1), dx); + if(l == &nod) + regfree(l); + } + else { + gins(AMOVL, nodconst(m), ax); + gins(AMULL, l, Z); + } + if(s != 0) + gins(ASHRL, nodconst(s), dx); +} + +void +sext(Node *d, Node *s, Node *l) +{ + if(s->reg == D_AX && !nodreg(d, Z, D_DX)) { + reg[D_DX]++; + gins(ACDQ, Z, Z); + } + else { + regalloc(d, l, Z); + gins(AMOVL, s, d); + gins(ASARL, nodconst(31), d); + } +} + +void +sdiv2(long c, int v, Node *l, Node *n) +{ + Node nod; + + if(v > 0) { + if(v > 1) { + sext(&nod, n, l); + gins(AANDL, nodconst((1 << v) - 1), &nod); + gins(AADDL, &nod, n); + regfree(&nod); + } + else { + gins(ACMPL, n, nodconst(0x80000000)); + gins(ASBBL, nodconst(-1), n); + } + gins(ASARL, nodconst(v), n); + } + if(c < 0) + gins(ANEGL, Z, n); +} + +void +smod2(long c, int v, Node *l, Node *n) +{ + Node nod; + + if(c == 1) { + zeroregm(n); + return; + } + + sext(&nod, n, l); + if(v == 0) { + zeroregm(n); + gins(AXORL, &nod, n); + gins(ASUBL, &nod, n); + } + else if(v > 1) { + gins(AANDL, nodconst((1 << v) - 1), &nod); + gins(AADDL, &nod, n); + gins(AANDL, nodconst((1 << v) - 1), n); + gins(ASUBL, &nod, n); + } + else { + gins(AANDL, nodconst(1), n); + gins(AXORL, &nod, n); + gins(ASUBL, &nod, n); + } + regfree(&nod); +} |