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