dolphin-emulator/Source/Core/Core
Pierre Bourdon 0ff1481494 Optimize PPC CR emulation by using magic 64 bit values
PowerPC has a 32 bit CR register, which is used to store flags for results of
computations. Most instructions have an optional bit that tells the CPU whether
the flags should be updated. This 32 bit register actually contains 8 sets of 4
flags: Summary Overflow (SO), Equals (EQ), Greater Than (GT), Less Than (LT).
These 8 sets are usually called CR0-CR7 and accessed independently. In the most
common operations, the flags are computed from the result of the operation in
the following fashion:
  * EQ is set iff result == 0
  * LT is set iff result < 0
  * GT is set iff result > 0
  * (Dolphin does not emulate SO)

While X86 architectures have a similar concept of flags, it is very difficult
to access the FLAGS register directly to translate its value to an equivalent
PowerPC value. With the current Dolphin implementation, updating a PPC CR
register requires CPU branching, which has a few performance issues: it uses
space in the BTB, and in the worst case (!GT, !LT, EQ) requires 2 branches not
taken.

After some brainstorming on IRC about how this could be improved, calc84maniac
figured out a neat trick that makes common CR operations way more efficient to
JIT on 64 bit X86 architectures. It relies on emulating each CRn bitfield with
a 64 bit register internally, whose value is the result of the operation from
which flags are updated, sign extended to 64 bits. Then, checking if a CR bit
is set can be done in the following way:
  * EQ is set iff LOWER_32_BITS(cr_64b_val) == 0
  * GT is set iff (s64)cr_64b_val > 0
  * LT is set iff bit 62 of cr_64b_val is set

To take a few examples, if the result of an operation is:
  * -1 (0xFFFFFFFFFFFFFFFF) -> lower 32 bits not 0       => !EQ
                            -> (s64)val (-1) is not > 0  => !GT
                            -> bit 62 is set             =>  LT
            !EQ, !GT, LT

  *  0 (0x0000000000000000) -> lower 32 bits are 0       =>  EQ
                            -> (s64)val (0) is not > 0   => !GT
                            -> bit 62 is not set         => !LT
            EQ, !GT, !LT

  *  1 (0x0000000000000001) -> lower 32 bits not 0       => !EQ
                            -> (s64)val (1) is > 0       =>  GT
                            -> bit 62 is not set         => !LT
            !EQ, GT, !LT

Sometimes we need to convert PPC CR values to these 64 bit values. The
following convention is used in this case:
  * Bit 0 (LSB) is set iff !EQ
  * Bit 62 is set iff LT
  * Bit 63 is set iff !GT
  * Bit 32 always set to disambiguize between EQ and GT

Some more examples:
  * !EQ, GT, LT -> 0x4000000100000001 (!B63, B62, B32, B0)
                -> lower 32 bits not 0          => !EQ
                -> (s64)val is > 0              =>  GT
                -> bit 62 is set                =>  LT
  * EQ, GT, !LT -> 0x0000000100000000
                -> lower 32 bits are 0          =>  EQ
                -> (s64)val is > 0 (note: B32)  =>  GT
                -> bit 62 is not set            => !LT
2014-07-30 21:41:17 -07:00
..
Boot Core: Get rid of an unnecessary struct typedef in Boot.h. 2014-07-13 15:28:50 -04:00
Debugger mark all local functions as static 2014-07-11 16:07:23 +02:00
DSP Get rid of a few C-style struct declarations 2014-07-23 20:36:45 -04:00
FifoPlayer Revert "Don't add segfault handler in interpreter mode" 2014-07-07 05:30:06 +02:00
HLE Fix warnings unearthed by #579 2014-07-13 02:16:51 +02:00
HW Convert some more header inclusions into forward declarations 2014-07-29 20:55:07 -04:00
IPC_HLE Convert some more header inclusions into forward declarations 2014-07-29 20:55:07 -04:00
PowerPC Optimize PPC CR emulation by using magic 64 bit values 2014-07-30 21:41:17 -07:00
ActionReplay.cpp Centralize the logging code into its own folder in Common. 2014-06-25 22:11:42 -04:00
ActionReplay.h Convert all includes to relative paths. 2014-02-18 02:19:10 -05:00
ARDecrypt.cpp mark all local variables as static 2014-07-11 16:10:20 +02:00
ARDecrypt.h Convert all includes to relative paths. 2014-02-18 02:19:10 -05:00
ArmMemTools.cpp clang-modernize -use-nullptr 2014-03-09 21:14:26 +01:00
BootManager.cpp Revert "Don't add segfault handler in interpreter mode" 2014-07-07 05:30:06 +02:00
BootManager.h Replace all include guard ifdefs with "#pragma once" 2014-02-10 18:07:16 -05:00
CMakeLists.txt remove unused globals 2014-07-11 16:10:20 +02:00
ConfigManager.cpp ControllerEmu: Make BackgroundInput a global setting through the virtualization 2014-07-11 13:38:37 -04:00
ConfigManager.h ControllerEmu: Make BackgroundInput a global setting through the virtualization 2014-07-11 13:38:37 -04:00
Core.cpp Merge pull request #667 from RachelBryk/remove-audio-limit 2014-07-28 14:38:35 +02:00
Core.h mark all local variables as static 2014-07-11 16:10:20 +02:00
Core.vcxproj Remove fakepoll.h. 2014-07-26 22:53:40 -04:00
Core.vcxproj.filters Remove fakepoll.h. 2014-07-26 22:53:40 -04:00
CoreParameter.cpp Revert "Don't add segfault handler in interpreter mode" 2014-07-07 05:30:06 +02:00
CoreParameter.h Revert "Don't add segfault handler in interpreter mode" 2014-07-07 05:30:06 +02:00
CoreTiming.cpp Core: Turn some includes into forward declarations. 2014-07-27 13:37:09 -04:00
CoreTiming.h Core: Turn some includes into forward declarations. 2014-07-27 13:37:09 -04:00
DSPEmulator.cpp Fix more header sorting issues in Core/ (now check-includes clean). 2014-02-20 01:01:11 +01:00
DSPEmulator.h Core: Get rid of the void handle parameter for DSP initialization 2014-07-26 16:54:36 -04:00
ec_wii.cpp Fix warnings unearthed by #579 2014-07-13 02:16:51 +02:00
ec_wii.h Fix warnings unearthed by #579 2014-07-13 02:16:51 +02:00
GeckoCode.cpp mark all local variables as static 2014-07-11 16:10:20 +02:00
GeckoCode.h Convert all includes to relative paths. 2014-02-18 02:19:10 -05:00
GeckoCodeConfig.cpp Core: Turn some includes into forward declarations. 2014-07-27 13:37:09 -04:00
GeckoCodeConfig.h Core: Turn some includes into forward declarations. 2014-07-27 13:37:09 -04:00
Host.h Cosmetic changes based on feedback on PR #506. 2014-07-26 13:04:39 +02:00
MemTools.h Convert all includes to relative paths. 2014-02-18 02:19:10 -05:00
Movie.cpp Core: Turn some includes into forward declarations. 2014-07-27 13:37:09 -04:00
Movie.h Core: Turn some includes into forward declarations. 2014-07-27 13:37:09 -04:00
NetPlayClient.cpp mark all local variables as static 2014-07-11 16:10:20 +02:00
NetPlayClient.h Change SPADStatus struct name to GCPadStatus 2014-07-10 22:02:38 -04:00
NetPlayProto.h Revert "Don't add segfault handler in interpreter mode" 2014-07-07 05:30:06 +02:00
NetPlayServer.cpp Revert "Don't add segfault handler in interpreter mode" 2014-07-07 05:30:06 +02:00
NetPlayServer.h Add an option to kick players from netplay. 2014-06-18 13:22:45 -04:00
PatchEngine.cpp Core: Turn some includes into forward declarations. 2014-07-27 13:37:09 -04:00
PatchEngine.h Core: Turn some includes into forward declarations. 2014-07-27 13:37:09 -04:00
State.cpp DTK: Adjustments attempting to increase accuracy 2014-07-27 03:15:52 +08:00
State.h Various changes suggested by cppcheck 2014-02-28 12:43:20 +01:00
stdafx.cpp
stdafx.h Remove fakepoll.h. 2014-07-26 22:53:40 -04:00
Tracer.cpp mark all local variables as static 2014-07-11 16:10:20 +02:00
Tracer.h Replace all include guard ifdefs with "#pragma once" 2014-02-10 18:07:16 -05:00
VolumeHandler.cpp mark all local variables as static 2014-07-11 16:10:20 +02:00
VolumeHandler.h Convert all includes to relative paths. 2014-02-18 02:19:10 -05:00
x64MemTools.cpp Fix warnings unearthed by #579 2014-07-13 02:16:51 +02:00