Improved SSE detection:

* SSE3 detection via cpuid implemented.  [fixes Linux -- the force_sse3 option should no longer be needed!]

 * Instruction tests are now done for SSE3, SSE4, and SSE4.1 to confirm cpuid results (I doubt this is necessary, but the old code did it for SSE3, so I figured I'd keep it and log results anytime an inconsistency is detected).

 * SSE4.2 and SSE4a detection added.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@1086 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
Jake.Stine 2009-04-29 10:10:33 +00:00
parent 6e82c77e92
commit 41079415fa
3 changed files with 94 additions and 38 deletions

View File

@ -135,13 +135,15 @@ void SysDetect()
"\t%sDetected SSE2\n"
"\t%sDetected SSE3\n"
"\t%sDetected SSSE3\n"
"\t%sDetected SSE4.1\n", params
"\t%sDetected SSE4.1\n"
"\t%sDetected SSE4.2\n", params
cpucaps.hasMultimediaExtensions ? "" : "Not ",
cpucaps.hasStreamingSIMDExtensions ? "" : "Not ",
cpucaps.hasStreamingSIMD2Extensions ? "" : "Not ",
cpucaps.hasStreamingSIMD3Extensions ? "" : "Not ",
cpucaps.hasSupplementalStreamingSIMD3Extensions ? "" : "Not ",
cpucaps.hasStreamingSIMD4Extensions ? "" : "Not "
cpucaps.hasStreamingSIMD4Extensions ? "" : "Not ",
cpucaps.hasStreamingSIMD4Extensions2 ? "" : "Not "
);
if ( cpuinfo.x86ID[0] == 'A' ) //AMD cpu
@ -150,10 +152,12 @@ void SysDetect()
WriteLn(
"\t%sDetected MMX2\n"
"\t%sDetected 3DNOW\n"
"\t%sDetected 3DNOW2\n", params
"\t%sDetected 3DNOW2\n"
"\t%sDetected SSE4a\n", params
cpucaps.hasMultimediaExtensionsExt ? "" : "Not ",
cpucaps.has3DNOWInstructionExtensions ? "" : "Not ",
cpucaps.has3DNOWInstructionExtensionsExt ? "" : "Not "
cpucaps.has3DNOWInstructionExtensionsExt ? "" : "Not ",
cpucaps.hasStreamingSIMD4ExtensionsA ? "" : "Not "
);
}

View File

@ -23,6 +23,8 @@
#include "RedtapeWindows.h"
using namespace x86Emitter;
#if defined (_MSC_VER) && _MSC_VER >= 1400
extern "C"
@ -148,31 +150,29 @@ u64 GetCPUTick( void )
#endif
}
//////////////////////////////////////////////////////////////////////////////////////////
// Note: This function doesn't support GCC/Linux. Looking online it seems the only
// way to simulate the Micrsoft SEH model is to use unix signals, and the 'sigaction'
// function specifically. Maybe a project for a linux developer at a later date. :)
void cpudetectSSE3(void* pfnCallSSE3)
{
cpucaps.hasStreamingSIMD3Extensions = 1;
#ifdef _MSC_VER
static bool _test_instruction( void* pfnCall )
{
__try {
((void (*)())pfnCallSSE3)();
((void (*)())pfnCall)();
}
__except(EXCEPTION_EXECUTE_HANDLER) {
cpucaps.hasStreamingSIMD3Extensions = 0;
return false;
}
#else // linux
#ifdef PCSX2_FORCESSE3
cpucaps.hasStreamingSIMD3Extensions = 1;
#else
// exception handling doesn't work, so disable for x86 builds of linux
cpucaps.hasStreamingSIMD3Extensions = 0;
#endif
#endif
return true;
}
static char* bool_to_char( bool testcond )
{
return testcond ? "true" : "false";
}
#endif
#if defined __LINUX__
#include <sys/time.h>
@ -180,6 +180,8 @@ void cpudetectSSE3(void* pfnCallSSE3)
#endif
//////////////////////////////////////////////////////////////////////////////////////////
//
s64 CPUSpeedHz( unsigned int time )
{
s64 timeStart,
@ -197,9 +199,10 @@ s64 CPUSpeedHz( unsigned int time )
timeStart = timeGetTime( );
while( timeGetTime( ) == timeStart )
{
timeStart = timeGetTime( );
}
{
timeStart = timeGetTime( );
}
for(;;)
{
timeStop = timeGetTime( );
@ -294,6 +297,7 @@ void cpudetectInit()
if ( iCpuId( 0x80000001, regs ) != -1 )
{
x86_64_12BITBRANDID = regs[1] & 0xfff;
cpuinfo.x86EFlags2 = regs[ 2 ];
cpuinfo.x86EFlags = regs[ 3 ];
}
@ -364,40 +368,85 @@ void cpudetectInit()
cpucaps.hasMultiThreading = ( cpuinfo.x86Flags >> 28 ) & 1;
cpucaps.hasThermalMonitor = ( cpuinfo.x86Flags >> 29 ) & 1;
cpucaps.hasIntel64BitArchitecture = ( cpuinfo.x86Flags >> 30 ) & 1;
//that is only for AMDs
cpucaps.hasMultimediaExtensionsExt = ( cpuinfo.x86EFlags >> 22 ) & 1; //mmx2
cpucaps.hasAMD64BitArchitecture = ( cpuinfo.x86EFlags >> 29 ) & 1; //64bit cpu
cpucaps.has3DNOWInstructionExtensionsExt = ( cpuinfo.x86EFlags >> 30 ) & 1; //3dnow+
cpucaps.has3DNOWInstructionExtensions = ( cpuinfo.x86EFlags >> 31 ) & 1; //3dnow
cpucaps.hasStreamingSIMD4ExtensionsA = ( cpuinfo.x86EFlags2 >> 6 ) & 1; //INSERTQ / EXTRQ / MOVNT
cpuinfo.cpuspeed = (u32)(CPUSpeedHz( 1000 ) / 1000000);
// --> SSE 4.1 detection <--
// We don't care about the small subset of CPUs using SSE4 (which is also hard to
// detect, in addition to being of limited use due to the abbreviated instruction set).
// So we'll just leave it at SSE 4.1. SSE4 cpu detection is ignored.
cpuinfo.cpuspeed = (u32)(CPUSpeedHz( 600 ) / 1000000);
cpucaps.hasStreamingSIMD4Extensions = ( cpuinfo.x86Flags2 >> 19 ) & 1; //sse4.1
// --> SSSE3 detection <--
// --> SSE3 / SSSE3 / SSE4.1 / SSE 4.2 detection <--
cpucaps.hasStreamingSIMD3Extensions = ( cpuinfo.x86Flags2 >> 0 ) & 1; //sse3
cpucaps.hasSupplementalStreamingSIMD3Extensions = ( cpuinfo.x86Flags2 >> 9 ) & 1; //ssse3
cpucaps.hasStreamingSIMD4Extensions = ( cpuinfo.x86Flags2 >> 19 ) & 1; //sse4.1
cpucaps.hasStreamingSIMD4Extensions2 = ( cpuinfo.x86Flags2 >> 20 ) & 1; //sse4.2
// --> SSE3 detection <--
// These instructions may not be recognized by some compilers, or may not have
// intrinsic equivalents available. So we use our own ix86 emitter to generate
// some code and run it that way. :)
// Can the SSE3 / SSE4.1 bits be trusted? Using an instruction test is a very "complete"
// approach to ensuring the bit is accurate, and at least one reported case of a Q9550 not
// having SSE 4.1 set but still supporting it properly is fixed by this --air
#ifdef _MSC_VER
u8* recSSE = (u8*)HostSys::Mmap( NULL, 0x1000 );
if( recSSE != NULL )
{
x86SetPtr(recSSE);
SSE3_MOVSLDUP_XMM_to_XMM(XMM0, XMM0);
xSetPtr( recSSE );
xMOVSLDUP( xmm1, xmm0 );
RET();
cpudetectSSE3(recSSE);
u8* funcSSSE3 = xGetPtr();
xPABS.W( xmm0, xmm1 );
RET();
u8* funcSSE41 = xGetPtr();
xBLEND.VPD( xmm1, xmm0 );
RET();
bool sse3_result = _test_instruction( recSSE ); // sse3
bool ssse3_result = _test_instruction( funcSSSE3 );
bool sse41_result = _test_instruction( funcSSE41 );
HostSys::Munmap( recSSE, 0x1000 );
// Test for and log any irregularities here.
// We take the instruction test result over cpuid since (in theory) it should be a
// more reliable gauge of the cpu's actual ability.
if( sse3_result != cpucaps.hasStreamingSIMD3Extensions )
{
Console::Notice( "SSE3 Detection Inconsistency: cpuid=%s, test_result=%s",
params bool_to_char( cpucaps.hasStreamingSIMD3Extensions ), bool_to_char( sse3_result ) );
cpucaps.hasStreamingSIMD3Extensions = sse3_result;
}
if( ssse3_result != cpucaps.hasSupplementalStreamingSIMD3Extensions )
{
Console::Notice( "SSSE3 Detection Inconsistency: cpuid=%s, test_result=%s",
params bool_to_char( cpucaps.hasSupplementalStreamingSIMD3Extensions ), bool_to_char( ssse3_result ) );
cpucaps.hasSupplementalStreamingSIMD3Extensions = ssse3_result;
}
if( sse41_result != cpucaps.hasStreamingSIMD4Extensions )
{
Console::Notice( "SSE4 Detection Inconsistency: cpuid=%s, test_result=%s",
params bool_to_char( cpucaps.hasStreamingSIMD4Extensions ), bool_to_char( sse41_result ) );
cpucaps.hasStreamingSIMD4Extensions = sse41_result;
}
}
else { Console::Error("Error: Failed to allocate memory for SSE3 State detection."); }
else
Console::Notice(
"Notice: Could not allocate memory for SSE3/4 detection.\n"
"\tRelying on CPUID results. [this is not an error]"
);
#endif
//////////////////////////////////////
// Core Counting!

View File

@ -54,12 +54,14 @@ struct CAPABILITIES
u32 hasStreamingSIMD3Extensions;
u32 hasSupplementalStreamingSIMD3Extensions;
u32 hasStreamingSIMD4Extensions;
u32 hasStreamingSIMD4Extensions2;
// AMD-specific CPU Features
u32 hasMultimediaExtensionsExt;
u32 hasAMD64BitArchitecture;
u32 has3DNOWInstructionExtensionsExt;
u32 has3DNOWInstructionExtensions;
u32 hasStreamingSIMD4ExtensionsA;
};
extern CAPABILITIES cpucaps;
@ -73,6 +75,7 @@ struct CPUINFO
u32 x86Flags; // Feature Flags
u32 x86Flags2; // More Feature Flags
u32 x86EFlags; // Extended Feature Flags
u32 x86EFlags2; // Extended Feature Flags pg2
u32 PhysicalCores;
u32 LogicalCores;