xref: /minix3/minix/tests/test53.c (revision 3083d603ba9dea68befc9da05a714884e10ec7e8)
1433d6423SLionel Sambuc #include <assert.h>
2433d6423SLionel Sambuc #include <minix/u64.h>
3433d6423SLionel Sambuc #include <setjmp.h>
4433d6423SLionel Sambuc #include <signal.h>
5433d6423SLionel Sambuc #include <stdio.h>
6433d6423SLionel Sambuc #include <stdlib.h>
7433d6423SLionel Sambuc #include <sys/time.h>
8433d6423SLionel Sambuc #include <unistd.h>
9433d6423SLionel Sambuc 
10433d6423SLionel Sambuc #define ERR err(__LINE__)
11433d6423SLionel Sambuc int max_error = 4;
12433d6423SLionel Sambuc #include "common.h"
13433d6423SLionel Sambuc 
14433d6423SLionel Sambuc #define TIMED 0
15433d6423SLionel Sambuc 
16433d6423SLionel Sambuc 
17433d6423SLionel Sambuc static volatile int expect_SIGFPE;
18433d6423SLionel Sambuc static u64_t i, j, k;
19433d6423SLionel Sambuc static jmp_buf jmpbuf_SIGFPE, jmpbuf_main;
20433d6423SLionel Sambuc 
err(int line)21433d6423SLionel Sambuc static void err(int line)
22433d6423SLionel Sambuc {
23433d6423SLionel Sambuc 	/* print error information */
24433d6423SLionel Sambuc 	printf("error line %d; i=0x%.8lx%.8lx; j=0x%.8lx%.8lx; k=0x%.8lx%.8lx\n",
25433d6423SLionel Sambuc 		line,
26433d6423SLionel Sambuc 		ex64hi(i), ex64lo(i),
27433d6423SLionel Sambuc 		ex64hi(j), ex64lo(j),
28433d6423SLionel Sambuc 		ex64hi(k), ex64lo(k));
29433d6423SLionel Sambuc 
30433d6423SLionel Sambuc 	/* quit after too many errors */
31433d6423SLionel Sambuc 	e(7);
32433d6423SLionel Sambuc }
33433d6423SLionel Sambuc 
34433d6423SLionel Sambuc #define LENGTHOF(arr) (sizeof(arr) / sizeof(arr[0]))
35433d6423SLionel Sambuc 
getargval(int index,int * done)36433d6423SLionel Sambuc static u64_t getargval(int index, int *done)
37433d6423SLionel Sambuc {
38433d6423SLionel Sambuc 	u32_t values[] = {
39433d6423SLionel Sambuc 		/* corner cases */
40433d6423SLionel Sambuc 		0,
41433d6423SLionel Sambuc 		1,
42433d6423SLionel Sambuc 		0x7fffffff,
43433d6423SLionel Sambuc 		0x80000000,
44433d6423SLionel Sambuc 		0x80000001,
45433d6423SLionel Sambuc 		0xffffffff,
46433d6423SLionel Sambuc 		/* random values */
47433d6423SLionel Sambuc 		0xa9,
48433d6423SLionel Sambuc 		0x0d88,
49433d6423SLionel Sambuc 		0x242811,
50433d6423SLionel Sambuc 		0xeb44d1bc,
51433d6423SLionel Sambuc 		0x5b,
52433d6423SLionel Sambuc 		0xfb50,
53433d6423SLionel Sambuc 		0x569c02,
54433d6423SLionel Sambuc 		0xb23c8f7d,
55433d6423SLionel Sambuc 		0xc3,
56433d6423SLionel Sambuc 		0x2366,
57433d6423SLionel Sambuc 		0xfabb73,
58433d6423SLionel Sambuc 		0xcb4e8aef,
59433d6423SLionel Sambuc 		0xe9,
60433d6423SLionel Sambuc 		0xffdc,
61433d6423SLionel Sambuc 		0x05842d,
62433d6423SLionel Sambuc 		0x3fff902d};
63433d6423SLionel Sambuc 
64433d6423SLionel Sambuc 	assert(done);
65433d6423SLionel Sambuc 
66433d6423SLionel Sambuc 	/* values with corner case and random 32-bit components */
67433d6423SLionel Sambuc 	if (index < LENGTHOF(values) * LENGTHOF(values))
68433d6423SLionel Sambuc 		return make64(values[index / LENGTHOF(values)], values[index % LENGTHOF(values)]);
69433d6423SLionel Sambuc 
70433d6423SLionel Sambuc 	index -= LENGTHOF(values) * LENGTHOF(values);
71433d6423SLionel Sambuc 
72433d6423SLionel Sambuc 	/* small numbers */
73433d6423SLionel Sambuc 	if (index < 16) return make64(index + 2, 0);
74433d6423SLionel Sambuc 	index -= 16;
75433d6423SLionel Sambuc 
76433d6423SLionel Sambuc 	/* big numbers */
77433d6423SLionel Sambuc 	if (index < 16) return make64(-index - 2, -1);
78433d6423SLionel Sambuc 	index -= 16;
79433d6423SLionel Sambuc 
80433d6423SLionel Sambuc 	/* powers of two */
81433d6423SLionel Sambuc 	if (index < 14) return make64(1 << (index * 2 + 5), 0);
82433d6423SLionel Sambuc 	index -= 14;
83433d6423SLionel Sambuc 	if (index < 16) return make64(0, 1 << (index * 2 + 1));
84433d6423SLionel Sambuc 	index -= 16;
85433d6423SLionel Sambuc 
86433d6423SLionel Sambuc 	/* done */
87433d6423SLionel Sambuc 	*done = 1;
88433d6423SLionel Sambuc 	return make64(0, 0);
89433d6423SLionel Sambuc }
90433d6423SLionel Sambuc 
handler_SIGFPE(int signum)91433d6423SLionel Sambuc static void handler_SIGFPE(int signum)
92433d6423SLionel Sambuc {
93433d6423SLionel Sambuc 	assert(signum == SIGFPE);
94433d6423SLionel Sambuc 
95433d6423SLionel Sambuc 	/* restore the signal handler */
96433d6423SLionel Sambuc 	if (signal(SIGFPE, handler_SIGFPE) == SIG_ERR) ERR;
97433d6423SLionel Sambuc 
98433d6423SLionel Sambuc 	/* division by zero occurred, was this expected? */
99433d6423SLionel Sambuc 	if (expect_SIGFPE) {
100433d6423SLionel Sambuc 		/* expected: jump back to test */
101433d6423SLionel Sambuc 		expect_SIGFPE = 0;
102433d6423SLionel Sambuc 		longjmp(jmpbuf_SIGFPE, -1);
103433d6423SLionel Sambuc 	} else {
104433d6423SLionel Sambuc 		/* not expected: error and jump back to main */
105433d6423SLionel Sambuc 		longjmp(jmpbuf_main, -1);
106433d6423SLionel Sambuc 	}
107433d6423SLionel Sambuc 
108433d6423SLionel Sambuc 	/* not reachable */
109433d6423SLionel Sambuc 	assert(0);
110433d6423SLionel Sambuc 	exit(-1);
111433d6423SLionel Sambuc }
112433d6423SLionel Sambuc 
bsr64(u64_t i)113433d6423SLionel Sambuc static inline int bsr64(u64_t i)
114433d6423SLionel Sambuc {
115433d6423SLionel Sambuc 	int index;
116433d6423SLionel Sambuc 	u64_t mask;
117433d6423SLionel Sambuc 
118433d6423SLionel Sambuc 	for (index = 63, mask = 1ULL << 63; index >= 0; --index, mask >>= 1) {
119433d6423SLionel Sambuc 	    if (i & mask)
120433d6423SLionel Sambuc 		return index;
121433d6423SLionel Sambuc 	}
122433d6423SLionel Sambuc 
123433d6423SLionel Sambuc 	return -1;
124433d6423SLionel Sambuc }
125433d6423SLionel Sambuc 
testmul(void)126433d6423SLionel Sambuc static void testmul(void)
127433d6423SLionel Sambuc {
128433d6423SLionel Sambuc 	int kdone, kidx;
129433d6423SLionel Sambuc 	u32_t ilo = ex64lo(i), jlo = ex64lo(j);
130433d6423SLionel Sambuc 	u64_t prod = i * j;
131433d6423SLionel Sambuc 	int prodbits;
132433d6423SLionel Sambuc 
133433d6423SLionel Sambuc 	/* compute maximum index of highest-order bit */
134433d6423SLionel Sambuc 	prodbits = bsr64(i) + bsr64(j) + 1;
135433d6423SLionel Sambuc 	if (i == 0 || j == 0) prodbits = -1;
136433d6423SLionel Sambuc 	if (bsr64(prod) > prodbits) ERR;
137433d6423SLionel Sambuc 
138433d6423SLionel Sambuc 	/* compare to 32-bit multiplication if possible */
139433d6423SLionel Sambuc 	if (ex64hi(i) == 0 && ex64hi(j) == 0) {
140433d6423SLionel Sambuc 		if (prod != (u64_t)ilo * jlo) ERR;
141433d6423SLionel Sambuc 
142433d6423SLionel Sambuc 		/* if there is no overflow we can check against pure 32-bit */
143433d6423SLionel Sambuc 		if (prodbits < 32 && prod != ilo * jlo) ERR;
144433d6423SLionel Sambuc 	}
145433d6423SLionel Sambuc 
146433d6423SLionel Sambuc 	/* in 32-bit arith low-order DWORD matches regardless of overflow */
147433d6423SLionel Sambuc 	if (ex64lo(prod) != ilo * jlo) ERR;
148433d6423SLionel Sambuc 
149433d6423SLionel Sambuc 	/* multiplication by zero yields zero */
150433d6423SLionel Sambuc 	if (prodbits < 0 && prod != 0) ERR;
151433d6423SLionel Sambuc 
152433d6423SLionel Sambuc 	/* if there is no overflow, check absence of zero divisors */
153433d6423SLionel Sambuc 	if (prodbits >= 0 && prodbits < 64 && prod == 0) ERR;
154433d6423SLionel Sambuc 
155433d6423SLionel Sambuc 	/* commutativity */
156433d6423SLionel Sambuc 	if (prod != j * i) ERR;
157433d6423SLionel Sambuc 
158433d6423SLionel Sambuc 	/* loop though all argument value combinations for third argument */
159433d6423SLionel Sambuc 	for (kdone = 0, kidx = 0; k = getargval(kidx, &kdone), !kdone; kidx++) {
160433d6423SLionel Sambuc 		/* associativity */
161433d6423SLionel Sambuc 		if ((i * j) * k != i * (j * k)) ERR;
162433d6423SLionel Sambuc 
163433d6423SLionel Sambuc 		/* left and right distributivity */
164433d6423SLionel Sambuc 		if ((i + j) * k != (i * k) + (j * k)) ERR;
165433d6423SLionel Sambuc 		if (i * (j + k) != (i * j) + (i * k)) ERR;
166433d6423SLionel Sambuc 	}
167433d6423SLionel Sambuc }
168433d6423SLionel Sambuc 
do_not_optimize_away(volatile u64_t * ptr)169*3083d603SDavid van Moolenbroek static void do_not_optimize_away(volatile u64_t * ptr)
170*3083d603SDavid van Moolenbroek {
171*3083d603SDavid van Moolenbroek 
172*3083d603SDavid van Moolenbroek 	/* TODO: does this actually do the job? */
173*3083d603SDavid van Moolenbroek 	*ptr ^= 1;
174*3083d603SDavid van Moolenbroek }
175*3083d603SDavid van Moolenbroek 
testdiv0(void)176433d6423SLionel Sambuc static void testdiv0(void)
177433d6423SLionel Sambuc {
178433d6423SLionel Sambuc 	int funcidx;
179433d6423SLionel Sambuc 	u64_t res;
180433d6423SLionel Sambuc 
181433d6423SLionel Sambuc 	assert(j == 0);
182433d6423SLionel Sambuc 
183433d6423SLionel Sambuc 	/* loop through the 5 different division functions */
184433d6423SLionel Sambuc 	for (funcidx = 0; funcidx < 5; funcidx++) {
185433d6423SLionel Sambuc 		expect_SIGFPE = 1;
186433d6423SLionel Sambuc 		if (setjmp(jmpbuf_SIGFPE) == 0) {
187433d6423SLionel Sambuc 			/* divide by zero using various functions */
188433d6423SLionel Sambuc 			switch (funcidx) {
189433d6423SLionel Sambuc 				case 0: res = i / j;		ERR; break;
190433d6423SLionel Sambuc 				case 1: res = i / ex64lo(j);	ERR; break;
191433d6423SLionel Sambuc 				case 2: res = i / ex64lo(j);	ERR; break;
192433d6423SLionel Sambuc 				case 3: res = i % j;		ERR; break;
193433d6423SLionel Sambuc 				case 4: res = i % ex64lo(j);	ERR; break;
194433d6423SLionel Sambuc 				default: assert(0);		ERR; break;
195433d6423SLionel Sambuc 			}
196433d6423SLionel Sambuc 
197*3083d603SDavid van Moolenbroek 			do_not_optimize_away((volatile u64_t *)&res);
198*3083d603SDavid van Moolenbroek 
199433d6423SLionel Sambuc 			/* if we reach this point there was no signal and an
200433d6423SLionel Sambuc 			 * error has been recorded
201433d6423SLionel Sambuc 			 */
202433d6423SLionel Sambuc 			expect_SIGFPE = 0;
203433d6423SLionel Sambuc 		} else {
204433d6423SLionel Sambuc 			/* a signal has been received and expect_SIGFPE has
205433d6423SLionel Sambuc 			 * been reset; all is ok now
206433d6423SLionel Sambuc 			 */
207433d6423SLionel Sambuc 			assert(!expect_SIGFPE);
208433d6423SLionel Sambuc 		}
209433d6423SLionel Sambuc 	}
210433d6423SLionel Sambuc }
211433d6423SLionel Sambuc 
testdiv(void)212433d6423SLionel Sambuc static void testdiv(void)
213433d6423SLionel Sambuc {
214433d6423SLionel Sambuc 	u64_t q, r;
215433d6423SLionel Sambuc #if TIMED
216433d6423SLionel Sambuc 	struct timeval tvstart, tvend;
217433d6423SLionel Sambuc 
218433d6423SLionel Sambuc 	printf("i=0x%.8x%.8x; j=0x%.8x%.8x\n",
219433d6423SLionel Sambuc 		ex64hi(i), ex64lo(i),
220433d6423SLionel Sambuc 		ex64hi(j), ex64lo(j));
221433d6423SLionel Sambuc 	fflush(stdout);
222433d6423SLionel Sambuc 	if (gettimeofday(&tvstart, NULL) < 0) ERR;
223433d6423SLionel Sambuc #endif
224433d6423SLionel Sambuc 
225433d6423SLionel Sambuc 	/* division by zero has a separate test */
226433d6423SLionel Sambuc 	if (j == 0) {
227433d6423SLionel Sambuc 		testdiv0();
228433d6423SLionel Sambuc 		return;
229433d6423SLionel Sambuc 	}
230433d6423SLionel Sambuc 
231433d6423SLionel Sambuc 	/* perform division, store q in k to make ERR more informative */
232433d6423SLionel Sambuc 	q = i / j;
233433d6423SLionel Sambuc 	r = i % j;
234433d6423SLionel Sambuc 	k = q;
235433d6423SLionel Sambuc 
236433d6423SLionel Sambuc #if TIMED
237433d6423SLionel Sambuc 	if (gettimeofday(&tvend, NULL) < 0) ERR;
238433d6423SLionel Sambuc 	tvend.tv_sec -= tvstart.tv_sec;
239433d6423SLionel Sambuc 	tvend.tv_usec -= tvstart.tv_usec;
240433d6423SLionel Sambuc 	if (tvend.tv_usec < 0) {
241433d6423SLionel Sambuc 		tvend.tv_sec -= 1;
242433d6423SLionel Sambuc 		tvend.tv_usec += 1000000;
243433d6423SLionel Sambuc 	}
244433d6423SLionel Sambuc 	printf("q=0x%.8x%.8x; r=0x%.8x%.8x; time=%d.%.6d\n",
245433d6423SLionel Sambuc 		ex64hi(q), ex64lo(q),
246433d6423SLionel Sambuc 		ex64hi(r), ex64lo(r),
247433d6423SLionel Sambuc 		tvend.tv_sec, tvend.tv_usec);
248433d6423SLionel Sambuc 	fflush(stdout);
249433d6423SLionel Sambuc #endif
250433d6423SLionel Sambuc 
251433d6423SLionel Sambuc 	/* compare to 64/32-bit division if possible */
252433d6423SLionel Sambuc 	if (!ex64hi(j)) {
253433d6423SLionel Sambuc 		if (q != i / ex64lo(j)) ERR;
254433d6423SLionel Sambuc 		if (!ex64hi(q)) {
255433d6423SLionel Sambuc 			if (q != i / ex64lo(j)) ERR;
256433d6423SLionel Sambuc 		}
257433d6423SLionel Sambuc 		if (r != i % ex64lo(j)) ERR;
258433d6423SLionel Sambuc 
259433d6423SLionel Sambuc 		/* compare to 32-bit division if possible */
260433d6423SLionel Sambuc 		if (!ex64hi(i)) {
261433d6423SLionel Sambuc 			if (q != ex64lo(i) / ex64lo(j)) ERR;
262433d6423SLionel Sambuc 			if (r != ex64lo(i) % ex64lo(j)) ERR;
263433d6423SLionel Sambuc 		}
264433d6423SLionel Sambuc 	}
265433d6423SLionel Sambuc 
266433d6423SLionel Sambuc 	/* check results using i = q j + r and r < j */
267433d6423SLionel Sambuc 	if (i != (q * j) + r) ERR;
268433d6423SLionel Sambuc 	if (r >= j) ERR;
269433d6423SLionel Sambuc }
270433d6423SLionel Sambuc 
test(void)271433d6423SLionel Sambuc static void test(void)
272433d6423SLionel Sambuc {
273433d6423SLionel Sambuc 	int idone, jdone, iidx, jidx;
274433d6423SLionel Sambuc 
275433d6423SLionel Sambuc 	/* loop though all argument value combinations */
276433d6423SLionel Sambuc 	for (idone = 0, iidx = 0; i = getargval(iidx, &idone), !idone; iidx++)
277433d6423SLionel Sambuc 	for (jdone = 0, jidx = 0; j = getargval(jidx, &jdone), !jdone; jidx++) {
278433d6423SLionel Sambuc 		testmul();
279433d6423SLionel Sambuc 		testdiv();
280433d6423SLionel Sambuc 	}
281433d6423SLionel Sambuc }
282433d6423SLionel Sambuc 
main(void)283433d6423SLionel Sambuc int main(void)
284433d6423SLionel Sambuc {
285433d6423SLionel Sambuc 	start(53);
286433d6423SLionel Sambuc 
287433d6423SLionel Sambuc 	/* set up signal handler to deal with div by zero */
288433d6423SLionel Sambuc 	if (setjmp(jmpbuf_main) == 0) {
289433d6423SLionel Sambuc 		if (signal(SIGFPE, handler_SIGFPE) == SIG_ERR) ERR;
290433d6423SLionel Sambuc 
291433d6423SLionel Sambuc 		/* perform tests */
292433d6423SLionel Sambuc 		test();
293433d6423SLionel Sambuc 	} else {
294433d6423SLionel Sambuc 		/* an unexpected SIGFPE has occurred */
295433d6423SLionel Sambuc 		ERR;
296433d6423SLionel Sambuc 	}
297433d6423SLionel Sambuc 
298433d6423SLionel Sambuc 	/* this was all */
299433d6423SLionel Sambuc 	quit();
300433d6423SLionel Sambuc 
301433d6423SLionel Sambuc 	return(-1);	/* Unreachable */
302433d6423SLionel Sambuc }
303