2014-11-08 06:40:28 +00:00
// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
2014-11-09 11:03:04 +00:00
# include <algorithm>
2020-08-29 15:45:50 +00:00
# include "ppsspp_config.h"
2020-10-04 08:30:18 +00:00
# include "Common/System/NativeApp.h"
# include "Common/System/System.h"
2020-08-15 18:53:08 +00:00
# include "Common/TimeUtil.h"
2018-06-17 01:42:31 +00:00
# include "Core/ConfigValues.h"
2021-04-24 22:48:17 +00:00
# include "Core/Debugger/SymbolMap.h"
2014-11-08 06:40:28 +00:00
# include "Core/MIPS/JitCommon/JitCommon.h"
2016-04-30 23:20:21 +00:00
# include "Core/MIPS/JitCommon/JitBlockCache.h"
2014-11-08 06:40:28 +00:00
# include "Core/MIPS/MIPSCodeUtils.h"
2014-11-08 21:30:38 +00:00
# include "Core/MIPS/MIPSDebugInterface.h"
# include "Core/MIPS/MIPSAsm.h"
2014-11-09 23:14:07 +00:00
# include "Core/MIPS/MIPSTables.h"
2021-04-24 22:48:17 +00:00
# include "Core/MIPS/MIPSVFPUUtils.h"
2014-11-08 06:40:28 +00:00
# include "Core/MemMap.h"
# include "Core/Core.h"
# include "Core/CoreTiming.h"
2023-09-23 18:19:27 +00:00
# include "Core/Config.h"
2014-11-08 06:40:28 +00:00
# include "Core/HLE/HLE.h"
// Temporary hacks around annoying linking errors. Copied from Headless.
2023-08-07 20:44:06 +00:00
void NativeFrame ( GraphicsContext * graphicsContext ) { }
2014-11-08 06:40:28 +00:00
void NativeResized ( ) { }
2024-04-06 10:04:45 +00:00
bool System_MakeRequest ( SystemRequestType type , int requestId , const std : : string & param1 , const std : : string & param2 , int64_t param3 , int64_t param4 ) { return false ; }
2020-03-09 01:59:17 +00:00
void System_InputBoxGetString ( const std : : string & title , const std : : string & defaultValue , std : : function < void ( bool , const std : : string & ) > cb ) { cb ( false , " " ) ; }
2015-12-17 21:41:50 +00:00
void System_AskForPermission ( SystemPermission permission ) { }
PermissionStatus System_GetPermissionStatus ( SystemPermission permission ) { return PERMISSION_STATUS_GRANTED ; }
2014-11-08 06:40:28 +00:00
void UnitTestTerminator ( ) {
2014-11-09 00:37:30 +00:00
// Bails out of jit so we can time things.
2014-11-08 06:49:56 +00:00
coreState = CORE_POWERDOWN ;
2014-11-09 00:37:30 +00:00
hleSkipDeadbeef ( ) ;
2014-11-08 06:40:28 +00:00
}
HLEFunction UnitTestFakeSyscalls [ ] = {
{ 0x1234BEEF , & UnitTestTerminator , " UnitTestTerminator " } ,
} ;
2023-09-23 18:19:27 +00:00
double ExecCPUTest ( bool clearCache = true ) {
2014-11-08 06:40:28 +00:00
int blockTicks = 1000000 ;
int total = 0 ;
2023-09-23 18:19:27 +00:00
if ( MIPSComp : : jit ) {
currentMIPS - > pc = PSP_GetUserMemoryBase ( ) ;
MIPSComp : : JitAt ( ) ;
}
2020-09-24 21:52:03 +00:00
double st = time_now_d ( ) ;
2014-11-08 06:40:28 +00:00
do {
for ( int j = 0 ; j < 1000 ; + + j ) {
currentMIPS - > pc = PSP_GetUserMemoryBase ( ) ;
coreState = CORE_RUNNING ;
while ( coreState = = CORE_RUNNING ) {
mipsr4k . RunLoopUntil ( blockTicks ) ;
}
+ + total ;
}
}
2020-09-24 21:52:03 +00:00
while ( time_now_d ( ) - st < 0.5 ) ;
double elapsed = time_now_d ( ) - st ;
2014-11-08 06:40:28 +00:00
2023-09-23 18:19:27 +00:00
if ( MIPSComp : : jit ) {
JitBlockCacheDebugInterface * cache = MIPSComp : : jit - > GetBlockCacheDebugInterface ( ) ;
if ( cache ) {
JitBlockDebugInfo block = cache - > GetBlockDebugInfo ( 0 ) ;
2024-07-14 12:42:59 +00:00
WARN_LOG ( Log : : JIT , " Executed %d target instrs, %d IR, for %d orig " , ( int ) block . targetDisasm . size ( ) , ( int ) block . irDisasm . size ( ) , ( int ) block . origDisasm . size ( ) ) ;
2023-09-23 18:19:27 +00:00
}
if ( clearCache )
MIPSComp : : jit - > ClearCache ( ) ;
}
2014-11-08 06:40:28 +00:00
return total / elapsed ;
}
static void SetupJitHarness ( ) {
// We register a syscall so we have an easy way to finish the test.
RegisterModule ( " UnitTestFakeSyscalls " , ARRAY_SIZE ( UnitTestFakeSyscalls ) , UnitTestFakeSyscalls ) ;
// This is pretty much the bare minimum required to setup jit.
coreState = CORE_POWERUP ;
currentMIPS = & mipsr4k ;
2021-04-24 22:48:17 +00:00
g_symbolMap = new SymbolMap ( ) ;
2014-11-08 06:40:28 +00:00
Memory : : g_MemorySize = Memory : : RAM_NORMAL_SIZE ;
2017-03-02 11:36:54 +00:00
PSP_CoreParameter ( ) . cpuCore = CPUCore : : INTERPRETER ;
2021-08-17 14:48:47 +00:00
PSP_CoreParameter ( ) . fastForward = true ;
2014-11-08 06:40:28 +00:00
Memory : : Init ( ) ;
mipsr4k . Reset ( ) ;
CoreTiming : : Init ( ) ;
2023-03-10 04:23:33 +00:00
InitVFPU ( ) ;
2014-11-08 06:40:28 +00:00
}
static void DestroyJitHarness ( ) {
// Clear our custom module out to be safe.
HLEShutdown ( ) ;
CoreTiming : : Shutdown ( ) ;
mipsr4k . Shutdown ( ) ;
2017-05-07 01:45:04 +00:00
Memory : : Shutdown ( ) ;
2014-11-08 06:40:28 +00:00
coreState = CORE_POWERDOWN ;
currentMIPS = nullptr ;
2021-04-24 22:48:17 +00:00
delete g_symbolMap ;
2014-11-08 06:40:28 +00:00
}
bool TestJit ( ) {
SetupJitHarness ( ) ;
2023-09-23 18:19:27 +00:00
g_Config . bFastMemory = true ;
2014-11-08 06:40:28 +00:00
currentMIPS - > pc = PSP_GetUserMemoryBase ( ) ;
u32 * p = ( u32 * ) Memory : : GetPointer ( currentMIPS - > pc ) ;
// TODO: Smarter way of seeding in the code sequence.
2014-11-09 00:37:30 +00:00
static const char * lines [ ] = {
2014-11-29 10:37:45 +00:00
//"vcrsp.t C000, C100, C200",
2014-11-30 18:27:43 +00:00
//"vdot.q C000, C100, C200",
2014-11-29 10:37:45 +00:00
//"vmmul.q M000, M100, M200",
2014-11-30 18:27:43 +00:00
" lui r1, 0x8910 " ,
" vmmul.q M000, M100, M200 " ,
" sv.q C000, 0(r1) " ,
" sv.q C000, 16(r1) " ,
" sv.q C000, 32(r1) " ,
" sv.q C000, 48(r1) " ,
2014-11-29 10:37:45 +00:00
/*
2014-11-09 00:37:30 +00:00
" abs.s f1, f1 " ,
" cvt.w.s f1, f1 " ,
" cvt.w.s f3, f1 " ,
" cvt.w.s f0, f2 " ,
" cvt.w.s f5, f1 " ,
" cvt.w.s f6, f5 " ,
2014-11-29 10:37:45 +00:00
*/
2014-11-09 00:37:30 +00:00
} ;
bool compileSuccess = true ;
u32 addr = currentMIPS - > pc ;
DebugInterface * dbg = currentDebugMIPS ;
2014-11-08 06:40:28 +00:00
for ( int i = 0 ; i < 100 ; + + i ) {
2014-11-09 00:37:30 +00:00
/*
// VFPU ops aren't supported by MIPSAsm yet.
2014-11-08 19:31:54 +00:00
* p + + = 0xD03C0000 | ( 1 < < 7 ) | ( 1 < < 15 ) | ( 7 < < 8 ) ;
* p + + = 0xD03C0000 | ( 1 < < 7 ) | ( 1 < < 15 ) ;
* p + + = 0xD03C0000 | ( 1 < < 7 ) | ( 1 < < 15 ) | ( 7 < < 8 ) ;
* p + + = 0xD03C0000 | ( 1 < < 7 ) | ( 1 < < 15 ) | ( 7 < < 8 ) ;
* p + + = 0xD03C0000 | ( 1 < < 7 ) | ( 1 < < 15 ) | ( 7 < < 8 ) ;
* p + + = 0xD03C0000 | ( 1 < < 7 ) | ( 1 < < 15 ) | ( 7 < < 8 ) ;
* p + + = 0xD03C0000 | ( 1 < < 7 ) | ( 1 < < 15 ) | ( 7 < < 8 ) ;
2014-11-09 00:37:30 +00:00
*/
for ( size_t j = 0 ; j < ARRAY_SIZE ( lines ) ; + + j ) {
2014-11-21 23:11:28 +00:00
p + + ;
if ( ! MIPSAsm : : MipsAssembleOpcode ( lines [ j ] , currentDebugMIPS , addr ) ) {
2022-01-17 19:13:24 +00:00
printf ( " ERROR: %s \n " , MIPSAsm : : GetAssembleError ( ) . c_str ( ) ) ;
2014-11-09 00:37:30 +00:00
compileSuccess = false ;
}
addr + = 4 ;
}
2014-11-08 06:40:28 +00:00
}
* p + + = MIPS_MAKE_SYSCALL ( " UnitTestFakeSyscalls " , " UnitTestTerminator " ) ;
* p + + = MIPS_MAKE_BREAK ( 1 ) ;
2023-09-23 18:19:27 +00:00
* p + + = MIPS_MAKE_JR_RA ( ) ;
2014-11-08 06:40:28 +00:00
2014-11-09 23:14:07 +00:00
// Dogfood.
addr = currentMIPS - > pc ;
for ( size_t j = 0 ; j < ARRAY_SIZE ( lines ) ; + + j ) {
char line [ 512 ] ;
2023-04-29 16:07:25 +00:00
MIPSDisAsm ( Memory : : Read_Instruction ( addr ) , addr , line , sizeof ( line ) , true ) ;
2014-11-09 23:14:07 +00:00
addr + = 4 ;
printf ( " %s \n " , line ) ;
}
2014-11-09 11:03:04 +00:00
printf ( " \n " ) ;
2023-09-23 18:19:27 +00:00
double jit_speed = 0.0 , jit_ir_speed = 0.0 , ir_speed = 0.0 , interp_speed = 0.0 ;
2014-11-09 00:37:30 +00:00
if ( compileSuccess ) {
interp_speed = ExecCPUTest ( ) ;
2023-09-23 18:19:27 +00:00
mipsr4k . UpdateCore ( CPUCore : : IR_INTERPRETER ) ;
ir_speed = ExecCPUTest ( ) ;
2017-03-02 11:36:54 +00:00
mipsr4k . UpdateCore ( CPUCore : : JIT ) ;
2014-11-09 00:37:30 +00:00
jit_speed = ExecCPUTest ( ) ;
2024-04-29 08:31:42 +00:00
# if !PPSSPP_PLATFORM(MAC)
2023-09-23 18:19:27 +00:00
mipsr4k . UpdateCore ( CPUCore : : JIT_IR ) ;
jit_ir_speed = ExecCPUTest ( false ) ;
2024-04-29 08:31:42 +00:00
# endif
2014-11-08 06:40:28 +00:00
2014-11-09 11:03:04 +00:00
// Disassemble
2023-07-17 01:51:20 +00:00
JitBlockCacheDebugInterface * cache = MIPSComp : : jit - > GetBlockCacheDebugInterface ( ) ;
if ( cache ) {
JitBlockDebugInfo block = cache - > GetBlockDebugInfo ( 0 ) ; // Should only be one block.
std : : vector < std : : string > & lines = block . targetDisasm ;
// Cut off at 25 due to the repetition above. Might need tweaking for large instructions.
2023-09-23 18:19:27 +00:00
const int cutoff = 50 ;
2023-07-17 01:51:20 +00:00
for ( int i = 0 ; i < std : : min ( ( int ) lines . size ( ) , cutoff ) ; i + + ) {
printf ( " %s \n " , lines [ i ] . c_str ( ) ) ;
}
if ( lines . size ( ) > cutoff )
printf ( " ... \n " ) ;
2014-11-09 11:03:04 +00:00
}
2023-09-23 18:19:27 +00:00
printf ( " Jit was %fx faster than interp, IR was %fx faster, JIT IR %fx. \n \n " , jit_speed / interp_speed , ir_speed / interp_speed , jit_ir_speed / interp_speed ) ;
2014-11-09 00:37:30 +00:00
}
2014-11-08 06:40:28 +00:00
2014-11-09 11:03:04 +00:00
printf ( " \n " ) ;
2014-11-08 06:40:28 +00:00
DestroyJitHarness ( ) ;
return jit_speed > = interp_speed ;
2015-12-17 21:41:50 +00:00
}