flycast/core/hw/sh4/dyna/shil.cpp

1093 lines
22 KiB
C++
Raw Normal View History

2013-12-19 17:10:14 +00:00
/*
Some WIP optimisation stuff and maby helper functions for shil
*/
2014-12-17 11:10:18 +00:00
#include <sstream>
2013-12-19 17:10:14 +00:00
#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())
{
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())
{
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);
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;
}
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)
{
core/hw/sh4/dyna/shil.cpp: Fix '&&' within '||' warning Here's the original compiler warning: ../../core/hw/sh4/dyna/shil.cpp:700:24: warning: '&&' within '||' [-Wlogical-op-parentheses] ...if (op->rd.is_reg() && op->rd._reg==reg_sr_T || op->op==shop_ifb) ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~ ~~ ../../core/hw/sh4/dyna/shil.cpp:700:24: note: place parentheses around the '&&' expression to silence this warning ...if (op->rd.is_reg() && op->rd._reg==reg_sr_T || op->op==shop_ifb) ^ ( ) ../../core/hw/sh4/dyna/shil.cpp:843:25: warning: '&&' within '||' [-Wlogical-op-parentheses] if (op->rs1.is_reg() && op->rs1._reg==reg_sr_T ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~ ../../core/hw/sh4/dyna/shil.cpp:843:25: note: place parentheses around the '&&' expression to silence this warning if (op->rs1.is_reg() && op->rs1._reg==reg_sr_T ^ ( ) ../../core/hw/sh4/dyna/shil.cpp:844:25: warning: '&&' within '||' [-Wlogical-op-parentheses] || op->rs2.is_reg() && op->rs2._reg==reg_sr_T ~~ ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~ ../../core/hw/sh4/dyna/shil.cpp:844:25: note: place parentheses around the '&&' expression to silence this warning || op->rs2.is_reg() && op->rs2._reg==reg_sr_T ^ ( ) ../../core/hw/sh4/dyna/shil.cpp:845:25: warning: '&&' within '||' [-Wlogical-op-parentheses] || op->rs3.is_reg() && op->rs3._reg==reg_sr_T ~~ ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~ ../../core/hw/sh4/dyna/shil.cpp:845:25: note: place parentheses around the '&&' expression to silence this warning || op->rs3.is_reg() && op->rs3._reg==reg_sr_T ^ ( )
2015-08-03 14:58:15 +00:00
if ((op->rd.is_reg() && op->rd._reg==reg_sr_T) || op->op==shop_ifb)
2013-12-19 17:10:14 +00:00
{
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)
{
core/hw/sh4/dyna/shil.cpp: Fix '&&' within '||' warning Here's the original compiler warning: ../../core/hw/sh4/dyna/shil.cpp:700:24: warning: '&&' within '||' [-Wlogical-op-parentheses] ...if (op->rd.is_reg() && op->rd._reg==reg_sr_T || op->op==shop_ifb) ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~ ~~ ../../core/hw/sh4/dyna/shil.cpp:700:24: note: place parentheses around the '&&' expression to silence this warning ...if (op->rd.is_reg() && op->rd._reg==reg_sr_T || op->op==shop_ifb) ^ ( ) ../../core/hw/sh4/dyna/shil.cpp:843:25: warning: '&&' within '||' [-Wlogical-op-parentheses] if (op->rs1.is_reg() && op->rs1._reg==reg_sr_T ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~ ../../core/hw/sh4/dyna/shil.cpp:843:25: note: place parentheses around the '&&' expression to silence this warning if (op->rs1.is_reg() && op->rs1._reg==reg_sr_T ^ ( ) ../../core/hw/sh4/dyna/shil.cpp:844:25: warning: '&&' within '||' [-Wlogical-op-parentheses] || op->rs2.is_reg() && op->rs2._reg==reg_sr_T ~~ ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~ ../../core/hw/sh4/dyna/shil.cpp:844:25: note: place parentheses around the '&&' expression to silence this warning || op->rs2.is_reg() && op->rs2._reg==reg_sr_T ^ ( ) ../../core/hw/sh4/dyna/shil.cpp:845:25: warning: '&&' within '||' [-Wlogical-op-parentheses] || op->rs3.is_reg() && op->rs3._reg==reg_sr_T ~~ ~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~ ../../core/hw/sh4/dyna/shil.cpp:845:25: note: place parentheses around the '&&' expression to silence this warning || op->rs3.is_reg() && op->rs3._reg==reg_sr_T ^ ( )
2015-08-03 14:58:15 +00:00
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)
2013-12-19 17:10:14 +00:00
|| 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("\nrout: ");
for (int i=0;i<sh4_reg_count;i++)
{
if (st[i]&2)
printf("%s ",name_reg(i).c_str());
}
puts("\nr-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);
//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"
2015-07-25 06:39:35 +00:00
#if FEAT_SHREC != DYNAREC_NONE
2013-12-19 17:10:14 +00:00
#define SHIL_MODE 3
#include "shil_canonical.h"
#endif
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];
}