Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libm/common/m9x/__fex_i386.c
+++ new/usr/src/lib/libm/common/m9x/__fex_i386.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
24 24 */
25 25 /*
26 26 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
27 27 * Use is subject to license terms.
28 28 */
29 29
30 30 #include "fenv_synonyms.h"
31 31 #include <stdio.h>
32 32 #include <unistd.h>
33 33 #include <stdlib.h>
34 34 #include <string.h>
35 35 #include <signal.h>
36 36 #include <siginfo.h>
37 37 #include <ucontext.h>
38 38 #include <thread.h>
39 39 #include <math.h>
40 40 #if defined(__SUNPRO_C)
41 41 #include <sunmath.h>
42 42 #endif
43 43 #include <fenv.h>
44 44 #include "fex_handler.h"
45 45 #include "fenv_inlines.h"
46 46
47 47 #if defined(__amd64)
48 48 #define test_sse_hw 1
49 49 #else
50 50 /*
51 51 * The following variable lives in libc on Solaris 10, where it
52 52 * gets set to a nonzero value at startup time on systems with SSE.
53 53 */
54 54 int _sse_hw = 0;
55 55 #pragma weak _sse_hw
56 56 #define test_sse_hw &_sse_hw && _sse_hw
57 57 #endif
58 58
59 59 static int accrued = 0;
60 60 static thread_key_t accrued_key;
61 61 static mutex_t accrued_key_lock = DEFAULTMUTEX;
62 62
63 63 int *
64 64 __fex_accrued()
65 65 {
66 66 int *p;
67 67
68 68 if (thr_main())
69 69 return &accrued;
70 70 else {
71 71 p = NULL;
72 72 mutex_lock(&accrued_key_lock);
73 73 if (thr_getspecific(accrued_key, (void **)&p) != 0 &&
74 74 thr_keycreate(&accrued_key, free) != 0) {
75 75 mutex_unlock(&accrued_key_lock);
76 76 return NULL;
77 77 }
78 78 mutex_unlock(&accrued_key_lock);
79 79 if (!p) {
80 80 if ((p = (int*) malloc(sizeof(int))) == NULL)
81 81 return NULL;
82 82 if (thr_setspecific(accrued_key, (void *)p) != 0) {
83 83 (void)free(p);
84 84 return NULL;
85 85 }
86 86 *p = 0;
87 87 }
88 88 return p;
89 89 }
90 90 }
91 91
92 92 void
93 93 __fenv_getfsr(unsigned long *fsr)
94 94 {
95 95 unsigned int cwsw, mxcsr;
96 96
97 97 __fenv_getcwsw(&cwsw);
98 98 /* clear reserved bits for no particularly good reason */
99 99 cwsw &= ~0xe0c00000u;
100 100 if (test_sse_hw) {
101 101 /* pick up exception flags (excluding denormal operand
102 102 flag) from mxcsr */
103 103 __fenv_getmxcsr(&mxcsr);
104 104 cwsw |= (mxcsr & 0x3d);
105 105 }
106 106 cwsw |= *__fex_accrued();
107 107 *fsr = cwsw ^ 0x003f0000u;
108 108 }
109 109
110 110 void
111 111 __fenv_setfsr(const unsigned long *fsr)
112 112 {
113 113 unsigned int cwsw, mxcsr;
114 114 int te;
115 115
116 116 /* save accrued exception flags corresponding to enabled exceptions */
117 117 cwsw = (unsigned int)*fsr;
118 118 te = __fenv_get_te(cwsw);
119 119 *__fex_accrued() = cwsw & te;
120 120 cwsw = (cwsw & ~te) ^ 0x003f0000;
121 121 if (test_sse_hw) {
122 122 /* propagate rounding direction, masks, and exception flags
123 123 (excluding denormal operand mask and flag) to mxcsr */
124 124 __fenv_getmxcsr(&mxcsr);
125 125 mxcsr = (mxcsr & ~0x7ebd) | ((cwsw >> 13) & 0x6000) |
126 126 ((cwsw >> 9) & 0x1e80) | (cwsw & 0x3d);
127 127 __fenv_setmxcsr(&mxcsr);
128 128 }
129 129 __fenv_setcwsw(&cwsw);
130 130 }
131 131
132 132 /* Offsets into the fp environment save area (assumes 32-bit protected mode) */
133 133 #define CW 0 /* control word */
134 134 #define SW 1 /* status word */
135 135 #define TW 2 /* tag word */
136 136 #define IP 3 /* instruction pointer */
137 137 #define OP 4 /* opcode */
138 138 #define EA 5 /* operand address */
139 139
140 140 /* macro for accessing fp registers in the save area */
141 141 #if defined(__amd64)
142 142 #define fpreg(u,x) *(long double *)(10*(x)+(char*)&(u)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.st)
143 143 #else
144 144 #define fpreg(u,x) *(long double *)(10*(x)+(char*)&(u)->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[7])
145 145 #endif
146 146
147 147 /*
148 148 * Fix sip->si_code; the Solaris x86 kernel can get it wrong
149 149 */
150 150 void
151 151 __fex_get_x86_exc(siginfo_t *sip, ucontext_t *uap)
152 152 {
153 153 unsigned sw, cw;
154 154
155 155 sw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status;
156 156 #if defined(__amd64)
157 157 cw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.cw;
158 158 #else
159 159 cw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[CW];
160 160 #endif
161 161 if ((sw & FE_INVALID) && !(cw & (1 << fp_trap_invalid)))
162 162 /* store 0 for stack fault, FPE_FLTINV for IEEE invalid op */
163 163 sip->si_code = ((sw & 0x40)? 0 : FPE_FLTINV);
164 164 else if ((sw & FE_DIVBYZERO) && !(cw & (1 << fp_trap_division)))
165 165 sip->si_code = FPE_FLTDIV;
166 166 else if ((sw & FE_OVERFLOW) && !(cw & (1 << fp_trap_overflow)))
167 167 sip->si_code = FPE_FLTOVF;
168 168 else if ((sw & FE_UNDERFLOW) && !(cw & (1 << fp_trap_underflow)))
169 169 sip->si_code = FPE_FLTUND;
170 170 else if ((sw & FE_INEXACT) && !(cw & (1 << fp_trap_inexact)))
171 171 sip->si_code = FPE_FLTRES;
172 172 else
173 173 sip->si_code = 0;
174 174 }
175 175
176 176 static enum fp_class_type
177 177 my_fp_classf(float *x)
178 178 {
179 179 int i = *(int*)x & ~0x80000000;
180 180
181 181 if (i < 0x7f800000) {
182 182 if (i < 0x00800000)
183 183 return ((i == 0)? fp_zero : fp_subnormal);
184 184 return fp_normal;
185 185 }
186 186 else if (i == 0x7f800000)
187 187 return fp_infinity;
188 188 else if (i & 0x400000)
189 189 return fp_quiet;
190 190 else
191 191 return fp_signaling;
192 192 }
193 193
194 194 static enum fp_class_type
195 195 my_fp_class(double *x)
196 196 {
197 197 int i = *(1+(int*)x) & ~0x80000000;
198 198
199 199 if (i < 0x7ff00000) {
200 200 if (i < 0x00100000)
201 201 return (((i | *(int*)x) == 0)? fp_zero : fp_subnormal);
202 202 return fp_normal;
203 203 }
204 204 else if (i == 0x7ff00000 && *(int*)x == 0)
205 205 return fp_infinity;
206 206 else if (i & 0x80000)
207 207 return fp_quiet;
208 208 else
209 209 return fp_signaling;
210 210 }
211 211
212 212 static enum fp_class_type
213 213 my_fp_classl(long double *x)
214 214 {
215 215 int i = *(2+(int*)x) & 0x7fff;
216 216
217 217 if (i < 0x7fff) {
218 218 if (i < 1) {
219 219 if (*(1+(int*)x) < 0) return fp_normal; /* pseudo-denormal */
220 220 return (((*(1+(int*)x) | *(int*)x) == 0)?
221 221 fp_zero : fp_subnormal);
222 222 }
223 223 return ((*(1+(int*)x) < 0)? fp_normal :
224 224 (enum fp_class_type) -1); /* unsupported format */
225 225 }
226 226 else if (*(1+(int*)x) == 0x80000000 && *(int*)x == 0)
227 227 return fp_infinity;
228 228 else if (*(1+(unsigned*)x) >= 0xc0000000)
229 229 return fp_quiet;
230 230 else if (*(1+(int*)x) < 0)
231 231 return fp_signaling;
232 232 else
233 233 return (enum fp_class_type) -1; /* unsupported format */
234 234 }
235 235
236 236 /*
237 237 * Determine which type of invalid operation exception occurred
238 238 */
239 239 enum fex_exception
240 240 __fex_get_invalid_type(siginfo_t *sip, ucontext_t *uap)
241 241 {
242 242 unsigned op;
243 243 unsigned long ea;
244 244 enum fp_class_type t1, t2;
245 245
246 246 /* get the opcode and data address */
247 247 #if defined(__amd64)
248 248 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16;
249 249 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp;
250 250 #else
251 251 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16;
252 252 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA];
253 253 #endif
254 254
255 255 /* if the instruction is fld, the source must be snan (it can't be
256 256 an unsupported format, since fldt doesn't raise any exceptions) */
257 257 switch (op & 0x7f8) {
258 258 case 0x100:
259 259 case 0x140:
260 260 case 0x180:
261 261 case 0x500:
262 262 case 0x540:
263 263 case 0x580:
264 264 return fex_inv_snan;
265 265 }
266 266
267 267 /* otherwise st is one of the operands; see if it's snan */
268 268 t1 = my_fp_classl(&fpreg(uap, 0));
269 269 if (t1 == fp_signaling)
270 270 return fex_inv_snan;
271 271 else if (t1 == (enum fp_class_type) -1)
272 272 return (enum fex_exception) -1;
273 273
274 274 /* determine the class of the second operand if there is one */
275 275 t2 = fp_normal;
276 276 switch (op & 0x7e0) {
277 277 case 0x600:
278 278 case 0x620:
279 279 case 0x640:
280 280 case 0x660:
281 281 case 0x680:
282 282 case 0x6a0:
283 283 /* short memory operand */
284 284 if (!ea)
285 285 return (enum fex_exception) -1;
286 286 if (*(short *)ea == 0)
287 287 t2 = fp_zero;
288 288 break;
289 289
290 290 case 0x200:
291 291 case 0x220:
292 292 case 0x240:
293 293 case 0x260:
294 294 case 0x280:
295 295 case 0x2a0:
296 296 /* int memory operand */
297 297 if (!ea)
298 298 return (enum fex_exception) -1;
299 299 if (*(int *)ea == 0)
300 300 t2 = fp_zero;
301 301 break;
302 302
303 303 case 0x000:
304 304 case 0x020:
305 305 case 0x040:
306 306 case 0x060:
307 307 case 0x080:
308 308 case 0x0a0:
309 309 /* single precision memory operand */
310 310 if (!ea)
311 311 return (enum fex_exception) -1;
312 312 t2 = my_fp_classf((float *)ea);
313 313 break;
314 314
315 315 case 0x400:
316 316 case 0x420:
317 317 case 0x440:
318 318 case 0x460:
319 319 case 0x480:
320 320 case 0x4a0:
321 321 /* double precision memory operand */
322 322 if (!ea)
323 323 return (enum fex_exception) -1;
324 324 t2 = my_fp_class((double *)ea);
325 325 break;
326 326
327 327 case 0x0c0:
328 328 case 0x0e0:
329 329 case 0x3e0:
330 330 case 0x4c0:
331 331 case 0x4e0:
332 332 case 0x5e0:
333 333 case 0x6c0:
334 334 case 0x6e0:
335 335 case 0x7e0:
336 336 /* register operand determined by opcode */
337 337 switch (op & 0x7f8) {
338 338 case 0x3e0:
339 339 case 0x3f8:
340 340 case 0x5f0:
341 341 case 0x5f8:
342 342 case 0x7e0:
343 343 case 0x7f8:
344 344 /* weed out nonexistent opcodes */
345 345 break;
346 346
347 347 default:
348 348 t2 = my_fp_classl(&fpreg(uap, op & 7));
349 349 }
350 350 break;
351 351
352 352 case 0x1e0:
353 353 case 0x2e0:
354 354 /* special forms */
355 355 switch (op) {
356 356 case 0x1f1: /* fyl2x */
357 357 case 0x1f3: /* fpatan */
358 358 case 0x1f5: /* fprem1 */
359 359 case 0x1f8: /* fprem */
360 360 case 0x1f9: /* fyl2xp1 */
361 361 case 0x1fd: /* fscale */
362 362 case 0x2e9: /* fucompp */
363 363 t2 = my_fp_classl(&fpreg(uap, 1));
364 364 break;
365 365 }
366 366 break;
367 367 }
368 368
369 369 /* see if the second op is snan */
370 370 if (t2 == fp_signaling)
371 371 return fex_inv_snan;
372 372 else if (t2 == (enum fp_class_type) -1)
373 373 return (enum fex_exception) -1;
374 374
375 375 /* determine the type of operation */
376 376 switch (op & 0x7f8) {
377 377 case 0x000:
378 378 case 0x020:
379 379 case 0x028:
380 380 case 0x040:
381 381 case 0x060:
382 382 case 0x068:
383 383 case 0x080:
384 384 case 0x0a0:
385 385 case 0x0a8:
386 386 case 0x0c0:
387 387 case 0x0e0:
388 388 case 0x0e8:
389 389 case 0x400:
390 390 case 0x420:
391 391 case 0x428:
392 392 case 0x440:
393 393 case 0x460:
394 394 case 0x468:
395 395 case 0x480:
396 396 case 0x4a0:
397 397 case 0x4a8:
398 398 case 0x4c0:
399 399 case 0x4e0:
400 400 case 0x4e8:
401 401 case 0x6c0:
402 402 case 0x6e0:
403 403 case 0x6e8:
404 404 /* fadd, fsub, fsubr */
405 405 if (t1 == fp_infinity && t2 == fp_infinity)
406 406 return fex_inv_isi;
407 407 break;
408 408
409 409 case 0x008:
410 410 case 0x048:
411 411 case 0x088:
412 412 case 0x0c8:
413 413 case 0x208:
414 414 case 0x248:
415 415 case 0x288:
416 416 case 0x408:
417 417 case 0x448:
418 418 case 0x488:
419 419 case 0x4c8:
420 420 case 0x608:
421 421 case 0x648:
422 422 case 0x688:
423 423 case 0x6c8:
424 424 /* fmul */
425 425 if ((t1 == fp_zero && t2 == fp_infinity) || (t2 == fp_zero &&
426 426 t1 == fp_infinity))
427 427 return fex_inv_zmi;
428 428 break;
429 429
430 430 case 0x030:
431 431 case 0x038:
432 432 case 0x070:
433 433 case 0x078:
434 434 case 0x0b0:
435 435 case 0x0b8:
436 436 case 0x0f0:
437 437 case 0x0f8:
438 438 case 0x230:
439 439 case 0x238:
440 440 case 0x270:
441 441 case 0x278:
442 442 case 0x2b0:
443 443 case 0x2b8:
444 444 case 0x430:
445 445 case 0x438:
446 446 case 0x470:
447 447 case 0x478:
448 448 case 0x4b0:
449 449 case 0x4b8:
450 450 case 0x4f0:
451 451 case 0x4f8:
452 452 case 0x630:
453 453 case 0x638:
454 454 case 0x670:
455 455 case 0x678:
456 456 case 0x6b0:
457 457 case 0x6b8:
458 458 case 0x6f0:
459 459 case 0x6f8:
460 460 /* fdiv */
461 461 if (t1 == fp_zero && t2 == fp_zero)
462 462 return fex_inv_zdz;
463 463 else if (t1 == fp_infinity && t2 == fp_infinity)
464 464 return fex_inv_idi;
465 465 break;
466 466
467 467 case 0x1f0:
468 468 case 0x1f8:
469 469 /* fsqrt, other special ops */
470 470 return fex_inv_sqrt;
471 471
472 472 case 0x010:
473 473 case 0x018:
474 474 case 0x050:
475 475 case 0x058:
476 476 case 0x090:
477 477 case 0x098:
478 478 case 0x0d0:
479 479 case 0x0d8:
480 480 case 0x210:
481 481 case 0x218:
482 482 case 0x250:
483 483 case 0x258:
484 484 case 0x290:
485 485 case 0x298:
486 486 case 0x2e8:
487 487 case 0x3f0:
488 488 case 0x410:
489 489 case 0x418:
490 490 case 0x450:
491 491 case 0x458:
492 492 case 0x490:
493 493 case 0x498:
494 494 case 0x4d0:
495 495 case 0x4d8:
496 496 case 0x5e0:
497 497 case 0x5e8:
498 498 case 0x610:
499 499 case 0x618:
500 500 case 0x650:
501 501 case 0x658:
502 502 case 0x690:
503 503 case 0x698:
504 504 case 0x6d0:
505 505 case 0x6d8:
506 506 case 0x7f0:
507 507 /* fcom */
508 508 if (t1 == fp_quiet || t2 == fp_quiet)
509 509 return fex_inv_cmp;
510 510 break;
511 511
512 512 case 0x1e0:
513 513 /* ftst */
514 514 if (op == 0x1e4 && t1 == fp_quiet)
515 515 return fex_inv_cmp;
516 516 break;
517 517
518 518 case 0x310:
519 519 case 0x318:
520 520 case 0x350:
521 521 case 0x358:
522 522 case 0x390:
523 523 case 0x398:
524 524 case 0x710:
525 525 case 0x718:
526 526 case 0x730:
527 527 case 0x738:
528 528 case 0x750:
529 529 case 0x758:
530 530 case 0x770:
531 531 case 0x778:
532 532 case 0x790:
533 533 case 0x798:
534 534 case 0x7b0:
535 535 case 0x7b8:
536 536 /* fist, fbst */
537 537 return fex_inv_int;
538 538 }
539 539
540 540 return (enum fex_exception) -1;
541 541 }
542 542
543 543 /* scale factors for exponent unwrapping */
544 544 static const long double
545 545 two12288 = 1.139165225263043370845938579315932009e+3699l, /* 2^12288 */
546 546 twom12288 = 8.778357852076208839765066529179033145e-3700l, /* 2^-12288 */
547 547 twom12288mulp = 8.778357852076208839289190796475222545e-3700l;
548 548 /* (")*(1-2^-64) */
549 549
550 550 /* inline templates */
551 551 extern long double f2xm1(long double);
552 552 extern long double fyl2x(long double, long double);
553 553 extern long double fptan(long double);
554 554 extern long double fpatan(long double, long double);
555 555 extern long double fxtract(long double);
556 556 extern long double fprem1(long double, long double);
557 557 extern long double fprem(long double, long double);
558 558 extern long double fyl2xp1(long double, long double);
559 559 extern long double fsqrt(long double);
560 560 extern long double fsincos(long double);
561 561 extern long double frndint(long double);
562 562 extern long double fscale(long double, long double);
563 563 extern long double fsin(long double);
564 564 extern long double fcos(long double);
565 565
566 566 /*
567 567 * Get the operands, generate the default untrapped result with
568 568 * exceptions, and set a code indicating the type of operation
569 569 */
570 570 void
571 571 __fex_get_op(siginfo_t *sip, ucontext_t *uap, fex_info_t *info)
572 572 {
573 573 fex_numeric_t t;
574 574 long double op2v, x;
575 575 unsigned int cwsw, ex, sw, op;
576 576 unsigned long ea;
577 577 volatile int c;
578 578
579 579 /* get the exception type, status word, opcode, and data address */
580 580 ex = sip->si_code;
581 581 sw = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.status;
582 582 #if defined(__amd64)
583 583 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16;
584 584 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp;
585 585 #else
586 586 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16;
587 587 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA];
588 588 #endif
589 589
590 590 /* initialize res to the default untrapped result and ex to the
591 591 corresponding flags (assume trapping is disabled and flags
592 592 are clear) */
593 593
594 594 /* single operand instructions */
595 595 info->op = fex_cnvt;
596 596 info->op2.type = fex_nodata;
597 597 switch (op & 0x7f8) {
598 598 /* load instructions */
599 599 case 0x100:
600 600 case 0x140:
601 601 case 0x180:
602 602 if (!ea) {
603 603 info->op = fex_other;
604 604 info->op1.type = info->op2.type = info->res.type = fex_nodata;
605 605 info->flags = 0;
606 606 return;
607 607 }
608 608 info->op1.type = fex_float;
609 609 info->op1.val.f = *(float *)ea;
610 610 info->res.type = fex_ldouble;
611 611 info->res.val.q = (long double) info->op1.val.f;
612 612 goto done;
613 613
614 614 case 0x500:
615 615 case 0x540:
616 616 case 0x580:
617 617 if (!ea) {
618 618 info->op = fex_other;
619 619 info->op1.type = info->op2.type = info->res.type = fex_nodata;
620 620 info->flags = 0;
621 621 return;
622 622 }
623 623 info->op1.type = fex_double;
624 624 info->op1.val.d = *(double *)ea;
625 625 info->res.type = fex_ldouble;
626 626 info->res.val.q = (long double) info->op1.val.d;
627 627 goto done;
628 628
629 629 /* store instructions */
630 630 case 0x110:
631 631 case 0x118:
632 632 case 0x150:
633 633 case 0x158:
634 634 case 0x190:
635 635 case 0x198:
636 636 info->res.type = fex_float;
637 637 if (ex == FPE_FLTRES && (op & 8) != 0) {
638 638 /* inexact, stack popped */
639 639 if (!ea) {
640 640 info->op = fex_other;
641 641 info->op1.type = info->op2.type = info->res.type = fex_nodata;
642 642 info->flags = 0;
643 643 return;
644 644 }
645 645 info->op1.type = fex_nodata;
646 646 info->res.val.f = *(float *)ea;
647 647 info->flags = FE_INEXACT;
648 648 return;
649 649 }
650 650 info->op1.type = fex_ldouble;
651 651 info->op1.val.q = fpreg(uap, 0);
652 652 info->res.val.f = (float) info->op1.val.q;
653 653 goto done;
654 654
655 655 case 0x310:
656 656 case 0x318:
657 657 case 0x350:
658 658 case 0x358:
659 659 case 0x390:
660 660 case 0x398:
661 661 info->res.type = fex_int;
662 662 if (ex == FPE_FLTRES && (op & 8) != 0) {
663 663 /* inexact, stack popped */
664 664 if (!ea) {
665 665 info->op = fex_other;
666 666 info->op1.type = info->op2.type = info->res.type = fex_nodata;
667 667 info->flags = 0;
668 668 return;
669 669 }
670 670 info->op1.type = fex_nodata;
671 671 info->res.val.i = *(int *)ea;
672 672 info->flags = FE_INEXACT;
673 673 return;
674 674 }
675 675 info->op1.type = fex_ldouble;
676 676 info->op1.val.q = fpreg(uap, 0);
677 677 info->res.val.i = (int) info->op1.val.q;
678 678 goto done;
679 679
680 680 case 0x510:
681 681 case 0x518:
682 682 case 0x550:
683 683 case 0x558:
684 684 case 0x590:
685 685 case 0x598:
686 686 info->res.type = fex_double;
687 687 if (ex == FPE_FLTRES && (op & 8) != 0) {
688 688 /* inexact, stack popped */
689 689 if (!ea) {
690 690 info->op = fex_other;
691 691 info->op1.type = info->op2.type = info->res.type = fex_nodata;
692 692 info->flags = 0;
693 693 return;
694 694 }
695 695 info->op1.type = fex_nodata;
696 696 info->res.val.d = *(double *)ea;
697 697 info->flags = FE_INEXACT;
698 698 return;
699 699 }
700 700 info->op1.type = fex_ldouble;
701 701 info->op1.val.q = fpreg(uap, 0);
702 702 info->res.val.d = (double) info->op1.val.q;
703 703 goto done;
704 704
705 705 case 0x710:
706 706 case 0x718:
707 707 case 0x750:
708 708 case 0x758:
709 709 case 0x790:
710 710 case 0x798:
711 711 info->res.type = fex_int;
712 712 if (ex == FPE_FLTRES && (op & 8) != 0) {
713 713 /* inexact, stack popped */
714 714 if (!ea) {
715 715 info->op = fex_other;
716 716 info->op1.type = info->op2.type = info->res.type = fex_nodata;
717 717 info->flags = 0;
718 718 return;
719 719 }
720 720 info->op1.type = fex_nodata;
721 721 info->res.val.i = *(short *)ea;
722 722 info->flags = FE_INEXACT;
723 723 return;
724 724 }
725 725 info->op1.type = fex_ldouble;
726 726 info->op1.val.q = fpreg(uap, 0);
727 727 info->res.val.i = (short) info->op1.val.q;
728 728 goto done;
729 729
730 730 case 0x730:
731 731 case 0x770:
732 732 case 0x7b0:
733 733 /* fbstp; don't bother */
734 734 info->op = fex_other;
735 735 info->op1.type = info->res.type = fex_nodata;
736 736 info->flags = 0;
737 737 return;
738 738
739 739 case 0x738:
740 740 case 0x778:
741 741 case 0x7b8:
742 742 info->res.type = fex_llong;
743 743 if (ex == FPE_FLTRES) {
744 744 /* inexact, stack popped */
745 745 if (!ea) {
746 746 info->op = fex_other;
747 747 info->op1.type = info->op2.type = info->res.type = fex_nodata;
748 748 info->flags = 0;
749 749 return;
750 750 }
751 751 info->op1.type = fex_nodata;
752 752 info->res.val.l = *(long long *)ea;
753 753 info->flags = FE_INEXACT;
754 754 return;
755 755 }
756 756 info->op1.type = fex_ldouble;
757 757 info->op1.val.q = fpreg(uap, 0);
758 758 info->res.val.l = (long long) info->op1.val.q;
759 759 goto done;
760 760 }
761 761
762 762 /* all other ops (except compares) have destinations on the stack
763 763 so overflow, underflow, and inexact will stomp their operands */
764 764 if (ex == FPE_FLTOVF || ex == FPE_FLTUND || ex == FPE_FLTRES) {
765 765 /* find the trapped result */
766 766 info->op1.type = info->op2.type = fex_nodata;
767 767 info->res.type = fex_ldouble;
768 768 switch (op & 0x7f8) {
769 769 case 0x1f0:
770 770 /* fptan pushes 1.0 afterward, so result is in st(1) */
771 771 info->res.val.q = ((op == 0x1f2)? fpreg(uap, 1) :
772 772 fpreg(uap, 0));
773 773 break;
774 774
775 775 case 0x4c0:
776 776 case 0x4c8:
777 777 case 0x4e0:
778 778 case 0x4e8:
779 779 case 0x4f0:
780 780 case 0x4f8:
781 781 info->res.val.q = fpreg(uap, op & 7);
782 782 break;
783 783
784 784 case 0x6c0:
785 785 case 0x6c8:
786 786 case 0x6e0:
787 787 case 0x6e8:
788 788 case 0x6f0:
789 789 case 0x6f8:
790 790 /* stack was popped afterward */
791 791 info->res.val.q = fpreg(uap, (op - 1) & 7);
792 792 break;
793 793
794 794 default:
795 795 info->res.val.q = fpreg(uap, 0);
796 796 }
797 797
798 798 /* reconstruct default untrapped result */
799 799 if (ex == FPE_FLTOVF) {
800 800 /* generate an overflow with the sign of the result */
801 801 x = two12288;
802 802 *(4+(short*)&x) |= (*(4+(short*)&info->res.val.q) & 0x8000);
803 803 info->res.val.q = x * two12288;
804 804 info->flags = FE_OVERFLOW | FE_INEXACT;
805 805 __fenv_getcwsw(&cwsw);
806 806 cwsw &= ~FE_ALL_EXCEPT;
807 807 __fenv_setcwsw(&cwsw);
808 808 }
809 809 else if (ex == FPE_FLTUND) {
810 810 /* undo the scaling; we can't distinguish a chopped result
811 811 from an exact one without futzing around to trap all in-
812 812 exact exceptions so as to keep the flag clear, so we just
813 813 punt */
814 814 if (sw & 0x200) /* result was rounded up */
815 815 info->res.val.q = (info->res.val.q * twom12288) * twom12288mulp;
816 816 else
817 817 info->res.val.q = (info->res.val.q * twom12288) * twom12288;
818 818 __fenv_getcwsw(&cwsw);
819 819 info->flags = (cwsw & FE_INEXACT) | FE_UNDERFLOW;
820 820 cwsw &= ~FE_ALL_EXCEPT;
821 821 __fenv_setcwsw(&cwsw);
822 822 }
823 823 else
824 824 info->flags = FE_INEXACT;
825 825
826 826 /* determine the operation code */
827 827 switch (op) {
828 828 case 0x1f0: /* f2xm1 */
829 829 case 0x1f1: /* fyl2x */
830 830 case 0x1f2: /* fptan */
831 831 case 0x1f3: /* fpatan */
832 832 case 0x1f5: /* fprem1 */
833 833 case 0x1f8: /* fprem */
834 834 case 0x1f9: /* fyl2xp1 */
835 835 case 0x1fb: /* fsincos */
836 836 case 0x1fc: /* frndint */
837 837 case 0x1fd: /* fscale */
838 838 case 0x1fe: /* fsin */
839 839 case 0x1ff: /* fcos */
840 840 info->op = fex_other;
841 841 return;
842 842
843 843 case 0x1fa: /* fsqrt */
844 844 info->op = fex_sqrt;
845 845 return;
846 846 }
847 847
848 848 info->op = fex_other;
849 849 switch (op & 0x7c0) {
850 850 case 0x000:
851 851 case 0x040:
852 852 case 0x080:
853 853 case 0x0c0:
854 854 case 0x200:
855 855 case 0x240:
856 856 case 0x280:
857 857 case 0x400:
858 858 case 0x440:
859 859 case 0x480:
860 860 case 0x4c0:
861 861 case 0x600:
862 862 case 0x640:
863 863 case 0x680:
864 864 case 0x6c0:
865 865 switch (op & 0x38) {
866 866 case 0x00:
867 867 info->op = fex_add;
868 868 break;
869 869
870 870 case 0x08:
871 871 info->op = fex_mul;
872 872 break;
873 873
874 874 case 0x20:
875 875 case 0x28:
876 876 info->op = fex_sub;
877 877 break;
878 878
879 879 case 0x30:
880 880 case 0x38:
881 881 info->op = fex_div;
882 882 break;
883 883 }
884 884 }
885 885 return;
886 886 }
887 887
888 888 /* for other exceptions, the operands are preserved, so we can
889 889 just emulate the operation with traps disabled */
890 890
891 891 /* one operand is always in st */
892 892 info->op1.type = fex_ldouble;
893 893 info->op1.val.q = fpreg(uap, 0);
894 894
895 895 /* oddball instructions */
896 896 info->op = fex_other;
897 897 switch (op) {
898 898 case 0x1e4: /* ftst */
899 899 info->op = fex_cmp;
900 900 info->op2.type = fex_ldouble;
901 901 info->op2.val.q = 0.0l;
902 902 info->res.type = fex_nodata;
903 903 c = (info->op1.val.q < info->op2.val.q);
904 904 goto done;
905 905
906 906 case 0x1f0: /* f2xm1 */
907 907 info->res.type = fex_ldouble;
908 908 info->res.val.q = f2xm1(info->op1.val.q);
909 909 goto done;
910 910
911 911 case 0x1f1: /* fyl2x */
912 912 info->op2.type = fex_ldouble;
913 913 info->op2.val.q = fpreg(uap, 1);
914 914 info->res.type = fex_ldouble;
915 915 info->res.val.q = fyl2x(info->op1.val.q, info->op2.val.q);
916 916 goto done;
917 917
918 918 case 0x1f2: /* fptan */
919 919 info->res.type = fex_ldouble;
920 920 info->res.val.q = fptan(info->op1.val.q);
921 921 goto done;
922 922
923 923 case 0x1f3: /* fpatan */
924 924 info->op2.type = fex_ldouble;
925 925 info->op2.val.q = fpreg(uap, 1);
926 926 info->res.type = fex_ldouble;
927 927 info->res.val.q = fpatan(info->op1.val.q, info->op2.val.q);
928 928 goto done;
929 929
930 930 case 0x1f4: /* fxtract */
931 931 info->res.type = fex_ldouble;
932 932 info->res.val.q = fxtract(info->op1.val.q);
933 933 goto done;
934 934
935 935 case 0x1f5: /* fprem1 */
936 936 info->op2.type = fex_ldouble;
937 937 info->op2.val.q = fpreg(uap, 1);
938 938 info->res.type = fex_ldouble;
939 939 info->res.val.q = fprem1(info->op1.val.q, info->op2.val.q);
940 940 goto done;
941 941
942 942 case 0x1f8: /* fprem */
943 943 info->op2.type = fex_ldouble;
944 944 info->op2.val.q = fpreg(uap, 1);
945 945 info->res.type = fex_ldouble;
946 946 info->res.val.q = fprem(info->op1.val.q, info->op2.val.q);
947 947 goto done;
948 948
949 949 case 0x1f9: /* fyl2xp1 */
950 950 info->op2.type = fex_ldouble;
951 951 info->op2.val.q = fpreg(uap, 1);
952 952 info->res.type = fex_ldouble;
953 953 info->res.val.q = fyl2xp1(info->op1.val.q, info->op2.val.q);
954 954 goto done;
955 955
956 956 case 0x1fa: /* fsqrt */
957 957 info->op = fex_sqrt;
958 958 info->res.type = fex_ldouble;
959 959 info->res.val.q = fsqrt(info->op1.val.q);
960 960 goto done;
961 961
962 962 case 0x1fb: /* fsincos */
963 963 info->res.type = fex_ldouble;
964 964 info->res.val.q = fsincos(info->op1.val.q);
965 965 goto done;
966 966
967 967 case 0x1fc: /* frndint */
968 968 info->res.type = fex_ldouble;
969 969 info->res.val.q = frndint(info->op1.val.q);
970 970 goto done;
971 971
972 972 case 0x1fd: /* fscale */
973 973 info->op2.type = fex_ldouble;
974 974 info->op2.val.q = fpreg(uap, 1);
975 975 info->res.type = fex_ldouble;
976 976 info->res.val.q = fscale(info->op1.val.q, info->op2.val.q);
977 977 goto done;
978 978
979 979 case 0x1fe: /* fsin */
980 980 info->res.type = fex_ldouble;
981 981 info->res.val.q = fsin(info->op1.val.q);
982 982 goto done;
983 983
984 984 case 0x1ff: /* fcos */
985 985 info->res.type = fex_ldouble;
986 986 info->res.val.q = fcos(info->op1.val.q);
987 987 goto done;
988 988
989 989 case 0x2e9: /* fucompp */
990 990 info->op = fex_cmp;
991 991 info->op2.type = fex_ldouble;
992 992 info->op2.val.q = fpreg(uap, 1);
993 993 info->res.type = fex_nodata;
994 994 c = (info->op1.val.q == info->op2.val.q);
995 995 goto done;
996 996 }
997 997
998 998 /* fucom[p], fcomi[p], fucomi[p] */
999 999 switch (op & 0x7f8) {
1000 1000 case 0x3e8:
1001 1001 case 0x5e0:
1002 1002 case 0x5e8:
1003 1003 case 0x7e8: /* unordered compares */
1004 1004 info->op = fex_cmp;
1005 1005 info->op2.type = fex_ldouble;
1006 1006 info->op2.val.q = fpreg(uap, op & 7);
1007 1007 info->res.type = fex_nodata;
1008 1008 c = (info->op1.val.q == info->op2.val.q);
1009 1009 goto done;
1010 1010
1011 1011 case 0x3f0:
1012 1012 case 0x7f0: /* ordered compares */
1013 1013 info->op = fex_cmp;
1014 1014 info->op2.type = fex_ldouble;
1015 1015 info->op2.val.q = fpreg(uap, op & 7);
1016 1016 info->res.type = fex_nodata;
1017 1017 c = (info->op1.val.q < info->op2.val.q);
1018 1018 goto done;
1019 1019 }
1020 1020
1021 1021 /* all other instructions come in groups of the form
1022 1022 fadd, fmul, fcom, fcomp, fsub, fsubr, fdiv, fdivr */
1023 1023
1024 1024 /* get the second operand */
1025 1025 switch (op & 0x7c0) {
1026 1026 case 0x000:
1027 1027 case 0x040:
1028 1028 case 0x080:
1029 1029 if (!ea) {
1030 1030 info->op = fex_other;
1031 1031 info->op1.type = info->op2.type = info->res.type = fex_nodata;
1032 1032 info->flags = 0;
1033 1033 return;
1034 1034 }
1035 1035 info->op2.type = fex_float;
1036 1036 info->op2.val.f = *(float *)ea;
1037 1037 op2v = (long double) info->op2.val.f;
1038 1038 break;
1039 1039
1040 1040 case 0x0c0:
1041 1041 info->op2.type = fex_ldouble;
1042 1042 op2v = info->op2.val.q = fpreg(uap, op & 7);
1043 1043 break;
1044 1044
1045 1045 case 0x200:
1046 1046 case 0x240:
1047 1047 case 0x280:
1048 1048 if (!ea) {
1049 1049 info->op = fex_other;
1050 1050 info->op1.type = info->op2.type = info->res.type = fex_nodata;
1051 1051 info->flags = 0;
1052 1052 return;
1053 1053 }
1054 1054 info->op2.type = fex_int;
1055 1055 info->op2.val.i = *(int *)ea;
1056 1056 op2v = (long double) info->op2.val.i;
1057 1057 break;
1058 1058
1059 1059 case 0x400:
1060 1060 case 0x440:
1061 1061 case 0x480:
1062 1062 if (!ea) {
1063 1063 info->op = fex_other;
1064 1064 info->op1.type = info->op2.type = info->res.type = fex_nodata;
1065 1065 info->flags = 0;
1066 1066 return;
1067 1067 }
1068 1068 info->op2.type = fex_double;
1069 1069 info->op2.val.d = *(double *)ea;
1070 1070 op2v = (long double) info->op2.val.d;
1071 1071 break;
1072 1072
1073 1073 case 0x4c0:
1074 1074 case 0x6c0:
1075 1075 info->op2.type = fex_ldouble;
1076 1076 info->op2.val.q = fpreg(uap, op & 7);
1077 1077 t = info->op1;
1078 1078 info->op1 = info->op2;
1079 1079 info->op2 = t;
1080 1080 op2v = info->op2.val.q;
1081 1081 break;
1082 1082
1083 1083 case 0x600:
1084 1084 case 0x640:
1085 1085 case 0x680:
1086 1086 if (!ea) {
1087 1087 info->op = fex_other;
1088 1088 info->op1.type = info->op2.type = info->res.type = fex_nodata;
1089 1089 info->flags = 0;
1090 1090 return;
1091 1091 }
1092 1092 info->op2.type = fex_int;
1093 1093 info->op2.val.i = *(short *)ea;
1094 1094 op2v = (long double) info->op2.val.i;
1095 1095 break;
1096 1096
1097 1097 default:
1098 1098 info->op = fex_other;
1099 1099 info->op1.type = info->op2.type = info->res.type = fex_nodata;
1100 1100 info->flags = 0;
1101 1101 return;
1102 1102 }
1103 1103
1104 1104 /* distinguish different operations in the group */
1105 1105 info->res.type = fex_ldouble;
1106 1106 switch (op & 0x38) {
1107 1107 case 0x00:
1108 1108 info->op = fex_add;
1109 1109 info->res.val.q = info->op1.val.q + op2v;
1110 1110 break;
1111 1111
1112 1112 case 0x08:
1113 1113 info->op = fex_mul;
1114 1114 info->res.val.q = info->op1.val.q * op2v;
1115 1115 break;
1116 1116
1117 1117 case 0x10:
1118 1118 case 0x18:
1119 1119 info->op = fex_cmp;
1120 1120 info->res.type = fex_nodata;
1121 1121 c = (info->op1.val.q < op2v);
1122 1122 break;
1123 1123
1124 1124 case 0x20:
1125 1125 info->op = fex_sub;
1126 1126 info->res.val.q = info->op1.val.q - op2v;
1127 1127 break;
1128 1128
1129 1129 case 0x28:
1130 1130 info->op = fex_sub;
1131 1131 info->res.val.q = op2v - info->op1.val.q;
1132 1132 t = info->op1;
1133 1133 info->op1 = info->op2;
1134 1134 info->op2 = t;
1135 1135 break;
1136 1136
1137 1137 case 0x30:
1138 1138 info->op = fex_div;
1139 1139 info->res.val.q = info->op1.val.q / op2v;
1140 1140 break;
1141 1141
1142 1142 case 0x38:
1143 1143 info->op = fex_div;
1144 1144 info->res.val.q = op2v / info->op1.val.q;
1145 1145 t = info->op1;
1146 1146 info->op1 = info->op2;
1147 1147 info->op2 = t;
1148 1148 break;
1149 1149
1150 1150 default:
1151 1151 info->op = fex_other;
1152 1152 info->op1.type = info->op2.type = info->res.type = fex_nodata;
1153 1153 info->flags = 0;
1154 1154 return;
1155 1155 }
1156 1156
1157 1157 done:
1158 1158 __fenv_getcwsw(&cwsw);
1159 1159 info->flags = cwsw & FE_ALL_EXCEPT;
1160 1160 cwsw &= ~FE_ALL_EXCEPT;
1161 1161 __fenv_setcwsw(&cwsw);
1162 1162 }
1163 1163
1164 1164 /* pop the saved stack */
1165 1165 static void pop(ucontext_t *uap)
1166 1166 {
1167 1167 unsigned top;
1168 1168
1169 1169 fpreg(uap, 0) = fpreg(uap, 1);
1170 1170 fpreg(uap, 1) = fpreg(uap, 2);
1171 1171 fpreg(uap, 2) = fpreg(uap, 3);
1172 1172 fpreg(uap, 3) = fpreg(uap, 4);
1173 1173 fpreg(uap, 4) = fpreg(uap, 5);
1174 1174 fpreg(uap, 5) = fpreg(uap, 6);
1175 1175 fpreg(uap, 6) = fpreg(uap, 7);
1176 1176 #if defined(__amd64)
1177 1177 top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw >> 10)
1178 1178 & 0xe;
1179 1179 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fctw |= (3 << top);
1180 1180 top = (top + 2) & 0xe;
1181 1181 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw =
1182 1182 (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw & ~0x3800)
1183 1183 | (top << 10);
1184 1184 #else
1185 1185 top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] >> 10)
1186 1186 & 0xe;
1187 1187 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[TW] |= (3 << top);
1188 1188 top = (top + 2) & 0xe;
1189 1189 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] =
1190 1190 (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] & ~0x3800)
1191 1191 | (top << 10);
1192 1192 #endif
1193 1193 }
1194 1194
1195 1195 /* push x onto the saved stack */
1196 1196 static void push(long double x, ucontext_t *uap)
1197 1197 {
1198 1198 unsigned top;
1199 1199
1200 1200 fpreg(uap, 7) = fpreg(uap, 6);
1201 1201 fpreg(uap, 6) = fpreg(uap, 5);
1202 1202 fpreg(uap, 5) = fpreg(uap, 4);
1203 1203 fpreg(uap, 4) = fpreg(uap, 3);
1204 1204 fpreg(uap, 3) = fpreg(uap, 2);
1205 1205 fpreg(uap, 2) = fpreg(uap, 1);
1206 1206 fpreg(uap, 1) = fpreg(uap, 0);
1207 1207 fpreg(uap, 0) = x;
1208 1208 #if defined(__amd64)
1209 1209 top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw >> 10)
1210 1210 & 0xe;
1211 1211 top = (top - 2) & 0xe;
1212 1212 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fctw &= ~(3 << top);
1213 1213 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw =
1214 1214 (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw & ~0x3800)
1215 1215 | (top << 10);
1216 1216 #else
1217 1217 top = (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] >> 10)
1218 1218 & 0xe;
1219 1219 top = (top - 2) & 0xe;
1220 1220 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[TW] &= ~(3 << top);
1221 1221 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] =
1222 1222 (uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] & ~0x3800)
1223 1223 | (top << 10);
1224 1224 #endif
1225 1225 }
1226 1226
1227 1227 /* scale factors for exponent wrapping */
1228 1228 static const float
1229 1229 fun = 7.922816251e+28f, /* 2^96 */
1230 1230 fov = 1.262177448e-29f; /* 2^-96 */
1231 1231 static const double
1232 1232 dun = 1.552518092300708935e+231, /* 2^768 */
1233 1233 dov = 6.441148769597133308e-232; /* 2^-768 */
1234 1234
1235 1235 /*
1236 1236 * Store the specified result; if no result is given but the exception
1237 1237 * is underflow or overflow, use the default trapped result
1238 1238 */
1239 1239 void
1240 1240 __fex_st_result(siginfo_t *sip, ucontext_t *uap, fex_info_t *info)
1241 1241 {
1242 1242 fex_numeric_t r;
1243 1243 unsigned long ex, op, ea, stack;
1244 1244
1245 1245 /* get the exception type, opcode, and data address */
1246 1246 ex = sip->si_code;
1247 1247 #if defined(__amd64)
1248 1248 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.fop >> 16;
1249 1249 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.rdp; /*???*/
1250 1250 #else
1251 1251 op = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[OP] >> 16;
1252 1252 ea = uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[EA];
1253 1253 #endif
1254 1254
1255 1255 /* if the instruction is a compare, set the condition codes
1256 1256 to unordered and update the stack */
1257 1257 switch (op & 0x7f8) {
1258 1258 case 0x010:
1259 1259 case 0x050:
1260 1260 case 0x090:
1261 1261 case 0x0d0:
1262 1262 case 0x210:
1263 1263 case 0x250:
1264 1264 case 0x290:
1265 1265 case 0x410:
1266 1266 case 0x450:
1267 1267 case 0x490:
1268 1268 case 0x4d0:
1269 1269 case 0x5e0:
1270 1270 case 0x610:
1271 1271 case 0x650:
1272 1272 case 0x690:
1273 1273 /* f[u]com */
1274 1274 #if defined(__amd64)
1275 1275 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
1276 1276 #else
1277 1277 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |= 0x4500;
1278 1278 #endif
1279 1279 return;
1280 1280
1281 1281 case 0x018:
1282 1282 case 0x058:
1283 1283 case 0x098:
1284 1284 case 0x0d8:
1285 1285 case 0x218:
1286 1286 case 0x258:
1287 1287 case 0x298:
1288 1288 case 0x418:
1289 1289 case 0x458:
1290 1290 case 0x498:
1291 1291 case 0x4d8:
1292 1292 case 0x5e8:
1293 1293 case 0x618:
1294 1294 case 0x658:
1295 1295 case 0x698:
1296 1296 case 0x6d0:
1297 1297 /* f[u]comp */
1298 1298 #if defined(__amd64)
1299 1299 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
1300 1300 #else
1301 1301 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |= 0x4500;
1302 1302 #endif
1303 1303 pop(uap);
1304 1304 return;
1305 1305
1306 1306 case 0x2e8:
1307 1307 case 0x6d8:
1308 1308 /* f[u]compp */
1309 1309 #if defined(__amd64)
1310 1310 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
1311 1311 #else
1312 1312 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |= 0x4500;
1313 1313 #endif
1314 1314 pop(uap);
1315 1315 pop(uap);
1316 1316 return;
1317 1317
1318 1318 case 0x1e0:
1319 1319 if (op == 0x1e4) { /* ftst */
1320 1320 #if defined(__amd64)
1321 1321 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.sw |= 0x4500;
1322 1322 #else
1323 1323 uap->uc_mcontext.fpregs.fp_reg_set.fpchip_state.state[SW] |= 0x4500;
1324 1324 #endif
1325 1325 return;
1326 1326 }
1327 1327 break;
1328 1328
1329 1329 case 0x3e8:
1330 1330 case 0x3f0:
1331 1331 /* f[u]comi */
1332 1332 #if defined(__amd64)
1333 1333 uap->uc_mcontext.gregs[REG_PS] |= 0x45;
1334 1334 #else
1335 1335 uap->uc_mcontext.gregs[EFL] |= 0x45;
1336 1336 #endif
1337 1337 return;
1338 1338
1339 1339 case 0x7e8:
1340 1340 case 0x7f0:
1341 1341 /* f[u]comip */
1342 1342 #if defined(__amd64)
1343 1343 uap->uc_mcontext.gregs[REG_PS] |= 0x45;
1344 1344 #else
1345 1345 uap->uc_mcontext.gregs[EFL] |= 0x45;
1346 1346 #endif
1347 1347 pop(uap);
1348 1348 return;
1349 1349 }
1350 1350
1351 1351 /* if there is no result available and the exception is overflow
1352 1352 or underflow, use the wrapped result */
1353 1353 r = info->res;
1354 1354 if (r.type == fex_nodata) {
1355 1355 if (ex == FPE_FLTOVF || ex == FPE_FLTUND) {
1356 1356 /* for store instructions, do the scaling and store */
1357 1357 switch (op & 0x7f8) {
1358 1358 case 0x110:
1359 1359 case 0x118:
1360 1360 case 0x150:
1361 1361 case 0x158:
1362 1362 case 0x190:
1363 1363 case 0x198:
1364 1364 if (!ea)
1365 1365 return;
1366 1366 if (ex == FPE_FLTOVF)
1367 1367 *(float *)ea = (fpreg(uap, 0) * fov) * fov;
1368 1368 else
1369 1369 *(float *)ea = (fpreg(uap, 0) * fun) * fun;
1370 1370 if ((op & 8) != 0)
1371 1371 pop(uap);
1372 1372 break;
1373 1373
1374 1374 case 0x510:
1375 1375 case 0x518:
1376 1376 case 0x550:
1377 1377 case 0x558:
1378 1378 case 0x590:
1379 1379 case 0x598:
1380 1380 if (!ea)
1381 1381 return;
1382 1382 if (ex == FPE_FLTOVF)
1383 1383 *(double *)ea = (fpreg(uap, 0) * dov) * dov;
1384 1384 else
1385 1385 *(double *)ea = (fpreg(uap, 0) * dun) * dun;
1386 1386 if ((op & 8) != 0)
1387 1387 pop(uap);
1388 1388 break;
1389 1389 }
1390 1390 }
1391 1391 #ifdef DEBUG
1392 1392 else if (ex != FPE_FLTRES)
1393 1393 printf( "No result supplied, stack may be hosed\n" );
1394 1394 #endif
1395 1395 return;
1396 1396 }
1397 1397
1398 1398 /* otherwise convert the supplied result to the correct type,
1399 1399 put it in the destination, and update the stack as need be */
1400 1400
1401 1401 /* store instructions */
1402 1402 switch (op & 0x7f8) {
1403 1403 case 0x110:
1404 1404 case 0x118:
1405 1405 case 0x150:
1406 1406 case 0x158:
1407 1407 case 0x190:
1408 1408 case 0x198:
1409 1409 if (!ea)
1410 1410 return;
1411 1411 switch (r.type) {
1412 1412 case fex_int:
1413 1413 *(float *)ea = (float) r.val.i;
1414 1414 break;
1415 1415
1416 1416 case fex_llong:
1417 1417 *(float *)ea = (float) r.val.l;
1418 1418 break;
1419 1419
1420 1420 case fex_float:
↓ open down ↓ |
1420 lines elided |
↑ open up ↑ |
1421 1421 *(float *)ea = r.val.f;
1422 1422 break;
1423 1423
1424 1424 case fex_double:
1425 1425 *(float *)ea = (float) r.val.d;
1426 1426 break;
1427 1427
1428 1428 case fex_ldouble:
1429 1429 *(float *)ea = (float) r.val.q;
1430 1430 break;
1431 +
1432 + default:
1433 + break;
1431 1434 }
1432 1435 if (ex != FPE_FLTRES && (op & 8) != 0)
1433 1436 pop(uap);
1434 1437 return;
1435 1438
1436 1439 case 0x310:
1437 1440 case 0x318:
1438 1441 case 0x350:
1439 1442 case 0x358:
1440 1443 case 0x390:
1441 1444 case 0x398:
1442 1445 if (!ea)
1443 1446 return;
1444 1447 switch (r.type) {
1445 1448 case fex_int:
1446 1449 *(int *)ea = r.val.i;
1447 1450 break;
1448 1451
1449 1452 case fex_llong:
1450 1453 *(int *)ea = (int) r.val.l;
1451 1454 break;
1452 1455
1453 1456 case fex_float:
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
1454 1457 *(int *)ea = (int) r.val.f;
1455 1458 break;
1456 1459
1457 1460 case fex_double:
1458 1461 *(int *)ea = (int) r.val.d;
1459 1462 break;
1460 1463
1461 1464 case fex_ldouble:
1462 1465 *(int *)ea = (int) r.val.q;
1463 1466 break;
1467 +
1468 + default:
1469 + break;
1464 1470 }
1465 1471 if (ex != FPE_FLTRES && (op & 8) != 0)
1466 1472 pop(uap);
1467 1473 return;
1468 1474
1469 1475 case 0x510:
1470 1476 case 0x518:
1471 1477 case 0x550:
1472 1478 case 0x558:
1473 1479 case 0x590:
1474 1480 case 0x598:
1475 1481 if (!ea)
1476 1482 return;
1477 1483 switch (r.type) {
1478 1484 case fex_int:
1479 1485 *(double *)ea = (double) r.val.i;
1480 1486 break;
1481 1487
1482 1488 case fex_llong:
1483 1489 *(double *)ea = (double) r.val.l;
1484 1490 break;
1485 1491
1486 1492 case fex_float:
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
1487 1493 *(double *)ea = (double) r.val.f;
1488 1494 break;
1489 1495
1490 1496 case fex_double:
1491 1497 *(double *)ea = r.val.d;
1492 1498 break;
1493 1499
1494 1500 case fex_ldouble:
1495 1501 *(double *)ea = (double) r.val.q;
1496 1502 break;
1503 +
1504 + default:
1505 + break;
1497 1506 }
1498 1507 if (ex != FPE_FLTRES && (op & 8) != 0)
1499 1508 pop(uap);
1500 1509 return;
1501 1510
1502 1511 case 0x710:
1503 1512 case 0x718:
1504 1513 case 0x750:
1505 1514 case 0x758:
1506 1515 case 0x790:
1507 1516 case 0x798:
1508 1517 if (!ea)
1509 1518 return;
1510 1519 switch (r.type) {
1511 1520 case fex_int:
1512 1521 *(short *)ea = (short) r.val.i;
1513 1522 break;
1514 1523
1515 1524 case fex_llong:
1516 1525 *(short *)ea = (short) r.val.l;
1517 1526 break;
1518 1527
1519 1528 case fex_float:
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
1520 1529 *(short *)ea = (short) r.val.f;
1521 1530 break;
1522 1531
1523 1532 case fex_double:
1524 1533 *(short *)ea = (short) r.val.d;
1525 1534 break;
1526 1535
1527 1536 case fex_ldouble:
1528 1537 *(short *)ea = (short) r.val.q;
1529 1538 break;
1539 +
1540 + default:
1541 + break;
1530 1542 }
1531 1543 if (ex != FPE_FLTRES && (op & 8) != 0)
1532 1544 pop(uap);
1533 1545 return;
1534 1546
1535 1547 case 0x730:
1536 1548 case 0x770:
1537 1549 case 0x7b0:
1538 1550 /* fbstp; don't bother */
1539 1551 if (ea && ex != FPE_FLTRES)
1540 1552 pop(uap);
1541 1553 return;
1542 1554
1543 1555 case 0x738:
1544 1556 case 0x778:
1545 1557 case 0x7b8:
1546 1558 if (!ea)
1547 1559 return;
1548 1560 switch (r.type) {
1549 1561 case fex_int:
1550 1562 *(long long *)ea = (long long) r.val.i;
1551 1563 break;
1552 1564
1553 1565 case fex_llong:
1554 1566 *(long long *)ea = r.val.l;
1555 1567 break;
1556 1568
1557 1569 case fex_float:
↓ open down ↓ |
18 lines elided |
↑ open up ↑ |
1558 1570 *(long long *)ea = (long long) r.val.f;
1559 1571 break;
1560 1572
1561 1573 case fex_double:
1562 1574 *(long long *)ea = (long long) r.val.d;
1563 1575 break;
1564 1576
1565 1577 case fex_ldouble:
1566 1578 *(long long *)ea = (long long) r.val.q;
1567 1579 break;
1580 +
1581 + default:
1582 + break;
1568 1583 }
1569 1584 if (ex != FPE_FLTRES)
1570 1585 pop(uap);
1571 1586 return;
1572 1587 }
1573 1588
1574 1589 /* for all other instructions, the result goes into a register */
1575 1590 switch (r.type) {
1576 1591 case fex_int:
1577 1592 r.val.q = (long double) r.val.i;
1578 1593 break;
1579 1594
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
1580 1595 case fex_llong:
1581 1596 r.val.q = (long double) r.val.l;
1582 1597 break;
1583 1598
1584 1599 case fex_float:
1585 1600 r.val.q = (long double) r.val.f;
1586 1601 break;
1587 1602
1588 1603 case fex_double:
1589 1604 r.val.q = (long double) r.val.d;
1605 + break;
1606 +
1607 + default:
1590 1608 break;
1591 1609 }
1592 1610
1593 1611 /* for load instructions, push the result onto the stack */
1594 1612 switch (op & 0x7f8) {
1595 1613 case 0x100:
1596 1614 case 0x140:
1597 1615 case 0x180:
1598 1616 case 0x500:
1599 1617 case 0x540:
1600 1618 case 0x580:
1601 1619 if (ea)
1602 1620 push(r.val.q, uap);
1603 1621 return;
1604 1622 }
1605 1623
1606 1624 /* for all other instructions, if the exception is overflow,
1607 1625 underflow, or inexact, the stack has already been updated */
1608 1626 stack = (ex == FPE_FLTOVF || ex == FPE_FLTUND || ex == FPE_FLTRES);
1609 1627 switch (op & 0x7f8) {
1610 1628 case 0x1f0: /* oddballs */
1611 1629 switch (op) {
1612 1630 case 0x1f1: /* fyl2x */
1613 1631 case 0x1f3: /* fpatan */
1614 1632 case 0x1f9: /* fyl2xp1 */
1615 1633 /* pop the stack, leaving the result in st */
1616 1634 if (!stack)
1617 1635 pop(uap);
1618 1636 fpreg(uap, 0) = r.val.q;
1619 1637 return;
1620 1638
1621 1639 case 0x1f2: /* fpatan */
1622 1640 /* fptan pushes 1.0 afterward */
1623 1641 if (stack)
1624 1642 fpreg(uap, 1) = r.val.q;
1625 1643 else {
1626 1644 fpreg(uap, 0) = r.val.q;
1627 1645 push(1.0L, uap);
1628 1646 }
1629 1647 return;
1630 1648
1631 1649 case 0x1f4: /* fxtract */
1632 1650 case 0x1fb: /* fsincos */
1633 1651 /* leave the supplied result in st */
1634 1652 if (stack)
1635 1653 fpreg(uap, 0) = r.val.q;
1636 1654 else {
1637 1655 fpreg(uap, 0) = 0.0; /* punt */
1638 1656 push(r.val.q, uap);
1639 1657 }
1640 1658 return;
1641 1659 }
1642 1660
1643 1661 /* all others leave the stack alone and the result in st */
1644 1662 fpreg(uap, 0) = r.val.q;
1645 1663 return;
1646 1664
1647 1665 case 0x4c0:
1648 1666 case 0x4c8:
1649 1667 case 0x4e0:
1650 1668 case 0x4e8:
1651 1669 case 0x4f0:
1652 1670 case 0x4f8:
1653 1671 fpreg(uap, op & 7) = r.val.q;
1654 1672 return;
1655 1673
1656 1674 case 0x6c0:
1657 1675 case 0x6c8:
1658 1676 case 0x6e0:
1659 1677 case 0x6e8:
1660 1678 case 0x6f0:
1661 1679 case 0x6f8:
1662 1680 /* stack is popped afterward */
1663 1681 if (stack)
1664 1682 fpreg(uap, (op - 1) & 7) = r.val.q;
1665 1683 else {
1666 1684 fpreg(uap, op & 7) = r.val.q;
1667 1685 pop(uap);
1668 1686 }
1669 1687 return;
1670 1688
1671 1689 default:
1672 1690 fpreg(uap, 0) = r.val.q;
1673 1691 return;
1674 1692 }
1675 1693 }
↓ open down ↓ |
76 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX