uint128.cpp 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. // Copyright 2019 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #ifdef _MSC_VER
  5. #include <intrin.h>
  6. #pragma intrinsic(_umul128)
  7. #pragma intrinsic(_udiv128)
  8. #endif
  9. #include <cstring>
  10. #include "common/uint128.h"
  11. namespace Common {
  12. #ifdef _MSC_VER
  13. u64 MultiplyAndDivide64(u64 a, u64 b, u64 d) {
  14. u128 r{};
  15. r[0] = _umul128(a, b, &r[1]);
  16. u64 remainder;
  17. #if _MSC_VER < 1923
  18. return udiv128(r[1], r[0], d, &remainder);
  19. #else
  20. return _udiv128(r[1], r[0], d, &remainder);
  21. #endif
  22. }
  23. #else
  24. u64 MultiplyAndDivide64(u64 a, u64 b, u64 d) {
  25. const u64 diva = a / d;
  26. const u64 moda = a % d;
  27. const u64 divb = b / d;
  28. const u64 modb = b % d;
  29. return diva * b + moda * divb + moda * modb / d;
  30. }
  31. #endif
  32. u128 Multiply64Into128(u64 a, u64 b) {
  33. u128 result;
  34. #ifdef _MSC_VER
  35. result[0] = _umul128(a, b, &result[1]);
  36. #else
  37. unsigned __int128 tmp = a;
  38. tmp *= b;
  39. std::memcpy(&result, &tmp, sizeof(u128));
  40. #endif
  41. return result;
  42. }
  43. std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor) {
  44. u64 remainder = dividend[0] % divisor;
  45. u64 accum = dividend[0] / divisor;
  46. if (dividend[1] == 0)
  47. return {accum, remainder};
  48. // We ignore dividend[1] / divisor as that overflows
  49. const u64 first_segment = (dividend[1] % divisor) << 32;
  50. accum += (first_segment / divisor) << 32;
  51. const u64 second_segment = (first_segment % divisor) << 32;
  52. accum += (second_segment / divisor);
  53. remainder += second_segment % divisor;
  54. if (remainder >= divisor) {
  55. accum++;
  56. remainder -= divisor;
  57. }
  58. return {accum, remainder};
  59. }
  60. } // namespace Common