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