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