2013-12-19 17:10:14 +00:00
/*
Some WIP optimisation stuff and maby helper functions for shil
*/
# include "types.h"
# include "shil.h"
# include "decoder.h"
# include "hw/sh4/sh4_mem.h"
# include "blockmanager.h"
u32 RegisterWrite [ sh4_reg_count ] ;
u32 RegisterRead [ sh4_reg_count ] ;
void RegReadInfo ( shil_param p , size_t ord )
{
if ( p . is_reg ( ) )
{
2013-12-25 17:47:51 +00:00
for ( u32 i = 0 ; i < p . count ( ) ; i + + )
2013-12-19 17:10:14 +00:00
RegisterRead [ p . _reg + i ] = ord ;
}
}
void RegWriteInfo ( shil_opcode * ops , shil_param p , size_t ord )
{
if ( p . is_reg ( ) )
{
2013-12-25 17:47:51 +00:00
for ( u32 i = 0 ; i < p . count ( ) ; i + + )
2013-12-19 17:10:14 +00:00
{
if ( RegisterWrite [ p . _reg + i ] > = RegisterRead [ p . _reg + i ] & & RegisterWrite [ p . _reg + i ] ! = 0xFFFFFFFF ) //if last read was before last write, and there was a last write
{
printf ( " DEAD OPCODE %d %d! \n " , RegisterWrite [ p . _reg + i ] , ord ) ;
2013-12-24 00:56:44 +00:00
ops [ RegisterWrite [ p . _reg + i ] ] . Flow = 1 ; //the last write was unused
2013-12-19 17:10:14 +00:00
}
RegisterWrite [ p . _reg + i ] = ord ;
}
}
}
u32 fallback_blocks ;
u32 total_blocks ;
u32 REMOVED_OPS ;
bool isdst ( shil_opcode * op , Sh4RegType rd )
{
return ( op - > rd . is_r32 ( ) & & op - > rd . _reg = = rd ) | | ( op - > rd2 . is_r32 ( ) & & op - > rd2 . _reg = = rd ) ;
}
//really hacky ~
//Isn't this now obsolete anyway ? (constprop pass should include it ..)
// -> constprop has some small stability issues still, not ready to be used on ip/bios fully yet
void PromoteConstAddress ( RuntimeBlockInfo * blk )
{
bool is_const = false ;
u32 value ;
total_blocks + + ;
for ( size_t i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
shil_opcode * op = & blk - > oplist [ i ] ;
if ( is_const & & op - > op = = shop_readm & & op - > rs1 . is_reg ( ) & & op - > rs1 . _reg = = reg_r0 )
{
u32 val = value ;
if ( op - > rs3 . is_imm ( ) )
{
val + = op - > rs3 . _imm ;
op - > rs3 = shil_param ( ) ;
}
op - > rs1 = shil_param ( FMT_IMM , val ) ;
}
if ( op - > op = = shop_mov32 & & op - > rs1 . is_imm ( ) & & isdst ( op , reg_r0 ) )
{
is_const = true ;
value = op - > rs1 . _imm ;
}
else if ( is_const & & ( isdst ( op , reg_r0 ) | | op - > op = = shop_ifb | | op - > op = = shop_sync_sr ) )
is_const = false ;
}
}
void sq_pref ( RuntimeBlockInfo * blk , int i , Sh4RegType rt , bool mark )
{
u32 data = 0 ;
for ( int c = i - 1 ; c > 0 ; c - - )
{
if ( blk - > oplist [ c ] . op = = shop_writem & & blk - > oplist [ c ] . rs1 . _reg = = rt )
{
if ( blk - > oplist [ c ] . rs2 . is_r32i ( ) | | blk - > oplist [ c ] . rs2 . is_r32f ( ) | | blk - > oplist [ c ] . rs2 . is_r64f ( ) | | blk - > oplist [ c ] . rs2 . is_r32fv ( ) )
{
data + = blk - > oplist [ c ] . flags ;
if ( mark )
blk - > oplist [ c ] . flags2 = 0x1337 ;
}
else
break ;
}
if ( blk - > oplist [ c ] . op = = shop_pref | | ( blk - > oplist [ c ] . rd . is_reg ( ) & & blk - > oplist [ c ] . rd . _reg = = rt & & blk - > oplist [ c ] . op ! = shop_sub ) )
{
break ;
}
if ( data = = 32 )
break ;
}
if ( mark ) return ;
if ( data > = 8 )
{
blk - > oplist [ i ] . flags = 0x1337 ;
sq_pref ( blk , i , rt , true ) ;
printf ( " SQW-WM match %d ! \n " , data ) ;
}
else if ( data )
{
printf ( " SQW-WM FAIL %d ! \n " , data ) ;
}
}
void sq_pref ( RuntimeBlockInfo * blk )
{
for ( int i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
blk - > oplist [ i ] . flags2 = 0 ;
if ( blk - > oplist [ i ] . op = = shop_pref )
sq_pref ( blk , i , blk - > oplist [ i ] . rs1 . _reg , false ) ;
}
}
//Read Groups
void rdgrp ( RuntimeBlockInfo * blk )
{
int started = - 1 ;
Sh4RegType reg ;
Sh4RegType regd ;
u32 stride ;
bool pend_add ;
u32 rdc ;
u32 addv ;
for ( size_t i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
shil_opcode * op = & blk - > oplist [ i ] ;
op - > Flow = 0 ;
if ( started < 0 )
{
if ( op - > op = = shop_readm & & op - > rd . type > = FMT_F32 & & op - > rs1 . is_reg ( ) & & op - > rs3 . is_null ( ) )
{
started = i ;
stride = op - > rd . count ( ) ;
reg = op - > rs1 . _reg ;
regd = op - > rd . _reg ;
pend_add = true ;
rdc = 1 ;
addv = 0 ;
}
}
else
{
if ( ! pend_add & & op - > op = = shop_readm & & op - > rd . _reg = = ( regd + stride ) & & op - > rs1 . is_reg ( ) & & op - > rs1 . _reg = = reg & & op - > rs3 . is_null ( ) )
{
regd = ( Sh4RegType ) ( regd + stride ) ;
pend_add = true ;
rdc + + ;
}
else if ( pend_add & & op - > op = = shop_add & & op - > rd . _reg = = op - > rs1 . _reg & & op - > rs1 . is_reg ( ) & & op - > rs2 . is_imm ( ) & & op - > rs2 . _imm = = ( stride * 4 ) )
{
pend_add = false ;
addv + = op - > rs2 . _imm ;
}
else
{
u32 byts = rdc * stride * 4 ;
if ( rdc ! = 1 & & ( byts = = 8 | | byts = = 12 | | byts = = 16 | | byts = = 32 | | byts = = 64 ) )
{
verify ( addv = = byts | | ( pend_add & & ( addv + stride * 4 = = byts ) ) ) ;
blk - > oplist [ started ] . rd . type = byts = = 8 ? FMT_V2 : byts = = 12 ? FMT_V3 :
byts = = 16 ? FMT_V4 : byts = = 32 ? FMT_V8 : FMT_V16 ;
blk - > oplist [ started ] . flags = byts | 0x80 ;
if ( stride = = 8 )
blk - > oplist [ started ] . flags | = 0x100 ;
blk - > oplist [ started ] . Flow = ( rdc - 1 ) * 2 - ( pend_add ? 1 : 0 ) ;
blk - > oplist [ started + 1 ] . rs2 . _imm = addv ;
printf ( " Read Combination %d %d! \n " , rdc , addv ) ;
}
else if ( rdc ! = 1 )
{
printf ( " Read Combination failed %d %d %d \n " , rdc , rdc * stride * 4 , addv ) ;
}
started = - 1 ;
}
}
}
for ( size_t i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
shil_opcode * op = & blk - > oplist [ i ] ;
if ( op - > Flow )
{
blk - > oplist . erase ( blk - > oplist . begin ( ) + i + 2 , blk - > oplist . begin ( ) + i + 2 + op - > Flow ) ;
}
}
}
//Write Groups
void wtgrp ( RuntimeBlockInfo * blk )
{
int started = - 1 ;
Sh4RegType reg ;
Sh4RegType regd ;
u32 stride ;
bool pend_add ;
u32 rdc ;
u32 addv ;
for ( size_t i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
shil_opcode * op = & blk - > oplist [ i ] ;
op - > Flow = 0 ;
if ( started < 0 )
{
if ( op - > op = = shop_writem & & op - > rs2 . type > = FMT_F32 & & op - > rs1 . is_reg ( ) & & op - > rs3 . is_null ( ) )
{
started = i ;
stride = op - > rd . count ( ) ;
reg = op - > rs1 . _reg ;
regd = op - > rs2 . _reg ;
pend_add = true ;
rdc = 1 ;
addv = 0 ;
}
}
else
{
if ( ! pend_add & & op - > op = = shop_writem & & op - > rs2 . _reg = = ( regd - stride ) & & op - > rs1 . is_reg ( ) & & op - > rs1 . _reg = = reg & & op - > rs3 . is_null ( ) )
{
regd = ( Sh4RegType ) ( regd - stride ) ;
pend_add = true ;
rdc + + ;
}
else if ( pend_add & & op - > op = = shop_sub & & op - > rd . _reg = = op - > rs1 . _reg & & op - > rs1 . is_reg ( ) & & op - > rs1 . _reg = = reg & & op - > rs2 . is_imm ( ) & & op - > rs2 . _imm = = ( stride * 4 ) )
{
pend_add = false ;
addv + = op - > rs2 . _imm ;
}
else
{
u32 byts = rdc * stride * 4 ;
u32 mask = byts / 4 ;
if ( mask = = 3 ) mask = 4 ;
mask - - ;
if ( rdc ! = 1 /*&& (!(regd&mask))*/ & & ( byts = = 8 | | byts = = 12 | | byts = = 16 | | byts = = 32 | | byts = = 64 ) )
{
verify ( addv = = byts | | ( pend_add & & ( addv + stride * 4 = = byts ) ) ) ;
blk - > oplist [ started ] . rs2 . type = byts = = 8 ? FMT_V2 : byts = = 12 ? FMT_V3 :
byts = = 16 ? FMT_V4 : byts = = 32 ? FMT_V8 : FMT_V16 ;
blk - > oplist [ started ] . rs2 . _reg = regd ;
blk - > oplist [ started ] . rs3 . _imm = - ( rdc - 1 ) * stride * 4 ;
blk - > oplist [ started ] . rs3 . type = FMT_IMM ;
blk - > oplist [ started ] . flags = byts | 0x80 ;
if ( stride = = 8 )
blk - > oplist [ started ] . flags | = 0x100 ;
blk - > oplist [ started ] . Flow = ( rdc - 1 ) * 2 - ( pend_add ? 1 : 0 ) ;
blk - > oplist [ started + 1 ] . rs2 . _imm = addv ;
printf ( " Write Combination %d %d! \n " , rdc , addv ) ;
}
else if ( rdc ! = 1 )
{
printf ( " Write Combination failed fr%d,%d, %d %d %d \n " , regd , mask , rdc , rdc * stride * 4 , addv ) ;
}
i = started ;
started = - 1 ;
}
}
}
for ( size_t i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
shil_opcode * op = & blk - > oplist [ i ] ;
if ( op - > Flow )
{
blk - > oplist . erase ( blk - > oplist . begin ( ) + i + 2 , blk - > oplist . begin ( ) + i + 2 + op - > Flow ) ;
}
}
}
bool ReadsPhy ( shil_opcode * op , u32 phy )
{
return true ;
}
bool WritesPhy ( shil_opcode * op , u32 phy )
{
return true ;
}
void rw_related ( RuntimeBlockInfo * blk )
{
u32 reg [ sh4_reg_count ] = { 0 } ;
u32 total = 0 ;
u32 memtotal = 0 ;
for ( size_t i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
shil_opcode * op = & blk - > oplist [ i ] ;
op - > Flow = 0 ;
if ( op - > op = = shop_ifb | | op - > op = = shop_sync_sr )
{
memset ( reg , 0 , sizeof ( reg ) ) ;
}
if ( ( op - > op = = shop_add | | op - > op = = shop_sub ) )
{
if ( reg [ op - > rd . _reg ] )
{
if ( op - > rs1 . is_r32i ( ) & & op - > rs1 . _reg = = op - > rd . _reg & & op - > rs2 . is_imm_s16 ( ) )
{
//nothing !
}
else
reg [ op - > rd . _reg ] = 0 ;
}
}
else
{
if ( op - > op = = shop_readm | | op - > op = = shop_writem )
if ( op - > rs1 . is_r32i ( ) )
memtotal + + ;
if ( op - > op = = shop_readm | | op - > op = = shop_writem )
{
if ( op - > rs1 . is_r32i ( ) )
{
if ( op - > rs3 . is_imm_s16 ( ) | | op - > rs3 . is_null ( ) )
{
reg [ op - > rs1 . _reg ] + + ;
if ( reg [ op - > rs1 . _reg ] > 1 )
total + + ;
}
//else
//reg[op->rs1._reg]=0;
}
}
if ( op - > rd . is_reg ( ) & & reg [ op - > rd . _reg ] )
reg [ op - > rd . _reg ] = 0 ;
if ( op - > rd2 . is_reg ( ) & & reg [ op - > rd2 . _reg ] )
reg [ op - > rd2 . _reg ] = 0 ;
}
}
if ( memtotal )
{
u32 lookups = memtotal - total ;
//printf("rw_related total: %d/%d -- %.2f:1\n",total,memtotal,memtotal/(float)lookups);
}
else
{
//printf("rw_related total: none\n");
}
blk - > memops = memtotal ;
blk - > linkedmemops = total ;
}
//constprop
void constprop ( RuntimeBlockInfo * blk )
{
u32 rv [ 16 ] ;
bool isi [ 16 ] = { 0 } ;
for ( size_t i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
shil_opcode * op = & blk - > oplist [ i ] ;
if ( op - > rs2 . is_r32i ( ) & & op - > rs2 . _reg < 16 & & isi [ op - > rs2 . _reg ] )
{
/*
not all opcodes can take rs2 as constant
*/
if ( op - > op ! = shop_readm & & op - > op ! = shop_writem
& & op - > op ! = shop_mul_u16 & & op - > op ! = shop_mul_s16 & & op - > op ! = shop_mul_i32
& & op - > op ! = shop_mul_u64 & & op - > op ! = shop_mul_s64
& & op - > op ! = shop_adc & & op - > op ! = shop_sbc )
{
op - > rs2 . type = FMT_IMM ;
op - > rs2 . _imm = rv [ op - > rs2 . _reg ] ;
if ( op - > op = = shop_shld | | op - > op = = shop_shad )
{
//convert em to mov/shl/shr
printf ( " sh*d -> s*l ! \n " ) ;
s32 v = op - > rs2 . _imm ;
if ( v > = 0 )
{
//x86e->Emit(sl32,reg.mapg(op->rd),v);
op - > op = shop_shl ;
op - > rs2 . _imm = 0x1f & v ;
}
2013-12-23 14:17:16 +00:00
else if ( 0 = = ( v & 0x1f ) )
2013-12-19 17:10:14 +00:00
{
if ( op - > op ! = shop_shad )
{
//r[n]=0;
//x86e->Emit(op_mov32,reg.mapg(op->rd),0);
op - > op = shop_mov32 ;
op - > rs1 . type = FMT_IMM ;
op - > rs1 . _imm = 0 ;
op - > rs2 . type = FMT_NULL ;
}
else
{
//r[n]>>=31;
//x86e->Emit(op_sar32,reg.mapg(op->rd),31);
op - > op = shop_sar ;
op - > rs2 . _imm = 31 ;
}
}
else
{
//x86e->Emit(sr32,reg.mapg(op->rd),-v);
if ( op - > op ! = shop_shad )
op - > op = shop_shr ;
else
op - > op = shop_sar ;
op - > rs2 . _imm = 0x1f & ( - v ) ;
}
}
}
}
if ( op - > rs1 . is_r32i ( ) & & op - > rs1 . _reg < 16 & & isi [ op - > rs1 . _reg ] )
{
if ( ( op - > op = = shop_readm /*|| op->op==shop_writem*/ ) & & ( op - > flags & 0x7F ) = = 4 )
{
op - > rs1 . type = FMT_IMM ;
op - > rs1 . _imm = rv [ op - > rs1 . _reg ] ;
if ( op - > rs3 . is_imm ( ) )
{
op - > rs1 . _imm + = op - > rs3 . _imm ;
op - > rs3 . type = FMT_NULL ;
}
printf ( " %s promotion: %08X \n " , shop_readm = = op - > op ? " shop_readm " : " shop_writem " , op - > rs1 . _imm ) ;
}
else if ( op - > op = = shop_jdyn )
{
if ( blk - > BlockType = = BET_DynamicJump | | blk - > BlockType = = BET_DynamicCall )
{
blk - > BranchBlock = rv [ op - > rs1 . _reg ] ;
if ( op - > rs2 . is_imm ( ) )
blk - > BranchBlock + = op - > rs2 . _imm ; ;
blk - > BlockType = blk - > BlockType = = BET_DynamicJump ? BET_StaticJump : BET_StaticCall ;
blk - > oplist . erase ( blk - > oplist . begin ( ) + i ) ;
i - - ;
printf ( " SBP: %08X -> %08X! \n " , blk - > addr , blk - > BranchBlock ) ;
continue ;
}
else
{
printf ( " SBP: failed :( \n " ) ;
}
}
else if ( op - > op = = shop_mov32 )
{
//handled later on !
}
else if ( op - > op = = shop_add | | op - > op = = shop_sub )
{
if ( op - > rs2 . is_imm ( ) )
{
op - > rs1 . type = 1 ;
op - > rs1 . _imm = op - > op = = shop_add ?
( rv [ op - > rs1 . _reg ] + op - > rs2 . _imm ) :
( rv [ op - > rs1 . _reg ] - op - > rs2 . _imm ) ;
op - > rs2 . type = 0 ;
printf ( " %s -> mov32! \n " , op - > op = = shop_add ? " shop_add " : " shop_sub " ) ;
op - > op = shop_mov32 ;
}
else if ( op - > op = = shop_add & & ! op - > rs2 . is_imm ( ) )
{
u32 immy = rv [ op - > rs1 . _reg ] ;
op - > rs1 = op - > rs2 ;
op - > rs2 . type = 1 ;
op - > rs2 . _imm = immy ;
printf ( " %s -> imm prm (%08X)! \n " , op - > op = = shop_add ? " shop_add " : " shop_sub " , immy ) ;
}
}
else
{
op - > op = op - > op ;
}
}
if ( op - > rd . is_r32i ( ) & & op - > rd . _reg < 16 ) isi [ op - > rd . _reg ] = false ;
if ( op - > rd2 . is_r32i ( ) & & op - > rd2 . _reg < 16 ) isi [ op - > rd . _reg ] = false ;
if ( op - > op = = shop_mov32 & & op - > rs1 . is_imm ( ) & & op - > rd . is_r32i ( ) & & op - > rd . _reg < 16 )
{
isi [ op - > rd . _reg ] = true ;
rv [ op - > rd . _reg ] = op - > rs1 . _imm ;
}
//NOT WORKING
//WE NEED PROPER PAGELOCKS
if ( op - > op = = shop_readm & & op - > rs1 . is_imm ( ) & & op - > rd . is_r32i ( ) & & op - > rd . _reg < 16 & & op - > flags = = 0x4 & & op - > rs3 . is_null ( ) )
{
u32 baddr = blk - > addr & 0x0FFFFFFF ;
if ( /*baddr==0xC158400 &&*/ blk - > addr / PAGE_SIZE = = op - > rs1 . _imm / PAGE_SIZE )
{
isi [ op - > rd . _reg ] = true ;
rv [ op - > rd . _reg ] = ReadMem32 ( op - > rs1 . _imm ) ;
printf ( " IMM MOVE: %08X -> %08X \n " , op - > rs1 . _imm , rv [ op - > rd . _reg ] ) ;
op - > op = shop_mov32 ;
op - > rs1 . _imm = rv [ op - > rd . _reg ] ;
}
}
}
rw_related ( blk ) ;
}
//read_v4m3z1
void read_v4m3z1 ( RuntimeBlockInfo * blk )
{
int state = 0 ;
int st_sta = 0 ;
Sh4RegType reg_a ;
Sh4RegType reg_fb ;
for ( size_t i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
shil_opcode * op = & blk - > oplist [ i ] ;
bool a = false , b = false ;
if ( ( i + 6 ) > blk - > oplist . size ( ) )
break ;
if ( state = = 0 & & op - > op = = shop_readm & & op - > rd . is_r32f ( ) & & op - > rs1 . is_r32i ( ) & & op - > rs3 . is_null ( ) )
{
if ( op - > rd . _reg = = reg_fr_0 | | op - > rd . _reg = = reg_fr_4 | | op - > rd . _reg = = reg_fr_8 | | op - > rd . _reg = = reg_fr_12 )
{
reg_a = op - > rs1 . _reg ;
reg_fb = op - > rd . _reg ;
st_sta = i ;
goto _next_st ;
}
goto _fail ;
}
else if ( state < 8 & & state & 1 & & op - > op = = shop_add & & op - > rd . _reg = = reg_a & & op - > rs1 . is_reg ( ) & & op - > rs1 . _reg = = reg_a & & op - > rs2 . is_imm ( ) & & op - > rs2 . _imm = = 4 )
{
if ( state = = 7 )
{
u32 start = st_sta ;
for ( int j = 0 ; j < 6 ; j + + )
{
blk - > oplist . erase ( blk - > oplist . begin ( ) + start ) ;
}
i = start + 1 ;
op = & blk - > oplist [ start + 0 ] ;
op - > op = shop_readm ;
op - > flags = 0x440 ;
op - > rd = shil_param ( reg_fb = = reg_fr_0 ? regv_fv_0 :
reg_fb = = reg_fr_4 ? regv_fv_4 :
reg_fb = = reg_fr_8 ? regv_fv_8 :
reg_fb = = reg_fr_12 ? regv_fv_12 : reg_sr_T ) ;
op - > rd2 = shil_param ( ) ;
op - > rs1 = shil_param ( reg_a ) ;
op - > rs2 = shil_param ( ) ;
op - > rs3 = shil_param ( ) ;
op = & blk - > oplist [ start + 1 ] ;
op - > op = shop_add ;
op - > flags = 0 ;
op - > rd = shil_param ( reg_a ) ;
op - > rd2 = shil_param ( ) ;
op - > rs1 = shil_param ( reg_a ) ;
op - > rs2 = shil_param ( FMT_IMM , 16 ) ;
op - > rs3 = shil_param ( ) ;
goto _end ;
}
else
goto _next_st ;
}
else if ( state > 1 & &
op - > op = = shop_readm & & op - > rd . is_r32f ( ) & & op - > rd . _reg = = ( reg_fb + state / 2 ) & & op - > rs1 . is_r32i ( ) & & op - > rs1 . _reg = = reg_a & & op - > rs3 . is_null ( ) )
{
goto _next_st ;
}
else if ( ( a = ( op - > op = = shop_mov32 & & op - > rd . _reg = = ( reg_fb + 3 ) & & op - > rs1 . is_imm ( ) & & ( op - > rs1 . _imm = = 0x3f800000 /*|| op->rs1._imm==0*/ ) ) ) | |
( b = ( i > 7 & & op [ - 7 ] . op = = shop_mov32 & & op [ - 7 ] . rd . _reg = = ( reg_fb + 3 ) & & op [ - 7 ] . rs1 . is_imm ( ) & & ( op [ - 7 ] . rs1 . _imm = = 0x3f800000 /*|| op[-7].rs1._imm==0*/ ) ) ) )
{
if ( state = = 6 )
{
if ( b )
st_sta - - ;
if ( a )
printf ( " NOT B \b " ) ;
u32 start = st_sta ;
for ( int j = 0 ; j < 5 ; j + + )
{
blk - > oplist . erase ( blk - > oplist . begin ( ) + start ) ;
}
i = start + 1 ;
op = & blk - > oplist [ start + 0 ] ;
op - > op = shop_readm ;
op - > flags = 0x431 ;
op - > rd = shil_param ( reg_fb = = reg_fr_0 ? regv_fv_0 :
reg_fb = = reg_fr_4 ? regv_fv_4 :
reg_fb = = reg_fr_8 ? regv_fv_8 :
reg_fb = = reg_fr_12 ? regv_fv_12 : reg_sr_T ) ;
op - > rd2 = shil_param ( ) ;
op - > rs1 = shil_param ( reg_a ) ;
op - > rs2 = shil_param ( ) ;
op - > rs3 = shil_param ( ) ;
op = & blk - > oplist [ start + 1 ] ;
op - > op = shop_add ;
op - > flags = 0 ;
op - > rd = shil_param ( reg_a ) ;
op - > rd2 = shil_param ( ) ;
op - > rs1 = shil_param ( reg_a ) ;
op - > rs2 = shil_param ( FMT_IMM , 12 ) ;
op - > rs3 = shil_param ( ) ;
goto _end ;
}
else
goto _fail ;
}
else
goto _fail ;
die ( " wth " ) ;
_next_st :
state + + ;
continue ;
_fail :
if ( state )
i = st_sta ;
_end :
state = 0 ;
}
}
//dejcond
void dejcond ( RuntimeBlockInfo * blk )
{
u32 rv [ 16 ] ;
bool isi [ 16 ] = { 0 } ;
if ( ! blk - > has_jcond ) return ;
bool found = false ;
u32 jcondp = 0 ;
for ( size_t i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
shil_opcode * op = & blk - > oplist [ i ] ;
if ( found )
{
if ( op - > rd . is_reg ( ) & & op - > rd . _reg = = reg_sr_T | | op - > op = = shop_ifb )
{
found = false ;
}
}
if ( op - > op = = shop_jcond )
{
found = true ;
jcondp = i ;
}
}
if ( found )
{
blk - > has_jcond = false ;
blk - > oplist . erase ( blk - > oplist . begin ( ) + jcondp ) ;
}
}
//detect bswaps and talk about them
void enswap ( RuntimeBlockInfo * blk )
{
Sh4RegType r ;
int state = 0 ;
for ( size_t i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
shil_opcode * op = & blk - > oplist [ i ] ;
op - > Flow = 0 ;
if ( state = = 0 & & op - > op = = shop_swaplb )
{
if ( op - > rd . _reg = = op - > rs1 . _reg )
{
state = 1 ;
r = op - > rd . _reg ;
op - > Flow = 1 ;
continue ;
}
else
{
printf ( " bswap -- wrong regs \n " ) ;
}
}
if ( state = = 1 & & op - > op = = shop_ror & & op - > rs2 . is_imm ( ) & & op - > rs2 . _imm = = 16 & &
op - > rs1 . _reg = = r )
{
if ( op - > rd . _reg = = r )
{
state = 2 ;
op - > Flow = 1 ;
continue ;
}
else
{
printf ( " bswap -- wrong regs \n " ) ;
}
}
if ( state = = 2 & & op - > op = = shop_swaplb & & op - > rs1 . _reg = = r )
{
if ( op - > rd . _reg ! = r )
{
printf ( " oops? \n " ) ;
}
else
{
printf ( " SWAPM! \n " ) ;
}
op - > Flow = 1 ;
state = 0 ;
}
}
}
//enjcond
//this is a normally slower
//however, cause of reg alloc stuff in arm, this
//speeds up access to SR_T (pc_dyn is stored in reg, not mem)
//This is temporary til that limitation is fixed on the reg alloc logic
void enjcond ( RuntimeBlockInfo * blk )
{
u32 rv [ 16 ] ;
bool isi [ 16 ] = { 0 } ;
if ( ! blk - > has_jcond & & ( blk - > BlockType = = BET_Cond_0 | | blk - > BlockType = = BET_Cond_1 ) )
{
shil_opcode jcnd ;
jcnd . op = shop_jcond ;
jcnd . rs1 = shil_param ( reg_sr_T ) ;
jcnd . rd = shil_param ( reg_pc_dyn ) ;
jcnd . flags = 0 ;
blk - > oplist . push_back ( jcnd ) ;
blk - > has_jcond = true ;
}
}
//"links" consts to each other
void constlink ( RuntimeBlockInfo * blk )
{
Sh4RegType def = NoReg ;
s32 val ;
for ( size_t i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
shil_opcode * op = & blk - > oplist [ i ] ;
if ( op - > op ! = shop_mov32 )
def = NoReg ;
else
{
if ( def ! = NoReg & & op - > rs1 . is_imm ( ) & & op - > rs1 . _imm = = val )
{
op - > rs1 = shil_param ( def ) ;
}
else if ( def = = NoReg & & op - > rs1 . is_imm ( ) & & op - > rs1 . _imm = = 0 )
{
//def=op->rd._reg;
val = op - > rs1 . _imm ;
}
}
}
}
void srt_waw ( RuntimeBlockInfo * blk )
{
bool found = false ;
u32 srtw = 0 ;
for ( size_t i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
shil_opcode * op = & blk - > oplist [ i ] ;
if ( found )
{
if ( op - > rs1 . is_reg ( ) & & op - > rs1 . _reg = = reg_sr_T
| | op - > rs2 . is_reg ( ) & & op - > rs2 . _reg = = reg_sr_T
| | op - > rs3 . is_reg ( ) & & op - > rs3 . _reg = = reg_sr_T
| | op - > op = = shop_ifb )
{
found = false ;
}
}
if ( op - > rd . is_reg ( ) & & op - > rd . _reg = = reg_sr_T & & op - > rd2 . is_null ( ) )
{
if ( found )
{
blk - > oplist . erase ( blk - > oplist . begin ( ) + srtw ) ;
i - - ;
}
found = true ;
srtw = i ;
}
}
}
//Simplistic Write after Write without read pass to remove (a few) dead opcodes
//Seems to be working
void AnalyseBlock ( RuntimeBlockInfo * blk )
{
u32 st [ sh4_reg_count ] = { 0 } ;
/*
for ( size_t i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
shil_opcode * op = & blk - > oplist [ i ] ;
if ( op - > rs1 . is_reg ( ) & & st [ op - > rs1 . _reg ] = = 0 )
st [ op - > rs1 . _reg ] = 1 ;
if ( op - > rs2 . is_reg ( ) & & st [ op - > rs2 . _reg ] = = 0 )
st [ op - > rs2 . _reg ] = 1 ;
if ( op - > rs3 . is_reg ( ) & & st [ op - > rs3 . _reg ] = = 0 )
st [ op - > rs3 . _reg ] = 1 ;
if ( op - > rd . is_reg ( ) )
st [ op - > rd . _reg ] | = 2 ;
if ( op - > rd2 . is_reg ( ) )
st [ op - > rd2 . _reg ] | = 2 ;
}
if ( st [ reg_sr_T ] & 1 )
{
printf ( " BLOCK: %08X \n " , blk - > addr ) ;
puts ( " rin: " ) ;
for ( int i = 0 ; i < sh4_reg_count ; i + + )
{
if ( st [ i ] & 1 )
printf ( " %s " , name_reg ( i ) . c_str ( ) ) ;
}
puts ( " \n rout: " ) ;
for ( int i = 0 ; i < sh4_reg_count ; i + + )
{
if ( st [ i ] & 2 )
printf ( " %s " , name_reg ( i ) . c_str ( ) ) ;
}
puts ( " \n r-ns: " ) ;
for ( int i = 0 ; i < sh4_reg_count ; i + + )
{
if ( st [ i ] = = 2 )
printf ( " %s " , name_reg ( i ) . c_str ( ) ) ;
}
puts ( " \n " ) ;
}
*/
if ( settings . dynarec . unstable_opt )
sq_pref ( blk ) ;
//constprop(blk); // crashes on ip
# if HOST_CPU==CPU_X86
// rdgrp(blk);
// wtgrp(blk);
//constprop(blk);
# endif
bool last_op_sets_flags = ! blk - > has_jcond & & blk - > oplist . size ( ) > 0 & &
blk - > oplist [ blk - > oplist . size ( ) - 1 ] . rd . _reg = = reg_sr_T ;
srt_waw ( blk ) ;
constlink ( blk ) ;
2013-12-29 23:52:14 +00:00
//dejcond(blk);
2013-12-19 17:10:14 +00:00
if ( last_op_sets_flags )
{
shilop op = blk - > oplist [ blk - > oplist . size ( ) - 1 ] . op ;
if ( op = = shop_test | | op = = shop_seteq | | op = = shop_setab | | op = = shop_setae
| | op = = shop_setge | | op = = shop_setgt )
;
else
last_op_sets_flags = false ;
}
if ( ! last_op_sets_flags )
enjcond ( blk ) ;
//read_v4m3z1(blk);
//rw_related(blk);
return ; //disbled to be on the safe side ..
memset ( RegisterWrite , - 1 , sizeof ( RegisterWrite ) ) ;
memset ( RegisterRead , - 1 , sizeof ( RegisterRead ) ) ;
total_blocks + + ;
for ( size_t i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
shil_opcode * op = & blk - > oplist [ i ] ;
op - > Flow = 0 ;
if ( op - > op = = shop_ifb )
{
fallback_blocks + + ;
return ;
}
RegReadInfo ( op - > rs1 , i ) ;
RegReadInfo ( op - > rs2 , i ) ;
RegReadInfo ( op - > rs3 , i ) ;
RegWriteInfo ( & blk - > oplist [ 0 ] , op - > rd , i ) ;
RegWriteInfo ( & blk - > oplist [ 0 ] , op - > rd2 , i ) ;
}
for ( size_t i = 0 ; i < blk - > oplist . size ( ) ; i + + )
{
if ( blk - > oplist [ i ] . Flow )
{
blk - > oplist . erase ( blk - > oplist . begin ( ) + i ) ;
REMOVED_OPS + + ;
i - - ;
}
}
int affregs = 0 ;
for ( int i = 0 ; i < 16 ; i + + )
{
if ( RegisterWrite [ i ] ! = 0 )
{
affregs + + ;
//printf("r%02d:%02d ",i,RegisterWrite[i]);
}
}
//printf("<> %d\n",affregs);
//printf("%d FB, %d native, %.2f%% || %d removed ops!\n",fallback_blocks,total_blocks-fallback_blocks,fallback_blocks*100.f/total_blocks,REMOVED_OPS);
//printf("\nBlock: %d affecter regs %d c\n",affregs,blk->guest_cycles);
}
void UpdateFPSCR ( ) ;
bool UpdateSR ( ) ;
# include "hw/sh4/modules/ccn.h"
# include "ngen.h"
# include "hw/sh4/sh4_core.h"
# include "hw/sh4/sh4_mmr.h"
# define SHIL_MODE 1
# include "shil_canonical.h"
# define SHIL_MODE 4
# include "shil_canonical.h"
//#define SHIL_MODE 2
//#include "shil_canonical.h"
# ifndef HOST_NO_REC
# define SHIL_MODE 3
# include "shil_canonical.h"
# endif
# include <sstream>
string name_reg ( u32 reg )
{
stringstream ss ;
if ( reg > = reg_fr_0 & & reg < = reg_xf_15 )
ss < < " f " < < ( reg - 16 ) ;
else if ( reg < = reg_r15 )
ss < < " r " < < reg ;
else if ( reg = = reg_sr_T )
ss < < " sr.T " ;
else if ( reg = = reg_fpscr )
ss < < " fpscr " ;
else if ( reg = = reg_sr_status )
ss < < " sr " ;
else
ss < < " s " < < reg ;
return ss . str ( ) ;
}
string dissasm_param ( const shil_param & prm , bool comma )
{
stringstream ss ;
if ( ! prm . is_null ( ) & & comma )
ss < < " , " ;
if ( prm . is_imm ( ) )
{
if ( prm . is_imm_s8 ( ) )
ss < < ( s32 ) prm . _imm ;
else
ss < < " 0x " < < hex < < prm . _imm ;
}
else if ( prm . is_reg ( ) )
{
if ( ! prm . is_r32i ( ) )
ss < < " f " < < ( prm . _reg - 16 ) ;
else if ( prm . _reg < = reg_r15 )
ss < < " r " < < prm . _reg ;
else if ( prm . _reg = = reg_sr_T )
ss < < " sr.T " ;
else if ( prm . _reg = = reg_fpscr )
ss < < " fpscr " ;
else if ( prm . _reg = = reg_sr_status )
ss < < " sr " ;
else
ss < < " s " < < prm . _reg ;
if ( prm . count ( ) > 1 )
{
ss < < " v " < < prm . count ( ) ;
}
}
return ss . str ( ) ;
}
string shil_opcode : : dissasm ( )
{
stringstream ss ;
ss < < shilop_str [ op ] < < " " < < dissasm_param ( rd , false ) < < dissasm_param ( rd2 , true ) < < " <= " < < dissasm_param ( rs1 , false ) < < dissasm_param ( rs2 , true ) < < dissasm_param ( rs3 , true ) ;
return ss . str ( ) ;
}
const char * shil_opcode_name ( int op )
{
return shilop_str [ op ] ;
}