1 #include <assert.h> 2 #include <minix/u64.h> 3 #include <setjmp.h> 4 #include <signal.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <sys/time.h> 8 #include <unistd.h> 9 10 #define ERR err(__LINE__) 11 int max_error = 4; 12 #include "common.h" 13 14 #define TIMED 0 15 16 17 static volatile int expect_SIGFPE; 18 static u64_t i, j, k; 19 static jmp_buf jmpbuf_SIGFPE, jmpbuf_main; 20 21 static void err(int line) 22 { 23 /* print error information */ 24 printf("error line %d; i=0x%.8lx%.8lx; j=0x%.8lx%.8lx; k=0x%.8lx%.8lx\n", 25 line, 26 ex64hi(i), ex64lo(i), 27 ex64hi(j), ex64lo(j), 28 ex64hi(k), ex64lo(k)); 29 30 /* quit after too many errors */ 31 e(7); 32 } 33 34 #define LENGTHOF(arr) (sizeof(arr) / sizeof(arr[0])) 35 36 static u64_t getargval(int index, int *done) 37 { 38 u32_t values[] = { 39 /* corner cases */ 40 0, 41 1, 42 0x7fffffff, 43 0x80000000, 44 0x80000001, 45 0xffffffff, 46 /* random values */ 47 0xa9, 48 0x0d88, 49 0x242811, 50 0xeb44d1bc, 51 0x5b, 52 0xfb50, 53 0x569c02, 54 0xb23c8f7d, 55 0xc3, 56 0x2366, 57 0xfabb73, 58 0xcb4e8aef, 59 0xe9, 60 0xffdc, 61 0x05842d, 62 0x3fff902d}; 63 64 assert(done); 65 66 /* values with corner case and random 32-bit components */ 67 if (index < LENGTHOF(values) * LENGTHOF(values)) 68 return make64(values[index / LENGTHOF(values)], values[index % LENGTHOF(values)]); 69 70 index -= LENGTHOF(values) * LENGTHOF(values); 71 72 /* small numbers */ 73 if (index < 16) return make64(index + 2, 0); 74 index -= 16; 75 76 /* big numbers */ 77 if (index < 16) return make64(-index - 2, -1); 78 index -= 16; 79 80 /* powers of two */ 81 if (index < 14) return make64(1 << (index * 2 + 5), 0); 82 index -= 14; 83 if (index < 16) return make64(0, 1 << (index * 2 + 1)); 84 index -= 16; 85 86 /* done */ 87 *done = 1; 88 return make64(0, 0); 89 } 90 91 static void handler_SIGFPE(int signum) 92 { 93 assert(signum == SIGFPE); 94 95 /* restore the signal handler */ 96 if (signal(SIGFPE, handler_SIGFPE) == SIG_ERR) ERR; 97 98 /* division by zero occurred, was this expected? */ 99 if (expect_SIGFPE) { 100 /* expected: jump back to test */ 101 expect_SIGFPE = 0; 102 longjmp(jmpbuf_SIGFPE, -1); 103 } else { 104 /* not expected: error and jump back to main */ 105 longjmp(jmpbuf_main, -1); 106 } 107 108 /* not reachable */ 109 assert(0); 110 exit(-1); 111 } 112 113 static inline int bsr64(u64_t i) 114 { 115 int index; 116 u64_t mask; 117 118 for (index = 63, mask = 1ULL << 63; index >= 0; --index, mask >>= 1) { 119 if (i & mask) 120 return index; 121 } 122 123 return -1; 124 } 125 126 static void testmul(void) 127 { 128 int kdone, kidx; 129 u32_t ilo = ex64lo(i), jlo = ex64lo(j); 130 u64_t prod = i * j; 131 int prodbits; 132 133 /* compute maximum index of highest-order bit */ 134 prodbits = bsr64(i) + bsr64(j) + 1; 135 if (i == 0 || j == 0) prodbits = -1; 136 if (bsr64(prod) > prodbits) ERR; 137 138 /* compare to 32-bit multiplication if possible */ 139 if (ex64hi(i) == 0 && ex64hi(j) == 0) { 140 if (prod != (u64_t)ilo * jlo) ERR; 141 142 /* if there is no overflow we can check against pure 32-bit */ 143 if (prodbits < 32 && prod != ilo * jlo) ERR; 144 } 145 146 /* in 32-bit arith low-order DWORD matches regardless of overflow */ 147 if (ex64lo(prod) != ilo * jlo) ERR; 148 149 /* multiplication by zero yields zero */ 150 if (prodbits < 0 && prod != 0) ERR; 151 152 /* if there is no overflow, check absence of zero divisors */ 153 if (prodbits >= 0 && prodbits < 64 && prod == 0) ERR; 154 155 /* commutativity */ 156 if (prod != j * i) ERR; 157 158 /* loop though all argument value combinations for third argument */ 159 for (kdone = 0, kidx = 0; k = getargval(kidx, &kdone), !kdone; kidx++) { 160 /* associativity */ 161 if ((i * j) * k != i * (j * k)) ERR; 162 163 /* left and right distributivity */ 164 if ((i + j) * k != (i * k) + (j * k)) ERR; 165 if (i * (j + k) != (i * j) + (i * k)) ERR; 166 } 167 } 168 169 static void do_not_optimize_away(volatile u64_t * ptr) 170 { 171 172 /* TODO: does this actually do the job? */ 173 *ptr ^= 1; 174 } 175 176 static void testdiv0(void) 177 { 178 int funcidx; 179 u64_t res; 180 181 assert(j == 0); 182 183 /* loop through the 5 different division functions */ 184 for (funcidx = 0; funcidx < 5; funcidx++) { 185 expect_SIGFPE = 1; 186 if (setjmp(jmpbuf_SIGFPE) == 0) { 187 /* divide by zero using various functions */ 188 switch (funcidx) { 189 case 0: res = i / j; ERR; break; 190 case 1: res = i / ex64lo(j); ERR; break; 191 case 2: res = i / ex64lo(j); ERR; break; 192 case 3: res = i % j; ERR; break; 193 case 4: res = i % ex64lo(j); ERR; break; 194 default: assert(0); ERR; break; 195 } 196 197 do_not_optimize_away((volatile u64_t *)&res); 198 199 /* if we reach this point there was no signal and an 200 * error has been recorded 201 */ 202 expect_SIGFPE = 0; 203 } else { 204 /* a signal has been received and expect_SIGFPE has 205 * been reset; all is ok now 206 */ 207 assert(!expect_SIGFPE); 208 } 209 } 210 } 211 212 static void testdiv(void) 213 { 214 u64_t q, r; 215 #if TIMED 216 struct timeval tvstart, tvend; 217 218 printf("i=0x%.8x%.8x; j=0x%.8x%.8x\n", 219 ex64hi(i), ex64lo(i), 220 ex64hi(j), ex64lo(j)); 221 fflush(stdout); 222 if (gettimeofday(&tvstart, NULL) < 0) ERR; 223 #endif 224 225 /* division by zero has a separate test */ 226 if (j == 0) { 227 testdiv0(); 228 return; 229 } 230 231 /* perform division, store q in k to make ERR more informative */ 232 q = i / j; 233 r = i % j; 234 k = q; 235 236 #if TIMED 237 if (gettimeofday(&tvend, NULL) < 0) ERR; 238 tvend.tv_sec -= tvstart.tv_sec; 239 tvend.tv_usec -= tvstart.tv_usec; 240 if (tvend.tv_usec < 0) { 241 tvend.tv_sec -= 1; 242 tvend.tv_usec += 1000000; 243 } 244 printf("q=0x%.8x%.8x; r=0x%.8x%.8x; time=%d.%.6d\n", 245 ex64hi(q), ex64lo(q), 246 ex64hi(r), ex64lo(r), 247 tvend.tv_sec, tvend.tv_usec); 248 fflush(stdout); 249 #endif 250 251 /* compare to 64/32-bit division if possible */ 252 if (!ex64hi(j)) { 253 if (q != i / ex64lo(j)) ERR; 254 if (!ex64hi(q)) { 255 if (q != i / ex64lo(j)) ERR; 256 } 257 if (r != i % ex64lo(j)) ERR; 258 259 /* compare to 32-bit division if possible */ 260 if (!ex64hi(i)) { 261 if (q != ex64lo(i) / ex64lo(j)) ERR; 262 if (r != ex64lo(i) % ex64lo(j)) ERR; 263 } 264 } 265 266 /* check results using i = q j + r and r < j */ 267 if (i != (q * j) + r) ERR; 268 if (r >= j) ERR; 269 } 270 271 static void test(void) 272 { 273 int idone, jdone, iidx, jidx; 274 275 /* loop though all argument value combinations */ 276 for (idone = 0, iidx = 0; i = getargval(iidx, &idone), !idone; iidx++) 277 for (jdone = 0, jidx = 0; j = getargval(jidx, &jdone), !jdone; jidx++) { 278 testmul(); 279 testdiv(); 280 } 281 } 282 283 int main(void) 284 { 285 start(53); 286 287 /* set up signal handler to deal with div by zero */ 288 if (setjmp(jmpbuf_main) == 0) { 289 if (signal(SIGFPE, handler_SIGFPE) == SIG_ERR) ERR; 290 291 /* perform tests */ 292 test(); 293 } else { 294 /* an unexpected SIGFPE has occurred */ 295 ERR; 296 } 297 298 /* this was all */ 299 quit(); 300 301 return(-1); /* Unreachable */ 302 } 303