1/*	$NetBSD$	*/
2
3/*-
4 * Copyright (c) 2002 Ross Harvey
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *    Redistributions of source code must not add the GNU General Public
13 *    License or any similar license to this work or to derivative works
14 *    incorporating this code. No requirement to distribute source may
15 *    be imposed upon redistributions in binary form of this work or of
16 *    derivative works.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include <stdio.h>
35#include <stdlib.h>
36#include <unistd.h>
37#include <fcntl.h>
38#include <stdint.h>
39#include <assert.h>
40#include <time.h>
41
42#define	KLE	3	// exponent for k and l salt values
43#define	NEARBY	600	// all numbers +-NEARBY 0 and INTxx_MIN will be tried
44#define	RANDOMCOUNT 300000	// number of random(3)-based cases to run
45
46#define	 IM(x)	 ((intmax_t)(x))
47#define	UIM(x)	((uintmax_t)(x))
48
49#define TEST(id, a, b, c)                             			\
50    if (b) {                            				\
51	c = (a) / (b);                        				\
52	printf(id "%16jx / %16jx => %16jx\n", UIM(a), UIM(b), UIM(c));  \
53	c = (a) % (b);                        				\
54	printf(id "%16jx / %16jx => %16jx\n", UIM(a), UIM(b), UIM(c));  \
55    }
56
57#define	T64S(a, b, c)	TEST("64 ", (a), (b), (c))
58#define	T64U(a, b, c)	TEST("64U", (a), (b), (c))
59
60union {
61	char	ranstate[128];
62	long	alignme;
63} ranalign;
64
65int enable_time_output;
66
67void mark_time(const int phase)
68{
69static	time_t startphase;
70	time_t t;
71
72	t = time(NULL);
73	if (enable_time_output && phase != 0) {
74		fprintf(stderr, "phase %d/6: %5d seconds\n", phase,
75		    (int)(t - startphase));
76		fflush(stderr);
77	}
78	startphase = t;
79}
80
81int main(int ac, char **av)
82{
83     int32_t a32, b32, sr32;
84    uint32_t ur32;
85     intmax_t a64, b64, sr64;
86    uintmax_t ur64;
87     int i, j, k, l;
88
89    enable_time_output = ac <= 1;
90    mark_time(0);
91    for(i = KLE; i <= 30; ++i) {
92	a32 = 1 << i;
93	for(j = KLE; j <= 30; ++j) {
94	    b32 = 1 << j;
95	    for(k = -(1 << KLE); k <= 1 << KLE; ++k) {
96		for(l = -(1 << KLE); l <= 1 << KLE; ++l) {
97		    TEST("32 ",  a32 + k,  b32 + l, sr32);
98		    TEST("32 ",  a32 + k, -(b32 + l), sr32);
99		    TEST("32 ", -(a32 + k),   b32 + l, sr32);
100		    TEST("32 ", -(a32 + k), -(b32 + l), sr32);
101		    assert((1U << i) + k >= 0);
102		    assert((1U << j) + l >= 0);
103		    TEST("32U", (1U << i) + k, (1U << j) + l, ur32);
104		}
105	    }
106	}
107    }
108
109    mark_time(1);
110    for(a32 = -NEARBY; a32 < NEARBY; ++a32) {
111	for(b32 = -NEARBY; b32 < NEARBY; ++b32) {
112	    TEST("32 ", a32, b32, sr32);
113	    if (a32 >= 0 && b32 >= 0)
114		TEST("32U", (unsigned)a32, (unsigned)b32, ur32);
115	}
116    }
117    mark_time(2);
118    for(a32 = INT32_MIN; a32 < INT32_MIN + NEARBY; ++a32) {
119	for(b32 = INT32_MIN; b32 < INT32_MIN + NEARBY; ++b32)
120	    TEST("32 ", a32, b32, sr32);
121	for(b32 = -NEARBY; b32 < NEARBY; ++b32)
122	    if (a32 != INT32_MIN || b32 != -1)
123		TEST("32 ", a32, b32, sr32);
124    }
125
126    mark_time(3);
127    if (sizeof(intmax_t) == 4)
128	exit(0);
129    for(i = KLE; i <= 62; ++i) {
130	a64 = IM(1) << i;
131	for(j = KLE; j <= 62; ++j) {
132	    b64 = IM(1) << j;
133	    for(k = -(1 << KLE); k <= 1 << KLE; ++k) {
134		for(l = -(1 << KLE); l <= 1 << KLE; ++l) {
135		    T64S( a64 + k,  b64 + l, sr64);
136		    T64S( a64 + k, -b64 + l, sr64);
137		    T64S(-a64 + k,  b64 + l, sr64);
138		    T64S(-a64 + k, -b64 + l, sr64);
139		    T64U(UIM(a64) + k, UIM(b64) + l, ur64);
140		}
141	    }
142	}
143    }
144
145    mark_time(4);
146    for(a64 = -(1 << KLE); a64 < 1 << KLE; ++a64) {
147	for(b64 = -(1 << KLE); b64 < 1 << KLE; ++b64) {
148	    TEST("64 ", a64, b64, sr64);
149	    if (a64 >= 0 && b64 >= 0)
150		TEST("64U", (unsigned)a64, (unsigned)b64, ur64);
151	}
152    }
153    for(a64 = INT64_MIN; a64 < INT64_MIN + NEARBY; ++a64) {
154	for(b64 = INT64_MIN; b64 < INT64_MIN + NEARBY; ++b64)
155	    TEST("64 ", a64, b64, sr64);
156	for(b64 = -NEARBY; b64 < NEARBY; ++b64)
157	    if (a64 != INT64_MIN || b64 != -1)
158		TEST("64 ", a64, b64, sr64);
159    }
160    mark_time(5);
161    initstate(1UL, ranalign.ranstate, sizeof ranalign.ranstate);
162    for(i = 0; i < RANDOMCOUNT; ++i) {
163	int32_t low32 = random();
164	int64_t low64 = (intmax_t)random() << 32 | low32;
165
166	a32 = random();
167	b32 = random();
168	a64 = ((intmax_t)random() << 32) | a32;
169	b64 = ((intmax_t)random() << 32) | b32;
170	TEST("32 ", a32, b32, sr32);
171	TEST("32u", (unsigned)a32 + low32, (unsigned)b32 + low32, ur32);
172	TEST("32 ", -a32 - 1, b32, sr32);
173	TEST("32 ", a32, -b32, sr32);
174	if (a32 != INT32_MAX || b32 != 1)
175	    TEST("32 ", -a32 - 1, -b32, sr32);
176	TEST("64 ", a64, b64, sr64);
177	TEST("64u", (unsigned)a64 + low64, (unsigned)b64 + low64, ur64);
178	TEST("64 ", -a64 - 1, b64, sr64);
179	TEST("64 ", a64, -b64, sr64);
180	if (a64 != INT64_MAX || b64 != 1)
181	    TEST("64 ", -a64 - 1, -b64, sr64);
182    }
183    mark_time(6);
184    exit(0);
185    return 0;
186}
187