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