From b0afd53ea7ebc4c602250f1bd9baecb895c5bd80 Mon Sep 17 00:00:00 2001 From: MerryMage Date: Mon, 23 Jul 2018 15:57:29 +0100 Subject: [PATCH] u128: Add Multiply64To128 --- src/common/u128.cpp | 31 +++++++++++++++++++++++++++++++ src/common/u128.h | 2 ++ 2 files changed, 33 insertions(+) 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;