github.com/akaros/go-akaros@v0.0.0-20181004170632-85005d477eab/src/runtime/vlrt.c (about) 1 // Inferno's libkern/vlrt-386.c 2 // http://code.google.com/p/inferno-os/source/browse/libkern/vlrt-386.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved. 6 // Portions Copyright 2009 The Go Authors. All rights reserved. 7 // 8 // Permission is hereby granted, free of charge, to any person obtaining a copy 9 // of this software and associated documentation files (the "Software"), to deal 10 // in the Software without restriction, including without limitation the rights 11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 // copies of the Software, and to permit persons to whom the Software is 13 // furnished to do so, subject to the following conditions: 14 // 15 // The above copyright notice and this permission notice shall be included in 16 // all copies or substantial portions of the Software. 17 // 18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 // THE SOFTWARE. 25 26 // +build arm 386 27 28 #include "textflag.h" 29 30 /* 31 * C runtime for 64-bit divide, others. 32 * 33 * TODO(rsc): The simple functions are dregs--8c knows how 34 * to generate the code directly now. Find and remove. 35 */ 36 37 void runtime·panicdivide(void); 38 39 typedef unsigned long ulong; 40 typedef unsigned int uint; 41 typedef unsigned short ushort; 42 typedef unsigned char uchar; 43 typedef signed char schar; 44 45 #define SIGN(n) (1UL<<(n-1)) 46 47 typedef struct Vlong Vlong; 48 struct Vlong 49 { 50 ulong lo; 51 ulong hi; 52 }; 53 54 typedef union Vlong64 Vlong64; 55 union Vlong64 56 { 57 long long v; 58 Vlong v2; 59 }; 60 61 void runtime·abort(void); 62 63 #pragma textflag NOSPLIT 64 Vlong 65 _addv(Vlong a, Vlong b) 66 { 67 Vlong r; 68 69 r.lo = a.lo + b.lo; 70 r.hi = a.hi + b.hi; 71 if(r.lo < a.lo) 72 r.hi++; 73 return r; 74 } 75 76 #pragma textflag NOSPLIT 77 Vlong 78 _subv(Vlong a, Vlong b) 79 { 80 Vlong r; 81 82 r.lo = a.lo - b.lo; 83 r.hi = a.hi - b.hi; 84 if(r.lo > a.lo) 85 r.hi--; 86 return r; 87 } 88 89 Vlong 90 _d2v(double d) 91 { 92 union { double d; Vlong vl; } x; 93 ulong xhi, xlo, ylo, yhi; 94 int sh; 95 Vlong y; 96 97 x.d = d; 98 99 xhi = (x.vl.hi & 0xfffff) | 0x100000; 100 xlo = x.vl.lo; 101 sh = 1075 - ((x.vl.hi >> 20) & 0x7ff); 102 103 ylo = 0; 104 yhi = 0; 105 if(sh >= 0) { 106 /* v = (hi||lo) >> sh */ 107 if(sh < 32) { 108 if(sh == 0) { 109 ylo = xlo; 110 yhi = xhi; 111 } else { 112 ylo = (xlo >> sh) | (xhi << (32-sh)); 113 yhi = xhi >> sh; 114 } 115 } else { 116 if(sh == 32) { 117 ylo = xhi; 118 } else 119 if(sh < 64) { 120 ylo = xhi >> (sh-32); 121 } 122 } 123 } else { 124 /* v = (hi||lo) << -sh */ 125 sh = -sh; 126 if(sh <= 10) { /* NOTE: sh <= 11 on ARM??? */ 127 ylo = xlo << sh; 128 yhi = (xhi << sh) | (xlo >> (32-sh)); 129 } else { 130 /* overflow */ 131 yhi = d; /* causes something awful */ 132 } 133 } 134 if(x.vl.hi & SIGN(32)) { 135 if(ylo != 0) { 136 ylo = -ylo; 137 yhi = ~yhi; 138 } else 139 yhi = -yhi; 140 } 141 142 y.hi = yhi; 143 y.lo = ylo; 144 return y; 145 } 146 147 Vlong 148 _f2v(float f) 149 { 150 return _d2v(f); 151 } 152 153 double 154 _ul2d(ulong u) 155 { 156 // compensate for bug in c 157 if(u & SIGN(32)) { 158 u ^= SIGN(32); 159 return 2147483648. + u; 160 } 161 return u; 162 } 163 164 double 165 _v2d(Vlong x) 166 { 167 if(x.hi & SIGN(32)) { 168 if(x.lo) { 169 x.lo = -x.lo; 170 x.hi = ~x.hi; 171 } else 172 x.hi = -x.hi; 173 return -(_ul2d(x.hi)*4294967296. + _ul2d(x.lo)); 174 } 175 return (long)x.hi*4294967296. + x.lo; 176 } 177 178 float 179 _v2f(Vlong x) 180 { 181 return _v2d(x); 182 } 183 184 ulong runtime·_div64by32(Vlong, ulong, ulong*); 185 int runtime·_mul64by32(Vlong*, Vlong, ulong); 186 187 static void 188 slowdodiv(Vlong num, Vlong den, Vlong *q, Vlong *r) 189 { 190 ulong numlo, numhi, denhi, denlo, quohi, quolo, t; 191 int i; 192 193 numhi = num.hi; 194 numlo = num.lo; 195 denhi = den.hi; 196 denlo = den.lo; 197 198 /* 199 * get a divide by zero 200 */ 201 if(denlo==0 && denhi==0) { 202 runtime·panicdivide(); 203 } 204 205 /* 206 * set up the divisor and find the number of iterations needed 207 */ 208 if(numhi >= SIGN(32)) { 209 quohi = SIGN(32); 210 quolo = 0; 211 } else { 212 quohi = numhi; 213 quolo = numlo; 214 } 215 i = 0; 216 while(denhi < quohi || (denhi == quohi && denlo < quolo)) { 217 denhi = (denhi<<1) | (denlo>>31); 218 denlo <<= 1; 219 i++; 220 } 221 222 quohi = 0; 223 quolo = 0; 224 for(; i >= 0; i--) { 225 quohi = (quohi<<1) | (quolo>>31); 226 quolo <<= 1; 227 if(numhi > denhi || (numhi == denhi && numlo >= denlo)) { 228 t = numlo; 229 numlo -= denlo; 230 if(numlo > t) 231 numhi--; 232 numhi -= denhi; 233 quolo |= 1; 234 } 235 denlo = (denlo>>1) | (denhi<<31); 236 denhi >>= 1; 237 } 238 239 if(q) { 240 q->lo = quolo; 241 q->hi = quohi; 242 } 243 if(r) { 244 r->lo = numlo; 245 r->hi = numhi; 246 } 247 } 248 249 #ifdef GOARCH_arm 250 static void 251 dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp) 252 { 253 slowdodiv(num, den, qp, rp); 254 } 255 #endif 256 257 #ifdef GOARCH_386 258 static void 259 dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp) 260 { 261 ulong n; 262 Vlong x, q, r; 263 264 if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){ 265 if(qp) { 266 qp->hi = 0; 267 qp->lo = 0; 268 } 269 if(rp) { 270 rp->hi = num.hi; 271 rp->lo = num.lo; 272 } 273 return; 274 } 275 276 if(den.hi != 0){ 277 q.hi = 0; 278 n = num.hi/den.hi; 279 if(runtime·_mul64by32(&x, den, n) || x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo)) 280 slowdodiv(num, den, &q, &r); 281 else { 282 q.lo = n; 283 *(long long*)&r = *(long long*)&num - *(long long*)&x; 284 } 285 } else { 286 if(num.hi >= den.lo){ 287 if(den.lo == 0) 288 runtime·panicdivide(); 289 q.hi = n = num.hi/den.lo; 290 num.hi -= den.lo*n; 291 } else { 292 q.hi = 0; 293 } 294 q.lo = runtime·_div64by32(num, den.lo, &r.lo); 295 r.hi = 0; 296 } 297 if(qp) { 298 qp->lo = q.lo; 299 qp->hi = q.hi; 300 } 301 if(rp) { 302 rp->lo = r.lo; 303 rp->hi = r.hi; 304 } 305 } 306 #endif 307 308 Vlong 309 _divvu(Vlong n, Vlong d) 310 { 311 Vlong q; 312 313 if(n.hi == 0 && d.hi == 0) { 314 if(d.lo == 0) 315 runtime·panicdivide(); 316 q.hi = 0; 317 q.lo = n.lo / d.lo; 318 return q; 319 } 320 dodiv(n, d, &q, 0); 321 return q; 322 } 323 324 Vlong 325 _modvu(Vlong n, Vlong d) 326 { 327 Vlong r; 328 329 if(n.hi == 0 && d.hi == 0) { 330 if(d.lo == 0) 331 runtime·panicdivide(); 332 r.hi = 0; 333 r.lo = n.lo % d.lo; 334 return r; 335 } 336 dodiv(n, d, 0, &r); 337 return r; 338 } 339 340 static void 341 vneg(Vlong *v) 342 { 343 344 if(v->lo == 0) { 345 v->hi = -v->hi; 346 return; 347 } 348 v->lo = -v->lo; 349 v->hi = ~v->hi; 350 } 351 352 Vlong 353 _divv(Vlong n, Vlong d) 354 { 355 long nneg, dneg; 356 Vlong q; 357 358 if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { 359 if((long)n.lo == -0x80000000 && (long)d.lo == -1) { 360 // special case: 32-bit -0x80000000 / -1 causes divide error, 361 // but it's okay in this 64-bit context. 362 q.lo = 0x80000000; 363 q.hi = 0; 364 return q; 365 } 366 if(d.lo == 0) 367 runtime·panicdivide(); 368 q.lo = (long)n.lo / (long)d.lo; 369 q.hi = ((long)q.lo) >> 31; 370 return q; 371 } 372 nneg = n.hi >> 31; 373 if(nneg) 374 vneg(&n); 375 dneg = d.hi >> 31; 376 if(dneg) 377 vneg(&d); 378 dodiv(n, d, &q, 0); 379 if(nneg != dneg) 380 vneg(&q); 381 return q; 382 } 383 384 Vlong 385 _modv(Vlong n, Vlong d) 386 { 387 long nneg, dneg; 388 Vlong r; 389 390 if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) { 391 if((long)n.lo == -0x80000000 && (long)d.lo == -1) { 392 // special case: 32-bit -0x80000000 % -1 causes divide error, 393 // but it's okay in this 64-bit context. 394 r.lo = 0; 395 r.hi = 0; 396 return r; 397 } 398 if(d.lo == 0) 399 runtime·panicdivide(); 400 r.lo = (long)n.lo % (long)d.lo; 401 r.hi = ((long)r.lo) >> 31; 402 return r; 403 } 404 nneg = n.hi >> 31; 405 if(nneg) 406 vneg(&n); 407 dneg = d.hi >> 31; 408 if(dneg) 409 vneg(&d); 410 dodiv(n, d, 0, &r); 411 if(nneg) 412 vneg(&r); 413 return r; 414 } 415 416 #pragma textflag NOSPLIT 417 Vlong 418 _rshav(Vlong a, int b) 419 { 420 long t; 421 Vlong r; 422 423 t = a.hi; 424 if(b >= 32) { 425 r.hi = t>>31; 426 if(b >= 64) { 427 /* this is illegal re C standard */ 428 r.lo = t>>31; 429 return r; 430 } 431 r.lo = t >> (b-32); 432 return r; 433 } 434 if(b <= 0) { 435 r.hi = t; 436 r.lo = a.lo; 437 return r; 438 } 439 r.hi = t >> b; 440 r.lo = (t << (32-b)) | (a.lo >> b); 441 return r; 442 } 443 444 #pragma textflag NOSPLIT 445 Vlong 446 _rshlv(Vlong a, int b) 447 { 448 ulong t; 449 Vlong r; 450 451 t = a.hi; 452 if(b >= 32) { 453 r.hi = 0; 454 if(b >= 64) { 455 /* this is illegal re C standard */ 456 r.lo = 0; 457 return r; 458 } 459 r.lo = t >> (b-32); 460 return r; 461 } 462 if(b <= 0) { 463 r.hi = t; 464 r.lo = a.lo; 465 return r; 466 } 467 r.hi = t >> b; 468 r.lo = (t << (32-b)) | (a.lo >> b); 469 return r; 470 } 471 472 #pragma textflag NOSPLIT 473 Vlong 474 _lshv(Vlong a, int b) 475 { 476 ulong t; 477 478 t = a.lo; 479 if(b >= 32) { 480 if(b >= 64) { 481 /* this is illegal re C standard */ 482 return (Vlong){0, 0}; 483 } 484 return (Vlong){0, t<<(b-32)}; 485 } 486 if(b <= 0) { 487 return (Vlong){t, a.hi}; 488 } 489 return (Vlong){t<<b, (t >> (32-b)) | (a.hi << b)}; 490 } 491 492 #pragma textflag NOSPLIT 493 Vlong 494 _andv(Vlong a, Vlong b) 495 { 496 Vlong r; 497 498 r.hi = a.hi & b.hi; 499 r.lo = a.lo & b.lo; 500 return r; 501 } 502 503 #pragma textflag NOSPLIT 504 Vlong 505 _orv(Vlong a, Vlong b) 506 { 507 Vlong r; 508 509 r.hi = a.hi | b.hi; 510 r.lo = a.lo | b.lo; 511 return r; 512 } 513 514 #pragma textflag NOSPLIT 515 Vlong 516 _xorv(Vlong a, Vlong b) 517 { 518 Vlong r; 519 520 r.hi = a.hi ^ b.hi; 521 r.lo = a.lo ^ b.lo; 522 return r; 523 } 524 525 Vlong 526 _vpp(Vlong *r) 527 { 528 Vlong l; 529 530 l = *r; 531 r->lo++; 532 if(r->lo == 0) 533 r->hi++; 534 return l; 535 } 536 537 #pragma textflag NOSPLIT 538 Vlong 539 _vmm(Vlong *r) 540 { 541 Vlong l; 542 543 l = *r; 544 if(r->lo == 0) 545 r->hi--; 546 r->lo--; 547 return l; 548 } 549 550 #pragma textflag NOSPLIT 551 Vlong 552 _ppv(Vlong *r) 553 { 554 555 r->lo++; 556 if(r->lo == 0) 557 r->hi++; 558 return *r; 559 } 560 561 #pragma textflag NOSPLIT 562 Vlong 563 _mmv(Vlong *r) 564 { 565 566 if(r->lo == 0) 567 r->hi--; 568 r->lo--; 569 return *r; 570 } 571 572 #pragma textflag NOSPLIT 573 Vlong 574 _vasop(void *lv, Vlong fn(Vlong, Vlong), int type, Vlong rv) 575 { 576 Vlong t, u; 577 578 u.lo = 0; 579 u.hi = 0; 580 switch(type) { 581 default: 582 runtime·abort(); 583 break; 584 585 case 1: /* schar */ 586 t.lo = *(schar*)lv; 587 t.hi = t.lo >> 31; 588 u = fn(t, rv); 589 *(schar*)lv = u.lo; 590 break; 591 592 case 2: /* uchar */ 593 t.lo = *(uchar*)lv; 594 t.hi = 0; 595 u = fn(t, rv); 596 *(uchar*)lv = u.lo; 597 break; 598 599 case 3: /* short */ 600 t.lo = *(short*)lv; 601 t.hi = t.lo >> 31; 602 u = fn(t, rv); 603 *(short*)lv = u.lo; 604 break; 605 606 case 4: /* ushort */ 607 t.lo = *(ushort*)lv; 608 t.hi = 0; 609 u = fn(t, rv); 610 *(ushort*)lv = u.lo; 611 break; 612 613 case 9: /* int */ 614 t.lo = *(int*)lv; 615 t.hi = t.lo >> 31; 616 u = fn(t, rv); 617 *(int*)lv = u.lo; 618 break; 619 620 case 10: /* uint */ 621 t.lo = *(uint*)lv; 622 t.hi = 0; 623 u = fn(t, rv); 624 *(uint*)lv = u.lo; 625 break; 626 627 case 5: /* long */ 628 t.lo = *(long*)lv; 629 t.hi = t.lo >> 31; 630 u = fn(t, rv); 631 *(long*)lv = u.lo; 632 break; 633 634 case 6: /* ulong */ 635 t.lo = *(ulong*)lv; 636 t.hi = 0; 637 u = fn(t, rv); 638 *(ulong*)lv = u.lo; 639 break; 640 641 case 7: /* vlong */ 642 case 8: /* uvlong */ 643 if((void*)fn == _lshv || (void*)fn == _rshav || (void*)fn == _rshlv) 644 u = ((Vlong(*)(Vlong,int))fn)(*(Vlong*)lv, *(int*)&rv); 645 else 646 u = fn(*(Vlong*)lv, rv); 647 *(Vlong*)lv = u; 648 break; 649 } 650 return u; 651 } 652 653 #pragma textflag NOSPLIT 654 Vlong 655 _p2v(void *p) 656 { 657 long t; 658 Vlong ret; 659 660 t = (ulong)p; 661 ret.lo = t; 662 ret.hi = 0; 663 return ret; 664 } 665 666 #pragma textflag NOSPLIT 667 Vlong 668 _sl2v(long sl) 669 { 670 long t; 671 Vlong ret; 672 673 t = sl; 674 ret.lo = t; 675 ret.hi = t >> 31; 676 return ret; 677 } 678 679 #pragma textflag NOSPLIT 680 Vlong 681 _ul2v(ulong ul) 682 { 683 long t; 684 Vlong ret; 685 686 t = ul; 687 ret.lo = t; 688 ret.hi = 0; 689 return ret; 690 } 691 692 #pragma textflag NOSPLIT 693 Vlong 694 _si2v(int si) 695 { 696 return (Vlong){si, si>>31}; 697 } 698 699 #pragma textflag NOSPLIT 700 Vlong 701 _ui2v(uint ui) 702 { 703 long t; 704 Vlong ret; 705 706 t = ui; 707 ret.lo = t; 708 ret.hi = 0; 709 return ret; 710 } 711 712 #pragma textflag NOSPLIT 713 Vlong 714 _sh2v(long sh) 715 { 716 long t; 717 Vlong ret; 718 719 t = (sh << 16) >> 16; 720 ret.lo = t; 721 ret.hi = t >> 31; 722 return ret; 723 } 724 725 #pragma textflag NOSPLIT 726 Vlong 727 _uh2v(ulong ul) 728 { 729 long t; 730 Vlong ret; 731 732 t = ul & 0xffff; 733 ret.lo = t; 734 ret.hi = 0; 735 return ret; 736 } 737 738 #pragma textflag NOSPLIT 739 Vlong 740 _sc2v(long uc) 741 { 742 long t; 743 Vlong ret; 744 745 t = (uc << 24) >> 24; 746 ret.lo = t; 747 ret.hi = t >> 31; 748 return ret; 749 } 750 751 #pragma textflag NOSPLIT 752 Vlong 753 _uc2v(ulong ul) 754 { 755 long t; 756 Vlong ret; 757 758 t = ul & 0xff; 759 ret.lo = t; 760 ret.hi = 0; 761 return ret; 762 } 763 764 #pragma textflag NOSPLIT 765 long 766 _v2sc(Vlong rv) 767 { 768 long t; 769 770 t = rv.lo & 0xff; 771 return (t << 24) >> 24; 772 } 773 774 #pragma textflag NOSPLIT 775 long 776 _v2uc(Vlong rv) 777 { 778 779 return rv.lo & 0xff; 780 } 781 782 #pragma textflag NOSPLIT 783 long 784 _v2sh(Vlong rv) 785 { 786 long t; 787 788 t = rv.lo & 0xffff; 789 return (t << 16) >> 16; 790 } 791 792 #pragma textflag NOSPLIT 793 long 794 _v2uh(Vlong rv) 795 { 796 797 return rv.lo & 0xffff; 798 } 799 800 #pragma textflag NOSPLIT 801 long 802 _v2sl(Vlong rv) 803 { 804 805 return rv.lo; 806 } 807 808 #pragma textflag NOSPLIT 809 long 810 _v2ul(Vlong rv) 811 { 812 813 return rv.lo; 814 } 815 816 #pragma textflag NOSPLIT 817 long 818 _v2si(Vlong rv) 819 { 820 return rv.lo; 821 } 822 823 #pragma textflag NOSPLIT 824 long 825 _v2ui(Vlong rv) 826 { 827 828 return rv.lo; 829 } 830 831 #pragma textflag NOSPLIT 832 int 833 _testv(Vlong rv) 834 { 835 return rv.lo || rv.hi; 836 } 837 838 #pragma textflag NOSPLIT 839 int 840 _eqv(Vlong lv, Vlong rv) 841 { 842 return lv.lo == rv.lo && lv.hi == rv.hi; 843 } 844 845 #pragma textflag NOSPLIT 846 int 847 _nev(Vlong lv, Vlong rv) 848 { 849 return lv.lo != rv.lo || lv.hi != rv.hi; 850 } 851 852 #pragma textflag NOSPLIT 853 int 854 _ltv(Vlong lv, Vlong rv) 855 { 856 return (long)lv.hi < (long)rv.hi || 857 (lv.hi == rv.hi && lv.lo < rv.lo); 858 } 859 860 #pragma textflag NOSPLIT 861 int 862 _lev(Vlong lv, Vlong rv) 863 { 864 return (long)lv.hi < (long)rv.hi || 865 (lv.hi == rv.hi && lv.lo <= rv.lo); 866 } 867 868 #pragma textflag NOSPLIT 869 int 870 _gtv(Vlong lv, Vlong rv) 871 { 872 return (long)lv.hi > (long)rv.hi || 873 (lv.hi == rv.hi && lv.lo > rv.lo); 874 } 875 876 #pragma textflag NOSPLIT 877 int 878 _gev(Vlong lv, Vlong rv) 879 { 880 return (long)lv.hi > (long)rv.hi || 881 (lv.hi == rv.hi && lv.lo >= rv.lo); 882 } 883 884 #pragma textflag NOSPLIT 885 int 886 _lov(Vlong lv, Vlong rv) 887 { 888 return lv.hi < rv.hi || 889 (lv.hi == rv.hi && lv.lo < rv.lo); 890 } 891 892 #pragma textflag NOSPLIT 893 int 894 _lsv(Vlong lv, Vlong rv) 895 { 896 return lv.hi < rv.hi || 897 (lv.hi == rv.hi && lv.lo <= rv.lo); 898 } 899 900 #pragma textflag NOSPLIT 901 int 902 _hiv(Vlong lv, Vlong rv) 903 { 904 return lv.hi > rv.hi || 905 (lv.hi == rv.hi && lv.lo > rv.lo); 906 } 907 908 #pragma textflag NOSPLIT 909 int 910 _hsv(Vlong lv, Vlong rv) 911 { 912 return lv.hi > rv.hi || 913 (lv.hi == rv.hi && lv.lo >= rv.lo); 914 }