diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 4137b8e23f..d14d998462 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -430,6 +430,8 @@ add_library(core PowerPC/Interpreter/Interpreter_Tables.cpp PowerPC/Interpreter/Interpreter.cpp PowerPC/Interpreter/Interpreter.h + PowerPC/JitCommon/DivUtils.cpp + PowerPC/JitCommon/DivUtils.h PowerPC/JitCommon/JitAsmCommon.cpp PowerPC/JitCommon/JitAsmCommon.h PowerPC/JitCommon/JitBase.cpp diff --git a/Source/Core/Core/PowerPC/JitCommon/DivUtils.cpp b/Source/Core/Core/PowerPC/JitCommon/DivUtils.cpp new file mode 100644 index 0000000000..c19b7c8091 --- /dev/null +++ b/Source/Core/Core/PowerPC/JitCommon/DivUtils.cpp @@ -0,0 +1,57 @@ +// Copyright 2021 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include + +#include "Core/PowerPC/JitCommon/DivUtils.h" + +namespace JitCommon +{ +Magic SignedDivisionConstants(s32 d) +{ + const u32 two31 = 2147483648; + + const u32 ad = std::abs(d); + const u32 t = two31 - (d < 0); + const u32 anc = t - 1 - t % ad; + u32 q1 = two31 / anc; + u32 r1 = two31 - q1 * anc; + u32 q2 = two31 / ad; + u32 r2 = two31 - q2 * ad; + + s32 p = 31; + u32 delta; + + do + { + p++; + + q1 *= 2; + r1 *= 2; + if (r1 >= anc) + { + q1++; + r1 -= anc; + } + + q2 *= 2; + r2 *= 2; + if (r2 >= ad) + { + q2++; + r2 -= ad; + } + delta = ad - r2; + } while (q1 < delta || (q1 == delta && r1 == 0)); + + Magic mag; + mag.multiplier = q2 + 1; + if (d < 0) + mag.multiplier = -mag.multiplier; + mag.shift = p - 32; + + return mag; +} + +} // namespace JitCommon diff --git a/Source/Core/Core/PowerPC/JitCommon/DivUtils.h b/Source/Core/Core/PowerPC/JitCommon/DivUtils.h new file mode 100644 index 0000000000..b243e2654b --- /dev/null +++ b/Source/Core/Core/PowerPC/JitCommon/DivUtils.h @@ -0,0 +1,22 @@ +// Copyright 2021 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "Common/CommonTypes.h" + +namespace JitCommon +{ +struct Magic +{ + s32 multiplier; + u8 shift; +}; + +// Calculate the constants required to optimize a signed 32-bit integer division. +// Taken from The PowerPC Compiler Writer's Guide and LLVM. +// Divisor must not be -1, 0, and 1. +Magic SignedDivisionConstants(s32 divisor); + +} // namespace JitCommon diff --git a/Source/Core/DolphinLib.vcxproj b/Source/Core/DolphinLib.vcxproj index 5485304bdd..211b0a5423 100644 --- a/Source/Core/DolphinLib.vcxproj +++ b/Source/Core/DolphinLib.vcxproj @@ -27,6 +27,12 @@ {41279555-f94f-4ebc-99de-af863c10c5c4} + + + + + + \ No newline at end of file diff --git a/Source/UnitTests/DivUtilsTest.cpp b/Source/UnitTests/DivUtilsTest.cpp new file mode 100644 index 0000000000..7802fc8496 --- /dev/null +++ b/Source/UnitTests/DivUtilsTest.cpp @@ -0,0 +1,33 @@ +// Copyright 2021 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include + +#include "Core/PowerPC/JitCommon/DivUtils.h" + +using namespace JitCommon; + +TEST(DivUtils, Signed) +{ + Magic m3 = SignedDivisionConstants(3); + Magic m5 = SignedDivisionConstants(5); + Magic m7 = SignedDivisionConstants(7); + Magic minus3 = SignedDivisionConstants(-3); + Magic minus5 = SignedDivisionConstants(-5); + Magic minus7 = SignedDivisionConstants(-7); + + EXPECT_EQ(0x55555556, m3.multiplier); + EXPECT_EQ(0, m3.shift); + EXPECT_EQ(0x66666667, m5.multiplier); + EXPECT_EQ(1, m5.shift); + EXPECT_EQ(-0x6DB6DB6D, m7.multiplier); + EXPECT_EQ(2, m7.shift); + + EXPECT_EQ(-0x55555556, minus3.multiplier); + EXPECT_EQ(0, minus3.shift); + EXPECT_EQ(-0x66666667, minus5.multiplier); + EXPECT_EQ(1, minus5.shift); + EXPECT_EQ(0x6DB6DB6D, minus7.multiplier); + EXPECT_EQ(2, minus7.shift); +} diff --git a/Source/UnitTests/UnitTests.vcxproj b/Source/UnitTests/UnitTests.vcxproj index 230ac50412..5711a8614e 100644 --- a/Source/UnitTests/UnitTests.vcxproj +++ b/Source/UnitTests/UnitTests.vcxproj @@ -68,6 +68,7 @@ +