xref: /plan9/sys/src/cmd/8c/div.c (revision d40255d87ccd1acd15b87823a96efd7b6296fadd)
1f7254e6cSDavid du Colombier #include "gc.h"
2f7254e6cSDavid du Colombier 
3f7254e6cSDavid du Colombier /*
4f7254e6cSDavid du Colombier  * Based on: Granlund, T.; Montgomery, P.L.
5f7254e6cSDavid du Colombier  * "Division by Invariant Integers using Multiplication".
6f7254e6cSDavid du Colombier  * SIGPLAN Notices, Vol. 29, June 1994, page 61.
7f7254e6cSDavid du Colombier  */
8f7254e6cSDavid du Colombier 
9*d40255d8SDavid du Colombier #define	TN(n)	((uvlong)1 << (n))
10f7254e6cSDavid du Colombier #define	T31	TN(31)
11f7254e6cSDavid du Colombier #define	T32	TN(32)
12f7254e6cSDavid du Colombier 
13f7254e6cSDavid du Colombier int
multiplier(ulong d,int p,uvlong * mp)14f7254e6cSDavid du Colombier multiplier(ulong d, int p, uvlong *mp)
15f7254e6cSDavid du Colombier {
16f7254e6cSDavid du Colombier 	int l;
17f7254e6cSDavid du Colombier 	uvlong mlo, mhi, tlo, thi;
18f7254e6cSDavid du Colombier 
19f7254e6cSDavid du Colombier 	l = topbit(d - 1) + 1;
20f7254e6cSDavid du Colombier 	mlo = (((TN(l) - d) << 32) / d) + T32;
21f7254e6cSDavid du Colombier 	if(l + p == 64)
22f7254e6cSDavid du Colombier 		mhi = (((TN(l) + 1 - d) << 32) / d) + T32;
23f7254e6cSDavid du Colombier 	else
24f7254e6cSDavid du Colombier 		mhi = (TN(32 + l) + TN(32 + l - p)) / d;
25f7254e6cSDavid du Colombier 	assert(mlo < mhi);
26f7254e6cSDavid du Colombier 	while(l > 0) {
27f7254e6cSDavid du Colombier 		tlo = mlo >> 1;
28f7254e6cSDavid du Colombier 		thi = mhi >> 1;
29f7254e6cSDavid du Colombier 		if(tlo == thi)
30f7254e6cSDavid du Colombier 			break;
31f7254e6cSDavid du Colombier 		mlo = tlo;
32f7254e6cSDavid du Colombier 		mhi = thi;
33f7254e6cSDavid du Colombier 		l--;
34f7254e6cSDavid du Colombier 	}
35f7254e6cSDavid du Colombier 	*mp = mhi;
36f7254e6cSDavid du Colombier 	return l;
37f7254e6cSDavid du Colombier }
38f7254e6cSDavid du Colombier 
39f7254e6cSDavid du Colombier int
sdiv(ulong d,ulong * mp,int * sp)40f7254e6cSDavid du Colombier sdiv(ulong d, ulong *mp, int *sp)
41f7254e6cSDavid du Colombier {
42f7254e6cSDavid du Colombier 	int s;
43f7254e6cSDavid du Colombier 	uvlong m;
44f7254e6cSDavid du Colombier 
45f7254e6cSDavid du Colombier 	s = multiplier(d, 32 - 1, &m);
46f7254e6cSDavid du Colombier 	*mp = m;
47f7254e6cSDavid du Colombier 	*sp = s;
48f7254e6cSDavid du Colombier 	if(m >= T31)
49f7254e6cSDavid du Colombier 		return 1;
50f7254e6cSDavid du Colombier 	else
51f7254e6cSDavid du Colombier 		return 0;
52f7254e6cSDavid du Colombier }
53f7254e6cSDavid du Colombier 
54f7254e6cSDavid du Colombier int
udiv(ulong d,ulong * mp,int * sp,int * pp)55f7254e6cSDavid du Colombier udiv(ulong d, ulong *mp, int *sp, int *pp)
56f7254e6cSDavid du Colombier {
57f7254e6cSDavid du Colombier 	int p, s;
58f7254e6cSDavid du Colombier 	uvlong m;
59f7254e6cSDavid du Colombier 
60f7254e6cSDavid du Colombier 	s = multiplier(d, 32, &m);
61f7254e6cSDavid du Colombier 	p = 0;
62f7254e6cSDavid du Colombier 	if(m >= T32) {
63f7254e6cSDavid du Colombier 		while((d & 1) == 0) {
64f7254e6cSDavid du Colombier 			d >>= 1;
65f7254e6cSDavid du Colombier 			p++;
66f7254e6cSDavid du Colombier 		}
67f7254e6cSDavid du Colombier 		s = multiplier(d, 32 - p, &m);
68f7254e6cSDavid du Colombier 	}
69f7254e6cSDavid du Colombier 	*mp = m;
70f7254e6cSDavid du Colombier 	*pp = p;
71f7254e6cSDavid du Colombier 	if(m >= T32) {
72f7254e6cSDavid du Colombier 		assert(p == 0);
73f7254e6cSDavid du Colombier 		*sp = s - 1;
74f7254e6cSDavid du Colombier 		return 1;
75f7254e6cSDavid du Colombier 	}
76f7254e6cSDavid du Colombier 	else {
77f7254e6cSDavid du Colombier 		*sp = s;
78f7254e6cSDavid du Colombier 		return 0;
79f7254e6cSDavid du Colombier 	}
80f7254e6cSDavid du Colombier }
81f7254e6cSDavid du Colombier 
82f7254e6cSDavid du Colombier void
sdivgen(Node * l,Node * r,Node * ax,Node * dx)83f7254e6cSDavid du Colombier sdivgen(Node *l, Node *r, Node *ax, Node *dx)
84f7254e6cSDavid du Colombier {
85f7254e6cSDavid du Colombier 	int a, s;
86f7254e6cSDavid du Colombier 	ulong m;
87f7254e6cSDavid du Colombier 	vlong c;
88f7254e6cSDavid du Colombier 
89f7254e6cSDavid du Colombier 	c = r->vconst;
90f7254e6cSDavid du Colombier 	if(c < 0)
91f7254e6cSDavid du Colombier 		c = -c;
92f7254e6cSDavid du Colombier 	a = sdiv(c, &m, &s);
93f7254e6cSDavid du Colombier //print("a=%d i=%ld s=%d m=%lux\n", a, (long)r->vconst, s, m);
94f7254e6cSDavid du Colombier 	gins(AMOVL, nodconst(m), ax);
95f7254e6cSDavid du Colombier 	gins(AIMULL, l, Z);
96f7254e6cSDavid du Colombier 	gins(AMOVL, l, ax);
97f7254e6cSDavid du Colombier 	if(a)
98f7254e6cSDavid du Colombier 		gins(AADDL, ax, dx);
99f7254e6cSDavid du Colombier 	gins(ASHRL, nodconst(31), ax);
100f7254e6cSDavid du Colombier 	gins(ASARL, nodconst(s), dx);
101f7254e6cSDavid du Colombier 	gins(AADDL, ax, dx);
102f7254e6cSDavid du Colombier 	if(r->vconst < 0)
103f7254e6cSDavid du Colombier 		gins(ANEGL, Z, dx);
104f7254e6cSDavid du Colombier }
105f7254e6cSDavid du Colombier 
106f7254e6cSDavid du Colombier void
udivgen(Node * l,Node * r,Node * ax,Node * dx)107f7254e6cSDavid du Colombier udivgen(Node *l, Node *r, Node *ax, Node *dx)
108f7254e6cSDavid du Colombier {
109f7254e6cSDavid du Colombier 	int a, s, t;
110f7254e6cSDavid du Colombier 	ulong m;
111f7254e6cSDavid du Colombier 	Node nod;
112f7254e6cSDavid du Colombier 
113f7254e6cSDavid du Colombier 	a = udiv(r->vconst, &m, &s, &t);
114f7254e6cSDavid du Colombier //print("a=%ud i=%ld p=%d s=%d m=%lux\n", a, (long)r->vconst, t, s, m);
115f7254e6cSDavid du Colombier 	if(t != 0) {
116f7254e6cSDavid du Colombier 		gins(AMOVL, l, ax);
117f7254e6cSDavid du Colombier 		gins(ASHRL, nodconst(t), ax);
118f7254e6cSDavid du Colombier 		gins(AMOVL, nodconst(m), dx);
119f7254e6cSDavid du Colombier 		gins(AMULL, dx, Z);
120f7254e6cSDavid du Colombier 	}
121f7254e6cSDavid du Colombier 	else if(a) {
122f7254e6cSDavid du Colombier 		if(l->op != OREGISTER) {
123f7254e6cSDavid du Colombier 			regalloc(&nod, l, Z);
124f7254e6cSDavid du Colombier 			gins(AMOVL, l, &nod);
125f7254e6cSDavid du Colombier 			l = &nod;
126f7254e6cSDavid du Colombier 		}
127f7254e6cSDavid du Colombier 		gins(AMOVL, nodconst(m), ax);
128f7254e6cSDavid du Colombier 		gins(AMULL, l, Z);
129f7254e6cSDavid du Colombier 		gins(AADDL, l, dx);
130f7254e6cSDavid du Colombier 		gins(ARCRL, nodconst(1), dx);
131f7254e6cSDavid du Colombier 		if(l == &nod)
132f7254e6cSDavid du Colombier 			regfree(l);
133f7254e6cSDavid du Colombier 	}
134f7254e6cSDavid du Colombier 	else {
135f7254e6cSDavid du Colombier 		gins(AMOVL, nodconst(m), ax);
136f7254e6cSDavid du Colombier 		gins(AMULL, l, Z);
137f7254e6cSDavid du Colombier 	}
138f7254e6cSDavid du Colombier 	if(s != 0)
139f7254e6cSDavid du Colombier 		gins(ASHRL, nodconst(s), dx);
140f7254e6cSDavid du Colombier }
141f7254e6cSDavid du Colombier 
142f7254e6cSDavid du Colombier void
sext(Node * d,Node * s,Node * l)143f7254e6cSDavid du Colombier sext(Node *d, Node *s, Node *l)
144f7254e6cSDavid du Colombier {
145f7254e6cSDavid du Colombier 	if(s->reg == D_AX && !nodreg(d, Z, D_DX)) {
146f7254e6cSDavid du Colombier 		reg[D_DX]++;
147f7254e6cSDavid du Colombier 		gins(ACDQ, Z, Z);
148f7254e6cSDavid du Colombier 	}
149f7254e6cSDavid du Colombier 	else {
150f7254e6cSDavid du Colombier 		regalloc(d, l, Z);
151f7254e6cSDavid du Colombier 		gins(AMOVL, s, d);
152f7254e6cSDavid du Colombier 		gins(ASARL, nodconst(31), d);
153f7254e6cSDavid du Colombier 	}
154f7254e6cSDavid du Colombier }
155f7254e6cSDavid du Colombier 
156f7254e6cSDavid du Colombier void
sdiv2(long c,int v,Node * l,Node * n)157f7254e6cSDavid du Colombier sdiv2(long c, int v, Node *l, Node *n)
158f7254e6cSDavid du Colombier {
159f7254e6cSDavid du Colombier 	Node nod;
160f7254e6cSDavid du Colombier 
161f7254e6cSDavid du Colombier 	if(v > 0) {
162f7254e6cSDavid du Colombier 		if(v > 1) {
163f7254e6cSDavid du Colombier 			sext(&nod, n, l);
164f7254e6cSDavid du Colombier 			gins(AANDL, nodconst((1 << v) - 1), &nod);
165f7254e6cSDavid du Colombier 			gins(AADDL, &nod, n);
166f7254e6cSDavid du Colombier 			regfree(&nod);
167f7254e6cSDavid du Colombier 		}
168f7254e6cSDavid du Colombier 		else {
169f7254e6cSDavid du Colombier 			gins(ACMPL, n, nodconst(0x80000000));
170f7254e6cSDavid du Colombier 			gins(ASBBL, nodconst(-1), n);
171f7254e6cSDavid du Colombier 		}
172f7254e6cSDavid du Colombier 		gins(ASARL, nodconst(v), n);
173f7254e6cSDavid du Colombier 	}
174f7254e6cSDavid du Colombier 	if(c < 0)
175f7254e6cSDavid du Colombier 		gins(ANEGL, Z, n);
176f7254e6cSDavid du Colombier }
177f7254e6cSDavid du Colombier 
178f7254e6cSDavid du Colombier void
smod2(long c,int v,Node * l,Node * n)179f7254e6cSDavid du Colombier smod2(long c, int v, Node *l, Node *n)
180f7254e6cSDavid du Colombier {
181f7254e6cSDavid du Colombier 	Node nod;
182f7254e6cSDavid du Colombier 
183f7254e6cSDavid du Colombier 	if(c == 1) {
184530efdcaSDavid du Colombier 		zeroregm(n);
185f7254e6cSDavid du Colombier 		return;
186f7254e6cSDavid du Colombier 	}
187f7254e6cSDavid du Colombier 
188f7254e6cSDavid du Colombier 	sext(&nod, n, l);
189f7254e6cSDavid du Colombier 	if(v == 0) {
190f7254e6cSDavid du Colombier 		zeroregm(n);
191f7254e6cSDavid du Colombier 		gins(AXORL, &nod, n);
192f7254e6cSDavid du Colombier 		gins(ASUBL, &nod, n);
193f7254e6cSDavid du Colombier 	}
194f7254e6cSDavid du Colombier 	else if(v > 1) {
195f7254e6cSDavid du Colombier 		gins(AANDL, nodconst((1 << v) - 1), &nod);
196f7254e6cSDavid du Colombier 		gins(AADDL, &nod, n);
197f7254e6cSDavid du Colombier 		gins(AANDL, nodconst((1 << v) - 1), n);
198f7254e6cSDavid du Colombier 		gins(ASUBL, &nod, n);
199f7254e6cSDavid du Colombier 	}
200f7254e6cSDavid du Colombier 	else {
201f7254e6cSDavid du Colombier 		gins(AANDL, nodconst(1), n);
202f7254e6cSDavid du Colombier 		gins(AXORL, &nod, n);
203f7254e6cSDavid du Colombier 		gins(ASUBL, &nod, n);
204f7254e6cSDavid du Colombier 	}
205f7254e6cSDavid du Colombier 	regfree(&nod);
206f7254e6cSDavid du Colombier }
207