From 7a3158a693dc657c722f055d68725711b8a55d92 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 11 Apr 2018 18:51:59 -0400 Subject: [PATCH 1/2] Interpreter_FPUtils: Don't use a union to type-pun between integral and FP types The previous code invokes undefined behavior. memcpy will optimize away to the relevant loads and stores while maintaining well-defined behavior. --- .../PowerPC/Interpreter/Interpreter_FPUtils.h | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h index d2adcd7b6f..8ddd9a7d72 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include "Common/CPUDetect.h" @@ -71,16 +72,28 @@ inline double ForceDouble(double d) inline double Force25Bit(double d) { - MathUtil::IntDouble x(d); - x.i = (x.i & 0xFFFFFFFFF8000000ULL) + (x.i & 0x8000000); - return x.d; + u64 integral; + std::memcpy(&integral, &d, sizeof(u64)); + + integral = (integral & 0xFFFFFFFFF8000000ULL) + (integral & 0x8000000); + + double result; + std::memcpy(&result, &integral, sizeof(double)); + + return result; } inline double MakeQuiet(double d) { - MathUtil::IntDouble x(d); - x.i |= MathUtil::DOUBLE_QBIT; - return x.d; + u64 integral; + std::memcpy(&integral, &d, sizeof(u64)); + + integral |= MathUtil::DOUBLE_QBIT; + + double result; + std::memcpy(&result, &integral, sizeof(double)); + + return result; } // these functions allow globally modify operations behaviour From ab25eb6449654c14a1c5778833e34f76019c16ae Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 11 Apr 2018 19:01:17 -0400 Subject: [PATCH 2/2] Interpreter_LoadStorePaired: Don't use a union to type-pun between integral and FP types --- .../Interpreter_LoadStorePaired.cpp | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStorePaired.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStorePaired.cpp index 2661804c71..5c9fbce27b 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStorePaired.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStorePaired.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #include #include @@ -172,21 +173,28 @@ void Interpreter::Helper_Quantize(u32 addr, u32 instI, u32 instRS, u32 instW) const EQuantizeType stType = gqr.st_type; const unsigned int stScale = gqr.st_scale; - double ps0 = rPS0(instRS); - double ps1 = rPS1(instRS); + const double ps0 = rPS0(instRS); + const double ps1 = rPS1(instRS); + switch (stType) { case QUANTIZE_FLOAT: { - u32 convPS0 = ConvertToSingleFTZ(MathUtil::IntDouble(ps0).i); + u64 integral_ps0; + std::memcpy(&integral_ps0, &ps0, sizeof(u64)); + + const u32 conv_ps0 = ConvertToSingleFTZ(integral_ps0); if (instW) { - WriteUnpaired(convPS0, addr); + WriteUnpaired(conv_ps0, addr); } else { - u32 convPS1 = ConvertToSingleFTZ(MathUtil::IntDouble(ps1).i); - WritePair(convPS0, convPS1, addr); + u64 integral_ps1; + std::memcpy(&integral_ps1, &ps1, sizeof(double)); + + const u32 conv_ps1 = ConvertToSingleFTZ(integral_ps1); + WritePair(conv_ps0, conv_ps1, addr); } break; } @@ -249,15 +257,15 @@ void Interpreter::Helper_Dequantize(u32 addr, u32 instI, u32 instRD, u32 instW) case QUANTIZE_FLOAT: if (instW) { - u32 value = ReadUnpaired(addr); - ps0 = MathUtil::IntFloat(value).f; + const u32 value = ReadUnpaired(addr); + std::memcpy(&ps0, &value, sizeof(float)); ps1 = 1.0f; } else { - std::pair value = ReadPair(addr); - ps0 = MathUtil::IntFloat(value.first).f; - ps1 = MathUtil::IntFloat(value.second).f; + const std::pair value = ReadPair(addr); + std::memcpy(&ps0, &value.first, sizeof(float)); + std::memcpy(&ps1, &value.second, sizeof(float)); } break;