diff --git a/src/common/u128.cpp b/src/common/u128.cpp index 5d97d222..73a825a1 100644 --- a/src/common/u128.cpp +++ b/src/common/u128.cpp @@ -11,6 +11,37 @@ namespace Dynarmic { +u128 Multiply64To128(u64 a, u64 b) { + const u32 a0 = static_cast(a); + const u32 b0 = static_cast(b); + const u32 a1 = static_cast(a >> 32); + const u32 b1 = static_cast(b >> 32); + + // result = (c2 << 64) + (c1 << 32) + c0 + // c2 = a1 * b1 + // c1 = a1 * b0 + a0 * b1 + // c0 = a0 * b0 + // noting that these operations may overflow + + const u64 c0 = static_cast(a0) * b0; + const u64 c1_0 = static_cast(a1) * b0; + const u64 c1_1 = static_cast(a0) * b1; + const u64 c2 = static_cast(a1) * b1; + + const u64 c1 = c1_0 + c1_1; + const u64 c1_overflow = c1 < c1_0; + + const u64 lower = c0 + (c1 << 32); + const u64 lower_overflow = lower < c0; + + const u64 upper = lower_overflow + (c1 >> 32) + (c1_overflow << 32) + c2; + + u128 result; + result.lower = lower; + result.upper = upper; + return result; +} + u128 operator<<(u128 operand, int amount) { if (amount < 0) { return operand >> -amount; diff --git a/src/common/u128.h b/src/common/u128.h index 867ac1dd..19d44bb6 100644 --- a/src/common/u128.h +++ b/src/common/u128.h @@ -48,6 +48,8 @@ static_assert(Common::BitSize() == 128); static_assert(std::is_standard_layout_v); static_assert(std::is_trivially_copyable_v); +u128 Multiply64To128(u64 a, u64 b); + inline u128 operator+(u128 a, u128 b) { u128 result; result.lower = a.lower + b.lower;