|
|
1.1 ! root 1: // TITLE("Large Integer Arithmetic") ! 2: //++ ! 3: // ! 4: // Copyright (c) 1990 Microsoft Corporation ! 5: // Copyright (c) 1993 Digital Equipment Corporation ! 6: // ! 7: // Module Name: ! 8: // ! 9: // largeint.s ! 10: // ! 11: // Abstract: ! 12: // ! 13: // This module implements routines for performing extended integer ! 14: // arithmetic. ! 15: // ! 16: // Author: ! 17: // ! 18: // David N. Cutler (davec) 18-Apr-1990 ! 19: // ! 20: // Environment: ! 21: // ! 22: // Any mode. ! 23: // ! 24: // Revision History: ! 25: // ! 26: // Thomas Van Baak (tvb) 9-May-1992 ! 27: // ! 28: // Adapted for Alpha AXP. ! 29: // ! 30: //-- ! 31: ! 32: #include "ksalpha.h" ! 33: ! 34: // ! 35: // Alpha AXP Implementation Notes: ! 36: // ! 37: // The LargeInteger functions defined below implement a set of portable ! 38: // 64-bit integer arithmetic operations for x86, Mips, and Alpha systems ! 39: // using the LARGE_INTEGER data type. Code using LARGE_INTEGER variables ! 40: // and calling these functions will be portable across all NT platforms. ! 41: // This is the recommended approach to 64-bit arithmetic on NT. ! 42: // ! 43: // However, if performance is more important than portability, then for ! 44: // Alpha systems, the native 64-bit integer data types may be used instead ! 45: // of the LARGE_INTEGER type and the LargeInteger functions. The Alpha C ! 46: // compilers support a __int64 data type (renamed LONGLONG in the system ! 47: // header files). All C integer arithmetic operators may be used with ! 48: // these quadword types. This eliminates the need for, and the overhead ! 49: // of, any of the portable LargeInteger functions. ! 50: // ! 51: // In general, a LARGE_INTEGER cannot simply be converted to a LONGLONG ! 52: // because of explicit references in application code to the 32-bit LowPart ! 53: // and HighPart members of the LARGE_INTEGER structure. ! 54: // ! 55: // The performance difference between using the portable LARGE_INTEGER ! 56: // types with LargeInteger functions and the Alpha LONGLONG types and ! 57: // operations is often not significant enough to warrant modifying otherwise ! 58: // portable code. In addition, future compiler optimization and inlining may ! 59: // actually result in identical performance between portable LARGE_INTEGER ! 60: // code and Alpha specific LONGLONG code. Therefore it is recommended to ! 61: // keep NT source code portable. ! 62: // ! 63: // The Alpha source for the large integer functions below differs from the ! 64: // Mips version since for Alpha a 64-bit argument or return value is passed ! 65: // through a 64-bit integer register. In addition, most operations are ! 66: // implemented with a single instruction. The division routines below, ! 67: // however, like Mips, use a simple shift/subtract algorithm which is ! 68: // considerably slower than the algorithm used by Alpha runtime division ! 69: // routines. ! 70: // ! 71: ! 72: SBTTL("Convert Long to Large Integer") ! 73: //++ ! 74: // ! 75: // LARGE_INTEGER ! 76: // ConvertLongToLargeInteger ( ! 77: // IN LONG SignedInteger ! 78: // ) ! 79: // ! 80: // Routine Description: ! 81: // ! 82: // This function converts a signed integer to a signed large integer ! 83: // and returns the result. ! 84: // ! 85: // Arguments: ! 86: // ! 87: // SignedInteger (a0) - Supplies the value to convert. ! 88: // ! 89: // Return Value: ! 90: // ! 91: // The large integer result is returned as the function value in v0. ! 92: // ! 93: //-- ! 94: ! 95: LEAF_ENTRY(ConvertLongToLargeInteger) ! 96: ! 97: addl a0, 0, v0 // ensure canonical (signed long) form ! 98: ret zero, (ra) // return ! 99: ! 100: .end ConvertLongToLargeInteger ! 101: ! 102: SBTTL("Convert Ulong to Large Integer") ! 103: //++ ! 104: // ! 105: // LARGE_INTEGER ! 106: // ConvertUlongToLargeInteger ( ! 107: // IN ULONG UnsignedInteger ! 108: // ) ! 109: // ! 110: // Routine Description: ! 111: // ! 112: // This function converts an unsigned integer to a signed large ! 113: // integer and returns the result. ! 114: // ! 115: // Arguments: ! 116: // ! 117: // UnsignedInteger (a0) - Supplies the value to convert. ! 118: // ! 119: // Return Value: ! 120: // ! 121: // The large integer result is returned as the function value in v0. ! 122: // ! 123: //-- ! 124: ! 125: LEAF_ENTRY(ConvertUlongToLargeInteger) ! 126: ! 127: zap a0, 0xf0, v0 // convert canonical ULONG to quadword ! 128: ret zero, (ra) // return ! 129: ! 130: .end ConvertUlongToLargeInteger ! 131: ! 132: SBTTL("Enlarged Signed Integer Multiply") ! 133: //++ ! 134: // ! 135: // LARGE_INTEGER ! 136: // EnlargedIntegerMultiply ( ! 137: // IN LONG Multiplicand, ! 138: // IN LONG Multiplier ! 139: // ) ! 140: // ! 141: // Routine Description: ! 142: // ! 143: // This function multiplies a signed integer by a signed integer and ! 144: // returns a signed large integer result. ! 145: // ! 146: // N.B. An overflow is not possible. ! 147: // ! 148: // Arguments: ! 149: // ! 150: // Multiplicand (a0) - Supplies the multiplicand value. ! 151: // ! 152: // Multiplier (a1) - Supplies the multiplier value. ! 153: // ! 154: // Return Value: ! 155: // ! 156: // The large integer result is returned as the function value in v0. ! 157: // ! 158: //-- ! 159: ! 160: LEAF_ENTRY(EnlargedIntegerMultiply) ! 161: ! 162: addl a0, 0, a0 // ensure canonical (signed long) form ! 163: addl a1, 0, a1 // ensure canonical (signed long) form ! 164: mulq a0, a1, v0 // multiply signed both quadwords ! 165: ret zero, (ra) // return ! 166: ! 167: .end EnlargedIntegerMultiply ! 168: ! 169: SBTTL("Enlarged Unsigned Divide") ! 170: //++ ! 171: // ! 172: // ULONG ! 173: // EnlargedUnsignedDivide ( ! 174: // IN ULARGE_INTEGER Dividend, ! 175: // IN ULONG Divisor, ! 176: // IN OUT PULONG Remainder OPTIONAL ! 177: // ) ! 178: // ! 179: // Routine Description: ! 180: // ! 181: // This function divides an unsigned large integer by an unsigned long ! 182: // and returns the resultant quotient and optionally the remainder. ! 183: // ! 184: // N.B. An overflow or divide by zero exception is possible. ! 185: // ! 186: // Arguments: ! 187: // ! 188: // Dividend (a0) - Supplies the unsigned 64-bit dividend value. ! 189: // ! 190: // Divisor (a1) - Supplies the unsigned 32-bit divisor value. ! 191: // ! 192: // Remainder (a2) - Supplies an optional pointer to a variable that ! 193: // receives the unsigned 32-bit remainder. ! 194: // ! 195: // Return Value: ! 196: // ! 197: // The unsigned long integer quotient is returned as the function value. ! 198: // ! 199: //-- ! 200: ! 201: LEAF_ENTRY(EnlargedUnsignedDivide) ! 202: ! 203: // ! 204: // Check for division by zero. ! 205: // ! 206: ! 207: zap a1, 0xf0, a1 // convert ULONG divisor to quadword ! 208: beq a1, 30f // trap if divisor is zero ! 209: ! 210: // ! 211: // Check for overflow. If the divisor is less than the upper half of the ! 212: // dividend the quotient would be wider than 32 bits. ! 213: // ! 214: ! 215: srl a0, 32, t0 // get upper longword of dividend ! 216: cmpule a1, t0, t1 // is divisor <= upper dividend? ! 217: bne t1, 40f // if ne[true], then overflow trap ! 218: ! 219: // ! 220: // Perform the shift/subtract loop 8 times and 4 bits per loop. ! 221: // ! 222: // t0 - Temp used for 0/1 results of compares. ! 223: // t1 - High 64-bits of 128-bit (t1, a0) dividend. ! 224: // t2 - Loop counter. ! 225: // ! 226: ! 227: ldiq t2, 32/4 // set iteration count ! 228: ! 229: srl a0, 32, t1 // get top 32 bits of carry-out ! 230: sll a0, 32, a0 // preshift first 32 bits left ! 231: ! 232: 10: cmplt a0, 0, t0 // predict low-dividend shift carry-out ! 233: addq a0, a0, a0 // shift low-dividend left ! 234: addq t1, t1, t1 // shift high-dividend left ! 235: bis t1, t0, t1 // merge in carry-out of low-dividend ! 236: ! 237: cmpule a1, t1, t0 // if dividend >= divisor, ! 238: addq a0, t0, a0 // then set quotient bit ! 239: subq t1, a1, t0 // subtract divisor from dividend, ! 240: cmovlbs a0, t0, t1 // if dividend >= divisor ! 241: ! 242: cmplt a0, 0, t0 // predict low-dividend shift carry-out ! 243: addq a0, a0, a0 // shift low-dividend left ! 244: addq t1, t1, t1 // shift high-dividend left ! 245: bis t1, t0, t1 // merge in carry-out of low-dividend ! 246: ! 247: cmpule a1, t1, t0 // if dividend >= divisor, ! 248: addq a0, t0, a0 // then set quotient bit ! 249: subq t1, a1, t0 // subtract divisor from dividend, ! 250: cmovlbs a0, t0, t1 // if dividend >= divisor ! 251: ! 252: cmplt a0, 0, t0 // predict low-dividend shift carry-out ! 253: addq a0, a0, a0 // shift low-dividend left ! 254: addq t1, t1, t1 // shift high-dividend left ! 255: bis t1, t0, t1 // merge in carry-out of low-dividend ! 256: ! 257: cmpule a1, t1, t0 // if dividend >= divisor, ! 258: addq a0, t0, a0 // then set quotient bit ! 259: subq t1, a1, t0 // subtract divisor from dividend, ! 260: cmovlbs a0, t0, t1 // if dividend >= divisor ! 261: ! 262: cmplt a0, 0, t0 // predict low-dividend shift carry-out ! 263: addq a0, a0, a0 // shift low-dividend left ! 264: addq t1, t1, t1 // shift high-dividend left ! 265: bis t1, t0, t1 // merge in carry-out of low-dividend ! 266: ! 267: cmpule a1, t1, t0 // if dividend >= divisor, ! 268: addq a0, t0, a0 // then set quotient bit ! 269: subq t1, a1, t0 // subtract divisor from dividend, ! 270: cmovlbs a0, t0, t1 // if dividend >= divisor ! 271: ! 272: subq t2, 1, t2 // any more iterations? ! 273: bne t2, 10b // ! 274: ! 275: // ! 276: // Finished with remainder value in t1 and quotient value in a0. ! 277: // ! 278: ! 279: addl a0, 0, v0 // set longword quotient return value ! 280: beq a2, 20f // skip optional remainder store ! 281: stl t1, 0(a2) // store longword remainder ! 282: ! 283: 20: ret zero, (ra) // return ! 284: ! 285: // ! 286: // Generate an exception for divide by zero and return a zero quotient if the ! 287: // caller continues execution. ! 288: // ! 289: ! 290: 30: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO ! 291: ! 292: GENERATE_TRAP ! 293: ! 294: ldil v0, 0 // return zero quotient ! 295: ret zero, (ra) // return ! 296: ! 297: // ! 298: // Generate an exception for overflow. ! 299: // ! 300: ! 301: 40: ldiq a0, 0x8000000000000000 // ! 302: subqv zero, a0, v0 // negate in order to overflow ! 303: trapb // wait for trap to occur ! 304: ret zero, (ra) // return ! 305: ! 306: .end EnlargedUnsignedDivide ! 307: ! 308: SBTTL("Enlarged Unsigned Integer Multiply") ! 309: //++ ! 310: // ! 311: // LARGE_INTEGER ! 312: // EnlargedUnsignedMultiply ( ! 313: // IN ULONG Multiplicand, ! 314: // IN ULONG Multiplier ! 315: // ) ! 316: // ! 317: // Routine Description: ! 318: // ! 319: // This function multiplies an unsigned integer by an unsigned integer ! 320: // and returns a signed large integer result. ! 321: // ! 322: // Arguments: ! 323: // ! 324: // Multiplicand (a0) - Supplies the multiplicand value. ! 325: // ! 326: // Multiplier (a1) - Supplies the multiplier value. ! 327: // ! 328: // Return Value: ! 329: // ! 330: // The large integer result is returned as the function value in v0. ! 331: // ! 332: //-- ! 333: ! 334: LEAF_ENTRY(EnlargedUnsignedMultiply) ! 335: ! 336: zap a0, 0xf0, a0 // convert canonical ULONG to quadword ! 337: zap a1, 0xf0, a1 // convert canonical ULONG to quadword ! 338: mulq a0, a1, v0 // multiply signed both quadwords ! 339: ret zero, (ra) // return ! 340: ! 341: .end EnlargedUnsignedMultiply ! 342: ! 343: SBTTL("Extended Integer Multiply") ! 344: //++ ! 345: // ! 346: // LARGE_INTEGER ! 347: // ExtendedIntegerMultiply ( ! 348: // IN LARGE_INTEGER Multiplicand, ! 349: // IN LONG Multiplier ! 350: // ) ! 351: // ! 352: // Routine Description: ! 353: // ! 354: // This function multiplies a signed large integer by a signed integer and ! 355: // returns the signed large integer result. ! 356: // ! 357: // N.B. An overflow is possible, but no exception is generated. ! 358: // ! 359: // Arguments: ! 360: // ! 361: // Multiplicand (a0) - Supplies the multiplicand value. ! 362: // ! 363: // Multiplier (a1) - Supplies the multiplier value. ! 364: // ! 365: // Return Value: ! 366: // ! 367: // The large integer result is returned as the function value in v0. ! 368: // ! 369: //-- ! 370: ! 371: LEAF_ENTRY(ExtendedIntegerMultiply) ! 372: ! 373: addl a1, 0, a1 // ensure canonical (signed long) form ! 374: mulq a0, a1, v0 // multiply signed both quadwords ! 375: ret zero, (ra) // return ! 376: ! 377: .end ExtendedIntegerMultiply ! 378: ! 379: SBTTL("Extended Large Integer Divide") ! 380: //++ ! 381: // ! 382: // LARGE_INTEGER ! 383: // ExtendedLargeIntegerDivide ( ! 384: // IN LARGE_INTEGER Dividend, ! 385: // IN ULONG Divisor, ! 386: // IN OUT PULONG Remainder OPTIONAL ! 387: // ) ! 388: // ! 389: // Routine Description: ! 390: // ! 391: // This function divides an unsigned large integer by an unsigned long ! 392: // and returns the quadword quotient and optionally the long remainder. ! 393: // ! 394: // N.B. A divide by zero exception is possible. ! 395: // ! 396: // Arguments: ! 397: // ! 398: // Dividend (a0) - Supplies the dividend value. ! 399: // ! 400: // Divisor (a1) - Supplies the divisor value. ! 401: // ! 402: // Remainder (a2) - Supplies an optional pointer to a variable that ! 403: // receives the remainder. ! 404: // ! 405: // Return Value: ! 406: // ! 407: // The large integer result is returned as the function value in v0. ! 408: // ! 409: //-- ! 410: ! 411: LEAF_ENTRY(ExtendedLargeIntegerDivide) ! 412: ! 413: // ! 414: // Check for division by zero. ! 415: // ! 416: ! 417: zap a1, 0xf0, a1 // convert canonical ULONG to quadword ! 418: beq a1, 30f // trap if divisor is zero ! 419: ! 420: // ! 421: // Perform the shift/subtract loop 16 times and 4 bits per loop. ! 422: // ! 423: // t0 - Temp used for 0/1 results of compares. ! 424: // t1 - High 64-bits of 128-bit (t1, a0) dividend. ! 425: // t2 - Loop counter. ! 426: // ! 427: ! 428: ldiq t2, 64/4 // set iteration count ! 429: ! 430: ldiq t1, 0 // zero-extend dividend to 128 bits ! 431: ! 432: 10: cmplt a0, 0, t0 // predict low-dividend shift carry-out ! 433: addq a0, a0, a0 // shift low-dividend left ! 434: addq t1, t1, t1 // shift high-dividend left ! 435: bis t1, t0, t1 // merge in carry-out of low-dividend ! 436: ! 437: cmpule a1, t1, t0 // if dividend >= divisor, ! 438: addq a0, t0, a0 // then set quotient bit ! 439: subq t1, a1, t0 // subtract divisor from dividend, ! 440: cmovlbs a0, t0, t1 // if dividend >= divisor ! 441: ! 442: cmplt a0, 0, t0 // predict low-dividend shift carry-out ! 443: addq a0, a0, a0 // shift low-dividend left ! 444: addq t1, t1, t1 // shift high-dividend left ! 445: bis t1, t0, t1 // merge in carry-out of low-dividend ! 446: ! 447: cmpule a1, t1, t0 // if dividend >= divisor, ! 448: addq a0, t0, a0 // then set quotient bit ! 449: subq t1, a1, t0 // subtract divisor from dividend, ! 450: cmovlbs a0, t0, t1 // if dividend >= divisor ! 451: ! 452: cmplt a0, 0, t0 // predict low-dividend shift carry-out ! 453: addq a0, a0, a0 // shift low-dividend left ! 454: addq t1, t1, t1 // shift high-dividend left ! 455: bis t1, t0, t1 // merge in carry-out of low-dividend ! 456: ! 457: cmpule a1, t1, t0 // if dividend >= divisor, ! 458: addq a0, t0, a0 // then set quotient bit ! 459: subq t1, a1, t0 // subtract divisor from dividend, ! 460: cmovlbs a0, t0, t1 // if dividend >= divisor ! 461: ! 462: cmplt a0, 0, t0 // predict low-dividend shift carry-out ! 463: addq a0, a0, a0 // shift low-dividend left ! 464: addq t1, t1, t1 // shift high-dividend left ! 465: bis t1, t0, t1 // merge in carry-out of low-dividend ! 466: ! 467: cmpule a1, t1, t0 // if dividend >= divisor, ! 468: addq a0, t0, a0 // then set quotient bit ! 469: subq t1, a1, t0 // subtract divisor from dividend, ! 470: cmovlbs a0, t0, t1 // if dividend >= divisor ! 471: ! 472: subq t2, 1, t2 // any more iterations? ! 473: bne t2, 10b // ! 474: ! 475: // ! 476: // Finished with remainder value in t1 and quotient value in a0. ! 477: // ! 478: ! 479: mov a0, v0 // set quadword quotient return value ! 480: beq a2, 20f // skip optional remainder store ! 481: stl t1, 0(a2) // store longword remainder ! 482: ! 483: 20: ret zero, (ra) // return ! 484: ! 485: // ! 486: // Generate an exception for divide by zero. ! 487: // ! 488: ! 489: 30: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO ! 490: ! 491: GENERATE_TRAP ! 492: ! 493: br zero, 30b // in case they continue ! 494: ! 495: .end ExtendedLargeIntegerDivide ! 496: ! 497: SBTTL("Extended Magic Divide") ! 498: //++ ! 499: // ! 500: // LARGE_INTEGER ! 501: // ExtendedMagicDivide ( ! 502: // IN LARGE_INTEGER Dividend, ! 503: // IN LARGE_INTEGER MagicDivisor, ! 504: // IN CCHAR ShiftCount ! 505: // ) ! 506: // ! 507: // Routine Description: ! 508: // ! 509: // This function divides a signed large integer by an unsigned large integer ! 510: // and returns the signed large integer result. The division is performed ! 511: // using reciprocal multiplication of a signed large integer value by an ! 512: // unsigned large integer fraction which represents the most significant ! 513: // 64-bits of the reciprocal divisor rounded up in its least significant bit ! 514: // and normalized with respect to bit 63. A shift count is also provided ! 515: // which is used to truncate the fractional bits from the result value. ! 516: // ! 517: // Arguments: ! 518: // ! 519: // Dividend (a0) - Supplies the dividend value. ! 520: // ! 521: // MagicDivisor (a1) - Supplies the magic divisor value which ! 522: // is a 64-bit multiplicative reciprocal. ! 523: // ! 524: // Shiftcount (a2) - Supplies the right shift adjustment value. ! 525: // ! 526: // Return Value: ! 527: // ! 528: // The large integer result is returned as the function value in v0. ! 529: // ! 530: //-- ! 531: ! 532: LEAF_ENTRY(ExtendedMagicDivide) ! 533: ! 534: // ! 535: // Make the dividend positive for the reciprocal multiplication to work. ! 536: // ! 537: ! 538: negq a0, t0 // negate dividend ! 539: cmovgt a0, a0, t0 // get absolute value in t0 ! 540: ! 541: // ! 542: // Multiply both quadword arguments together and take only the upper 64 bits of ! 543: // the resulting 128 bit product. This can be done using the umulh instruction. ! 544: // ! 545: // Division of a dividend by a constant divisor through reciprocal ! 546: // multiplication works because a/b is equivalent to (a*x)/(b*x) for any ! 547: // value of x. Now if b is a constant, some "magic" integer x can be chosen, ! 548: // based on the value of b, so that (b*x) is very close to a large power of ! 549: // two (e.g., 2^64). Then a/b = (a*x)/(b*x) = (a*x)/(2^64) = (a*x)>>64. This ! 550: // effectively turns the problem of division by a constant into multiplication ! 551: // by a constant which is a much faster operation. ! 552: // ! 553: ! 554: umulh t0, a1, t1 // multiply high both quadword arguments ! 555: sra t1, a2, t1 // shift result right by requested amount ! 556: ! 557: // ! 558: // Make the result negative if the dividend was negative. ! 559: // ! 560: ! 561: negq t1, t0 // negate result ! 562: cmovgt a0, t1, t0 // restore sign of dividend ! 563: ! 564: mov t0, v0 // set quadword result return value ! 565: ret zero, (ra) // return ! 566: ! 567: .end ExtendedMagicDivide ! 568: ! 569: SBTTL("Large Integer Add") ! 570: //++ ! 571: // ! 572: // LARGE_INTEGER ! 573: // LargeIntegerAdd ( ! 574: // IN LARGE_INTEGER Addend1, ! 575: // IN LARGE_INTEGER Addend2 ! 576: // ) ! 577: // ! 578: // Routine Description: ! 579: // ! 580: // This function adds a signed large integer to a signed large integer and ! 581: // returns the signed large integer result. ! 582: // ! 583: // N.B. An overflow is possible, but no exception is generated. ! 584: // ! 585: // Arguments: ! 586: // ! 587: // Addend1 (a0) - Supplies the first addend value. ! 588: // ! 589: // Addend2 (a1) - Supplies the second addend value. ! 590: // ! 591: // Return Value: ! 592: // ! 593: // The large integer result is returned as the function value in v0. ! 594: // ! 595: //-- ! 596: ! 597: LEAF_ENTRY(LargeIntegerAdd) ! 598: ! 599: addq a0, a1, v0 // add both quadword arguments ! 600: ret zero, (ra) // return ! 601: ! 602: .end LargeIntegerAdd ! 603: ! 604: SBTTL("Large Integer Arithmetic Shift Right") ! 605: //++ ! 606: // ! 607: // LARGE_INTEGER ! 608: // LargeIntegerArithmeticShift ( ! 609: // IN LARGE_INTEGER LargeInteger, ! 610: // IN CCHAR ShiftCount ! 611: // ) ! 612: // ! 613: // Routine Description: ! 614: // ! 615: // This function shifts a signed large integer right by an unsigned integer ! 616: // modulo 64 and returns the shifted signed large integer result. ! 617: // ! 618: // Arguments: ! 619: // ! 620: // LargeInteger (a0) - Supplies the large integer to be shifted. ! 621: // ! 622: // ShiftCount (a1) - Supplies the right shift count. ! 623: // ! 624: // Return Value: ! 625: // ! 626: // The large integer result is returned as the function value in v0. ! 627: // ! 628: //-- ! 629: ! 630: LEAF_ENTRY(LargeIntegerArithmeticShift) ! 631: ! 632: sra a0, a1, v0 // shift the quadword right/arithmetic ! 633: ret zero, (ra) // return ! 634: ! 635: .end LargeIntegerArithmeticShift ! 636: ! 637: SBTTL("Large Integer Divide") ! 638: //++ ! 639: // ! 640: // LARGE_INTEGER ! 641: // LargeIntegerDivide ( ! 642: // IN LARGE_INTEGER Dividend, ! 643: // IN LARGE_INTEGER Divisor, ! 644: // IN OUT PLARGE_INTEGER Remainder OPTIONAL ! 645: // ) ! 646: // ! 647: // Routine Description: ! 648: // ! 649: // This function divides an unsigned large integer by an unsigned large ! 650: // integer and returns the quadword quotient and optionally the quadword ! 651: // remainder. ! 652: // ! 653: // N.B. A divide by zero exception is possible. ! 654: // ! 655: // Arguments: ! 656: // ! 657: // Dividend (a0) - Supplies the dividend value. ! 658: // ! 659: // Divisor (a1) - Supplies the divisor value. ! 660: // ! 661: // Remainder (a2) - Supplies an optional pointer to a variable that ! 662: // receives the remainder. ! 663: // ! 664: // Return Value: ! 665: // ! 666: // The large integer result is returned as the function value in v0. ! 667: // ! 668: //-- ! 669: ! 670: LEAF_ENTRY(LargeIntegerDivide) ! 671: ! 672: // ! 673: // Check for division by zero. ! 674: // ! 675: ! 676: beq a1, 30f // trap if divisor is zero ! 677: ! 678: // ! 679: // Perform the shift/subtract loop 16 times and 4 bits per loop. ! 680: // ! 681: // t0 - Temp used for 0/1 results of compares. ! 682: // t1 - High 64-bits of 128-bit (t1, a0) dividend. ! 683: // t2 - Loop counter. ! 684: // ! 685: ! 686: ldiq t2, 64/4 // set iteration count ! 687: ! 688: ldiq t1, 0 // zero-extend dividend to 128 bits ! 689: ! 690: 10: cmplt a0, 0, t0 // predict low-dividend shift carry-out ! 691: addq a0, a0, a0 // shift low-dividend left ! 692: addq t1, t1, t1 // shift high-dividend left ! 693: bis t1, t0, t1 // merge in carry-out of low-dividend ! 694: ! 695: cmpule a1, t1, t0 // if dividend >= divisor, ! 696: addq a0, t0, a0 // then set quotient bit ! 697: subq t1, a1, t0 // subtract divisor from dividend, ! 698: cmovlbs a0, t0, t1 // if dividend >= divisor ! 699: ! 700: cmplt a0, 0, t0 // predict low-dividend shift carry-out ! 701: addq a0, a0, a0 // shift low-dividend left ! 702: addq t1, t1, t1 // shift high-dividend left ! 703: bis t1, t0, t1 // merge in carry-out of low-dividend ! 704: ! 705: cmpule a1, t1, t0 // if dividend >= divisor, ! 706: addq a0, t0, a0 // then set quotient bit ! 707: subq t1, a1, t0 // subtract divisor from dividend, ! 708: cmovlbs a0, t0, t1 // if dividend >= divisor ! 709: ! 710: cmplt a0, 0, t0 // predict low-dividend shift carry-out ! 711: addq a0, a0, a0 // shift low-dividend left ! 712: addq t1, t1, t1 // shift high-dividend left ! 713: bis t1, t0, t1 // merge in carry-out of low-dividend ! 714: ! 715: cmpule a1, t1, t0 // if dividend >= divisor, ! 716: addq a0, t0, a0 // then set quotient bit ! 717: subq t1, a1, t0 // subtract divisor from dividend, ! 718: cmovlbs a0, t0, t1 // if dividend >= divisor ! 719: ! 720: cmplt a0, 0, t0 // predict low-dividend shift carry-out ! 721: addq a0, a0, a0 // shift low-dividend left ! 722: addq t1, t1, t1 // shift high-dividend left ! 723: bis t1, t0, t1 // merge in carry-out of low-dividend ! 724: ! 725: cmpule a1, t1, t0 // if dividend >= divisor, ! 726: addq a0, t0, a0 // then set quotient bit ! 727: subq t1, a1, t0 // subtract divisor from dividend, ! 728: cmovlbs a0, t0, t1 // if dividend >= divisor ! 729: ! 730: subq t2, 1, t2 // any more iterations? ! 731: bne t2, 10b // ! 732: ! 733: // ! 734: // Finished with remainder value in t1 and quotient value in a0. ! 735: // ! 736: ! 737: mov a0, v0 // set quadword quotient return value ! 738: beq a2, 20f // skip optional remainder store ! 739: stq t1, 0(a2) // store quadword remainder ! 740: ! 741: 20: ret zero, (ra) // return ! 742: ! 743: // ! 744: // Generate an exception for divide by zero. ! 745: // ! 746: ! 747: 30: ldil a0, GENTRAP_INTEGER_DIVIDE_BY_ZERO ! 748: ! 749: GENERATE_TRAP ! 750: ! 751: br zero, 30b // in case they continue ! 752: ! 753: .end LargeIntegerDivide ! 754: ! 755: SBTTL("Large Integer Negate") ! 756: //++ ! 757: // ! 758: // LARGE_INTEGER ! 759: // LargeIntegerNegate ( ! 760: // IN LARGE_INTEGER Subtrahend ! 761: // ) ! 762: // ! 763: // Routine Description: ! 764: // ! 765: // This function negates a signed large integer and returns the signed ! 766: // large integer result. ! 767: // ! 768: // N.B. An overflow is possible, but no exception is generated. ! 769: // ! 770: // Arguments: ! 771: // ! 772: // Subtrahend (a0) - Supplies the subtrahend value. ! 773: // ! 774: // Return Value: ! 775: // ! 776: // The large integer result is returned as the function value in v0. ! 777: // ! 778: //-- ! 779: ! 780: LEAF_ENTRY(LargeIntegerNegate) ! 781: ! 782: subq zero, a0, v0 // negate the quadword argument ! 783: ret zero, (ra) // return ! 784: ! 785: .end LargeIntegerNegate ! 786: ! 787: SBTTL("Large Integer Shift Left") ! 788: //++ ! 789: // ! 790: // LARGE_INTEGER ! 791: // LargeIntegerShiftLeft ( ! 792: // IN LARGE_INTEGER LargeInteger, ! 793: // IN CCHAR ShiftCount ! 794: // ) ! 795: // ! 796: // Routine Description: ! 797: // ! 798: // This function shifts a signed large integer left by an unsigned integer ! 799: // modulo 64 and returns the shifted signed large integer result. ! 800: // ! 801: // Arguments: ! 802: // ! 803: // LargeInteger (a0) - Supplies the large integer to be shifted. ! 804: // ! 805: // ShiftCount (a1) - Supplies the left shift count. ! 806: // ! 807: // Return Value: ! 808: // ! 809: // The large integer result is returned as the function value in v0. ! 810: // ! 811: //-- ! 812: ! 813: LEAF_ENTRY(LargeIntegerShiftLeft) ! 814: ! 815: sll a0, a1, v0 // shift the quadword argument left ! 816: ret zero, (ra) // return ! 817: ! 818: .end LargeIntegerShiftLeft ! 819: ! 820: SBTTL("Large Integer Logical Shift Right") ! 821: //++ ! 822: // ! 823: // LARGE_INTEGER ! 824: // LargeIntegerShiftRight ( ! 825: // IN LARGE_INTEGER LargeInteger, ! 826: // IN CCHAR ShiftCount ! 827: // ) ! 828: // ! 829: // Routine Description: ! 830: // ! 831: // This function shifts an unsigned large integer right by an unsigned ! 832: // integer modulo 64 and returns the shifted unsigned large integer result. ! 833: // ! 834: // Arguments: ! 835: // ! 836: // LargeInteger (a0) - Supplies the large integer to be shifted. ! 837: // ! 838: // ShiftCount (a1) - Supplies the right shift count. ! 839: // ! 840: // Return Value: ! 841: // ! 842: // The large integer result is returned as the function value in v0. ! 843: // ! 844: //-- ! 845: ! 846: LEAF_ENTRY(LargeIntegerShiftRight) ! 847: ! 848: srl a0, a1, v0 // shift the quadword right/logical ! 849: ret zero, (ra) // return ! 850: ! 851: .end LargeIntegerShiftRight ! 852: ! 853: SBTTL("Large Integer Subtract") ! 854: //++ ! 855: // ! 856: // LARGE_INTEGER ! 857: // LargeIntegerSubtract ( ! 858: // IN LARGE_INTEGER Minuend, ! 859: // IN LARGE_INTEGER Subtrahend ! 860: // ) ! 861: // ! 862: // Routine Description: ! 863: // ! 864: // This function subtracts a signed large integer from a signed large ! 865: // integer and returns the signed large integer result. ! 866: // ! 867: // N.B. An overflow is possible, but no exception is generated. ! 868: // ! 869: // Arguments: ! 870: // ! 871: // Minuend (a0) - Supplies the minuend value. ! 872: // ! 873: // Subtrahend (a1) - Supplies the subtrahend value. ! 874: // ! 875: // Return Value: ! 876: // ! 877: // The large integer result is returned as the function value in v0. ! 878: // ! 879: //-- ! 880: ! 881: LEAF_ENTRY(LargeIntegerSubtract) ! 882: ! 883: subq a0, a1, v0 // subtract the quadword arguments ! 884: ret zero, (ra) // return ! 885: ! 886: .end LargeIntegerSubtract
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.