diff --git a/ChocolArm64/Instruction/ASoftFallback.cs b/ChocolArm64/Instruction/ASoftFallback.cs index 8ed55e2045..3f8ab5e3ef 100644 --- a/ChocolArm64/Instruction/ASoftFallback.cs +++ b/ChocolArm64/Instruction/ASoftFallback.cs @@ -153,12 +153,30 @@ namespace ChocolArm64.Instruction public static long SMulHi128(long LHS, long RHS) { - return (long)(BigInteger.Multiply(LHS, RHS) >> 64); + bool LSign = (LHS < 0); + bool RSign = (RHS < 0); + + long Result = (long)UMulHi128((ulong)(LSign ? -LHS : LHS), (ulong)(RSign ? -RHS : RHS)); + + if (LSign != RSign && LHS != 0 && RHS != 0) + return ~Result; //for negative results, hi 64-bits start at 0xFFF... and count back + return Result; } public static ulong UMulHi128(ulong LHS, ulong RHS) { - return (ulong)(BigInteger.Multiply(LHS, RHS) >> 64); + //long multiplication + //multiply 32 bits at a time in 64 bit, the result is what's carried over 64 bits. + ulong LHigh = LHS >> 32; + ulong LLow = LHS & 0xFFFFFFFF; + ulong RHigh = RHS >> 32; + ulong RLow = RHS & 0xFFFFFFFF; + ulong Z2 = LLow * RLow; + ulong T = LHigh * RLow + (Z2 >> 32); + ulong Z1 = T & 0xFFFFFFFF; + ulong Z0 = T >> 32; + Z1 += LLow * RHigh; + return LHigh * RHigh + Z0 + (Z1 >> 32); } } }