1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2011, Richard Lowe 14 */ 15 16 #ifndef _FENV_INLINES_H 17 #define _FENV_INLINES_H 18 19 #ifdef __GNUC__ 20 21 #ifdef __cplusplus 22 extern "C" { 23 #endif 24 25 #include <sys/types.h> 26 27 #if defined(__x86) 28 29 /* 30 * Floating point Control Word and Status Word 31 * Definition should actually be shared with x86 32 * (much of this 'amd64' code can be, in fact.) 33 */ 34 union fp_cwsw { 35 uint32_t cwsw; 36 struct { 37 uint16_t cw; 38 uint16_t sw; 39 } words; 40 }; 41 42 extern __GNU_INLINE void 43 __fenv_getcwsw(unsigned int *value) 44 { 45 union fp_cwsw *u = (union fp_cwsw *)value; 46 47 __asm__ __volatile__( 48 "fstsw %0\n\t" 49 "fstcw %1\n\t" 50 : "=m" (u->words.cw), "=m" (u->words.sw)); 51 } 52 53 extern __GNU_INLINE void 54 __fenv_setcwsw(const unsigned int *value) 55 { 56 union fp_cwsw cwsw; 57 short fenv[16]; 58 59 cwsw.cwsw = *value; 60 61 __asm__ __volatile__( 62 "fstenv %0\n\t" 63 "movw %4,%1\n\t" 64 "movw %3,%2\n\t" 65 "fldenv %0\n\t" 66 "fwait\n\t" 67 : "=m" (fenv), "=m" (fenv[0]), "=m" (fenv[2]) 68 : "r" (cwsw.words.cw), "r" (cwsw.words.sw) 69 /* For practical purposes, we clobber the whole FPU */ 70 : "cc", "st", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", 71 "st(6)", "st(7)"); 72 } 73 74 extern __GNU_INLINE void 75 __fenv_getmxcsr(unsigned int *value) 76 { 77 __asm__ __volatile__("stmxcsr %0" : "=m" (*value)); 78 } 79 80 extern __GNU_INLINE void 81 __fenv_setmxcsr(const unsigned int *value) 82 { 83 __asm__ __volatile__("ldmxcsr %0" : : "m" (*value)); 84 } 85 86 extern __GNU_INLINE long double 87 f2xm1(long double x) 88 { 89 long double ret; 90 91 __asm__ __volatile__("f2xm1" : "=t" (ret) : "0" (x) : "cc"); 92 return (ret); 93 } 94 95 extern __GNU_INLINE long double 96 fyl2x(long double y, long double x) 97 { 98 long double ret; 99 100 __asm__ __volatile__("fyl2x" 101 : "=t" (ret) 102 : "0" (x), "u" (y) 103 : "st(1)", "cc"); 104 return (ret); 105 } 106 107 extern __GNU_INLINE long double 108 fptan(long double x) 109 { 110 /* 111 * fptan pushes 1.0 then the result on completion, so we want to pop 112 * the FP stack twice, so we need a dummy value into which to pop it. 113 */ 114 long double ret; 115 long double dummy; 116 117 __asm__ __volatile__("fptan" 118 : "=t" (dummy), "=u" (ret) 119 : "0" (x) 120 : "cc"); 121 return (ret); 122 } 123 124 extern __GNU_INLINE long double 125 fpatan(long double x, long double y) 126 { 127 long double ret; 128 129 __asm__ __volatile__("fpatan" 130 : "=t" (ret) 131 : "0" (y), "u" (x) 132 : "st(1)", "cc"); 133 return (ret); 134 } 135 136 extern __GNU_INLINE long double 137 fxtract(long double x) 138 { 139 __asm__ __volatile__("fxtract" : "+t" (x) : : "cc"); 140 return (x); 141 } 142 143 extern __GNU_INLINE long double 144 fprem1(long double idend, long double div) 145 { 146 __asm__ __volatile__("fprem1" : "+t" (div) : "u" (idend) : "cc"); 147 return (div); 148 } 149 150 extern __GNU_INLINE long double 151 fprem(long double idend, long double div) 152 { 153 __asm__ __volatile__("fprem" : "+t" (div) : "u" (idend) : "cc"); 154 return (div); 155 } 156 157 extern __GNU_INLINE long double 158 fyl2xp1(long double y, long double x) 159 { 160 long double ret; 161 162 __asm__ __volatile__("fyl2xp1" 163 : "=t" (ret) 164 : "0" (x), "u" (y) 165 : "st(1)", "cc"); 166 return (ret); 167 } 168 169 extern __GNU_INLINE long double 170 fsqrt(long double x) 171 { 172 __asm__ __volatile__("fsqrt" : "+t" (x) : : "cc"); 173 return (x); 174 } 175 176 extern __GNU_INLINE long double 177 fsincos(long double x) 178 { 179 long double dummy; 180 181 __asm__ __volatile__("fsincos" : "+t" (x), "=u" (dummy) : : "cc"); 182 return (x); 183 } 184 185 extern __GNU_INLINE long double 186 frndint(long double x) 187 { 188 __asm__ __volatile__("frndint" : "+t" (x) : : "cc"); 189 return (x); 190 } 191 192 extern __GNU_INLINE long double 193 fscale(long double x, long double y) 194 { 195 long double ret; 196 197 __asm__ __volatile__("fscale" : "=t" (ret) : "0" (y), "u" (x) : "cc"); 198 return (ret); 199 } 200 201 extern __GNU_INLINE long double 202 fsin(long double x) 203 { 204 __asm__ __volatile__("fsin" : "+t" (x) : : "cc"); 205 return (x); 206 } 207 208 extern __GNU_INLINE long double 209 fcos(long double x) 210 { 211 __asm__ __volatile__("fcos" : "+t" (x) : : "cc"); 212 return (x); 213 } 214 215 extern __GNU_INLINE void 216 sse_cmpeqss(float *f1, float *f2, int *i1) 217 { 218 __asm__ __volatile__( 219 "cmpeqss %2, %1\n\t" 220 "movss %1, %0" 221 : "=m" (*i1), "+x" (*f1) 222 : "x" (*f2) 223 : "cc"); 224 } 225 226 extern __GNU_INLINE void 227 sse_cmpltss(float *f1, float *f2, int *i1) 228 { 229 __asm__ __volatile__( 230 "cmpltss %2, %1\n\t" 231 "movss %1, %0" 232 : "=m" (*i1), "+x" (*f1) 233 : "x" (*f2) 234 : "cc"); 235 } 236 237 extern __GNU_INLINE void 238 sse_cmpless(float *f1, float *f2, int *i1) 239 { 240 __asm__ __volatile__( 241 "cmpless %2, %1\n\t" 242 "movss %1, %0" 243 : "=m" (*i1), "+x" (*f1) 244 : "x" (*f2) 245 : "cc"); 246 } 247 248 extern __GNU_INLINE void 249 sse_cmpunordss(float *f1, float *f2, int *i1) 250 { 251 __asm__ __volatile__( 252 "cmpunordss %2, %1\n\t" 253 "movss %1, %0" 254 : "=m" (*i1), "+x" (*f1) 255 : "x" (*f2) 256 : "cc"); 257 } 258 259 extern __GNU_INLINE void 260 sse_minss(float *f1, float *f2, float *f3) 261 { 262 __asm__ __volatile__( 263 "minss %2, %1\n\t" 264 "movss %1, %0" 265 : "=m" (*f3), "+x" (*f1) 266 : "x" (*f2)); 267 } 268 269 extern __GNU_INLINE void 270 sse_maxss(float *f1, float *f2, float *f3) 271 { 272 __asm__ __volatile__( 273 "maxss %2, %1\n\t" 274 "movss %1, %0" 275 : "=m" (*f3), "+x" (*f1) 276 : "x" (*f2)); 277 } 278 279 extern __GNU_INLINE void 280 sse_addss(float *f1, float *f2, float *f3) 281 { 282 __asm__ __volatile__( 283 "addss %2, %1\n\t" 284 "movss %1, %0" 285 : "=m" (*f3), "+x" (*f1) 286 : "x" (*f2)); 287 } 288 289 extern __GNU_INLINE void 290 sse_subss(float *f1, float *f2, float *f3) 291 { 292 __asm__ __volatile__( 293 "subss %2, %1\n\t" 294 "movss %1, %0" 295 : "=m" (*f3), "+x" (*f1) 296 : "x" (*f2)); 297 } 298 299 extern __GNU_INLINE void 300 sse_mulss(float *f1, float *f2, float *f3) 301 { 302 __asm__ __volatile__( 303 "mulss %2, %1\n\t" 304 "movss %1, %0" 305 : "=m" (*f3), "+x" (*f1) 306 : "x" (*f2)); 307 } 308 309 extern __GNU_INLINE void 310 sse_divss(float *f1, float *f2, float *f3) 311 { 312 __asm__ __volatile__( 313 "divss %2, %1\n\t" 314 "movss %1, %0" 315 : "=m" (*f3), "+x" (*f1) 316 : "x" (*f2)); 317 } 318 319 extern __GNU_INLINE void 320 sse_sqrtss(float *f1, float *f2) 321 { 322 double tmp; 323 324 __asm__ __volatile__( 325 "sqrtss %2, %1\n\t" 326 "movss %1, %0" 327 : "=m" (*f2), "=x" (tmp) 328 : "m" (*f1)); 329 } 330 331 extern __GNU_INLINE void 332 sse_ucomiss(float *f1, float *f2) 333 { 334 __asm__ __volatile__("ucomiss %1, %0" : : "x" (*f1), "x" (*f2)); 335 336 } 337 338 extern __GNU_INLINE void 339 sse_comiss(float *f1, float *f2) 340 { 341 __asm__ __volatile__("comiss %1, %0" : : "x" (*f1), "x" (*f2)); 342 } 343 344 extern __GNU_INLINE void 345 sse_cvtss2sd(float *f1, double *d1) 346 { 347 double tmp; 348 349 __asm__ __volatile__( 350 "cvtss2sd %2, %1\n\t" 351 "movsd %1, %0" 352 : "=m" (*d1), "=x" (tmp) 353 : "m" (*f1)); 354 } 355 356 extern __GNU_INLINE void 357 sse_cvtsi2ss(int *i1, float *f1) 358 { 359 double tmp; 360 361 __asm__ __volatile__( 362 "cvtsi2ss %2, %1\n\t" 363 "movss %1, %0" 364 : "=m" (*f1), "=x" (tmp) 365 : "m" (*i1)); 366 } 367 368 extern __GNU_INLINE void 369 sse_cvttss2si(float *f1, int *i1) 370 { 371 int tmp; 372 373 __asm__ __volatile__( 374 "cvttss2si %2, %1\n\t" 375 "movl %1, %0" 376 : "=m" (*i1), "=r" (tmp) 377 : "m" (*f1)); 378 } 379 380 extern __GNU_INLINE void 381 sse_cvtss2si(float *f1, int *i1) 382 { 383 int tmp; 384 385 __asm__ __volatile__( 386 "cvtss2si %2, %1\n\t" 387 "movl %1, %0" 388 : "=m" (*i1), "=r" (tmp) 389 : "m" (*f1)); 390 } 391 392 #if defined(__amd64) 393 extern __GNU_INLINE void 394 sse_cvtsi2ssq(long long *ll1, float *f1) 395 { 396 double tmp; 397 398 __asm__ __volatile__( 399 "cvtsi2ssq %2, %1\n\t" 400 "movss %1, %0" 401 : "=m" (*f1), "=x" (tmp) 402 : "m" (*ll1)); 403 } 404 405 extern __GNU_INLINE void 406 sse_cvttss2siq(float *f1, long long *ll1) 407 { 408 uint64_t tmp; 409 410 __asm__ __volatile__( 411 "cvttss2siq %2, %1\n\t" 412 "movq %1, %0" 413 : "=m" (*ll1), "=r" (tmp) 414 : "m" (*f1)); 415 } 416 417 extern __GNU_INLINE void 418 sse_cvtss2siq(float *f1, long long *ll1) 419 { 420 uint64_t tmp; 421 422 __asm__ __volatile__( 423 "cvtss2siq %2, %1\n\t" 424 "movq %1, %0" 425 : "=m" (*ll1), "=r" (tmp) 426 : "m" (*f1)); 427 } 428 429 #endif 430 431 extern __GNU_INLINE void 432 sse_cmpeqsd(double *d1, double *d2, long long *ll1) 433 { 434 __asm__ __volatile__( 435 "cmpeqsd %2,%1\n\t" 436 "movsd %1,%0" 437 : "=m" (*ll1), "+x" (*d1) 438 : "x" (*d2)); 439 } 440 441 extern __GNU_INLINE void 442 sse_cmpltsd(double *d1, double *d2, long long *ll1) 443 { 444 __asm__ __volatile__( 445 "cmpltsd %2,%1\n\t" 446 "movsd %1,%0" 447 : "=m" (*ll1), "+x" (*d1) 448 : "x" (*d2)); 449 } 450 451 extern __GNU_INLINE void 452 sse_cmplesd(double *d1, double *d2, long long *ll1) 453 { 454 __asm__ __volatile__( 455 "cmplesd %2,%1\n\t" 456 "movsd %1,%0" 457 : "=m" (*ll1), "+x" (*d1) 458 : "x" (*d2)); 459 } 460 461 extern __GNU_INLINE void 462 sse_cmpunordsd(double *d1, double *d2, long long *ll1) 463 { 464 __asm__ __volatile__( 465 "cmpunordsd %2,%1\n\t" 466 "movsd %1,%0" 467 : "=m" (*ll1), "+x" (*d1) 468 : "x" (*d2)); 469 } 470 471 472 extern __GNU_INLINE void 473 sse_minsd(double *d1, double *d2, double *d3) 474 { 475 __asm__ __volatile__( 476 "minsd %2,%1\n\t" 477 "movsd %1,%0" 478 : "=m" (*d3), "+x" (*d1) 479 : "x" (*d2)); 480 } 481 482 extern __GNU_INLINE void 483 sse_maxsd(double *d1, double *d2, double *d3) 484 { 485 __asm__ __volatile__( 486 "maxsd %2,%1\n\t" 487 "movsd %1,%0" 488 : "=m" (*d3), "+x" (*d1) 489 : "x" (*d2)); 490 } 491 492 extern __GNU_INLINE void 493 sse_addsd(double *d1, double *d2, double *d3) 494 { 495 __asm__ __volatile__( 496 "addsd %2,%1\n\t" 497 "movsd %1,%0" 498 : "=m" (*d3), "+x" (*d1) 499 : "x" (*d2)); 500 } 501 502 extern __GNU_INLINE void 503 sse_subsd(double *d1, double *d2, double *d3) 504 { 505 __asm__ __volatile__( 506 "subsd %2,%1\n\t" 507 "movsd %1,%0" 508 : "=m" (*d3), "+x" (*d1) 509 : "x" (*d2)); 510 } 511 512 extern __GNU_INLINE void 513 sse_mulsd(double *d1, double *d2, double *d3) 514 { 515 __asm__ __volatile__( 516 "mulsd %2,%1\n\t" 517 "movsd %1,%0" 518 : "=m" (*d3), "+x" (*d1) 519 : "x" (*d2)); 520 } 521 522 extern __GNU_INLINE void 523 sse_divsd(double *d1, double *d2, double *d3) 524 { 525 __asm__ __volatile__( 526 "divsd %2,%1\n\t" 527 "movsd %1,%0" 528 : "=m" (*d3), "+x" (*d1) 529 : "x" (*d2)); 530 } 531 532 extern __GNU_INLINE void 533 sse_sqrtsd(double *d1, double *d2) 534 { 535 double tmp; 536 537 __asm__ __volatile__( 538 "sqrtsd %2, %1\n\t" 539 "movsd %1, %0" 540 : "=m" (*d2), "=x" (tmp) 541 : "m" (*d1)); 542 } 543 544 extern __GNU_INLINE void 545 sse_ucomisd(double *d1, double *d2) 546 { 547 __asm__ __volatile__("ucomisd %1, %0" : : "x" (*d1), "x" (*d2)); 548 } 549 550 extern __GNU_INLINE void 551 sse_comisd(double *d1, double *d2) 552 { 553 __asm__ __volatile__("comisd %1, %0" : : "x" (*d1), "x" (*d2)); 554 } 555 556 extern __GNU_INLINE void 557 sse_cvtsd2ss(double *d1, float *f1) 558 { 559 double tmp; 560 561 __asm__ __volatile__( 562 "cvtsd2ss %2,%1\n\t" 563 "movss %1,%0" 564 : "=m" (*f1), "=x" (tmp) 565 : "m" (*d1)); 566 } 567 568 extern __GNU_INLINE void 569 sse_cvtsi2sd(int *i1, double *d1) 570 { 571 double tmp; 572 __asm__ __volatile__( 573 "cvtsi2sd %2,%1\n\t" 574 "movsd %1,%0" 575 : "=m" (*d1), "=x" (tmp) 576 : "m" (*i1)); 577 } 578 579 extern __GNU_INLINE void 580 sse_cvttsd2si(double *d1, int *i1) 581 { 582 int tmp; 583 584 __asm__ __volatile__( 585 "cvttsd2si %2,%1\n\t" 586 "movl %1,%0" 587 : "=m" (*i1), "=r" (tmp) 588 : "m" (*d1)); 589 } 590 591 extern __GNU_INLINE void 592 sse_cvtsd2si(double *d1, int *i1) 593 { 594 int tmp; 595 596 __asm__ __volatile__( 597 "cvtsd2si %2,%1\n\t" 598 "movl %1,%0" 599 : "=m" (*i1), "=r" (tmp) 600 : "m" (*d1)); 601 } 602 603 #if defined(__amd64) 604 extern __GNU_INLINE void 605 sse_cvtsi2sdq(long long *ll1, double *d1) 606 { 607 double tmp; 608 609 __asm__ __volatile__( 610 "cvtsi2sdq %2,%1\n\t" 611 "movsd %1,%0" 612 : "=m" (*d1), "=x" (tmp) 613 : "m" (*ll1)); 614 } 615 616 extern __GNU_INLINE void 617 sse_cvttsd2siq(double *d1, long long *ll1) 618 { 619 uint64_t tmp; 620 621 __asm__ __volatile__( 622 "cvttsd2siq %2,%1\n\t" 623 "movq %1,%0" 624 : "=m" (*ll1), "=r" (tmp) 625 : "m" (*d1)); 626 } 627 628 extern __GNU_INLINE void 629 sse_cvtsd2siq(double *d1, long long *ll1) 630 { 631 uint64_t tmp; 632 633 __asm__ __volatile__( 634 "cvtsd2siq %2,%1\n\t" 635 "movq %1,%0" 636 : "=m" (*ll1), "=r" (tmp) 637 : "m" (*d1)); 638 } 639 #endif 640 641 #elif defined(__sparc) 642 extern __GNU_INLINE void 643 __fenv_getfsr(unsigned long *l) 644 { 645 __asm__ __volatile__( 646 #if defined(__sparcv9) 647 "stx %%fsr,%0\n\t" 648 #else 649 "st %%fsr,%0\n\t" 650 #endif 651 : "=m" (*l)); 652 } 653 654 extern __GNU_INLINE void 655 __fenv_setfsr(const unsigned long *l) 656 { 657 __asm__ __volatile__( 658 #if defined(__sparcv9) 659 "ldx %0,%%fsr\n\t" 660 #else 661 "ld %0,%%fsr\n\t" 662 #endif 663 : : "m" (*l) : "cc"); 664 } 665 666 extern __GNU_INLINE void 667 __fenv_getfsr32(unsigned int *l) 668 { 669 __asm__ __volatile__("st %%fsr,%0\n\t" : "=m" (*l)); 670 } 671 672 extern __GNU_INLINE void 673 __fenv_setfsr32(const unsigned int *l) 674 { 675 __asm__ __volatile__("ld %0,%%fsr\n\t" : : "m" (*l)); 676 } 677 #else 678 #error "GCC FENV inlines not implemented for this platform" 679 #endif 680 681 #ifdef __cplusplus 682 } 683 #endif 684 685 #endif /* __GNUC__ */ 686 687 #endif /* _FENV_INLINES_H */ 688