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