// put rt_val into rt, potentially making use of rs with value rs_val
static void emit_movimm_from(u_int rs_val,int rs,u_int rt_val,int rt)
{
- u_int xor=rs_val^rt_val;
+ u_int armval;
+ int diff;
+ if(genimm(rt_val,&armval)) {
+ assem_debug("mov %s,#%d\n",regname[rt],rt_val);
+ output_w32(0xe3a00000|rd_rn_rm(rt,0,0)|armval);
+ return;
+ }
+ if(genimm(~rt_val,&armval)) {
+ assem_debug("mvn %s,#%d\n",regname[rt],rt_val);
+ output_w32(0xe3e00000|rd_rn_rm(rt,0,0)|armval);
+ return;
+ }
+ diff=rt_val-rs_val;
+ if(genimm(diff,&armval)) {
+ assem_debug("add %s,%s,#%d\n",regname[rt],regname[rs],diff);
+ output_w32(0xe2800000|rd_rn_rm(rt,rs,0)|armval);
+ return;
+ }else if(genimm(-diff,&armval)) {
+ assem_debug("sub %s,%s,#%d\n",regname[rt],regname[rs],-diff);
+ output_w32(0xe2400000|rd_rn_rm(rt,rs,0)|armval);
+ return;
+ }
+ emit_movimm(rt_val,rt);
+}
+
+// return 1 if above function can do it's job cheaply
+static int is_similar_value(u_int v1,u_int v2)
+{
u_int xs;
- for(xs=xor;xs!=0&&(xs&3)==0;xs>>=2)
+ int diff;
+ if(v1==v2) return 1;
+ diff=v2-v1;
+ for(xs=diff;xs!=0&&(xs&3)==0;xs>>=2)
;
- if(xs<0x100)
- emit_xorimm(rs,xor,rt);
- else
- emit_movimm(rt_val,rt);
+ if(xs<0x100) return 1;
+ for(xs=-diff;xs!=0&&(xs&3)==0;xs>>=2)
+ ;
+ if(xs<0x100) return 1;
+ return 0;
}
// trashes r2
uint64_t uu;
u_int wasconst;
u_int isconst;
- u_int waswritten; // regs that were used as store base before
+ u_int loadedconst; // host regs that have constants loaded
+ u_int waswritten; // MIPS regs that were used as store base before
uint64_t constmap[HOST_REGS];
};
(using_tlb&&((signed int)constmap[i][rs]+offset)>=(signed int)0xC0000000))
#endif
emit_movimm(constmap[i][rs]+offset,ra);
+ regs[i].loadedconst|=1<<ra;
}
} // else did it in the previous cycle
} // else load_consts already did it
(using_tlb&&((signed int)constmap[i+1][rs]+offset)>=(signed int)0xC0000000))
#endif
emit_movimm(constmap[i+1][rs]+offset,ra);
+ regs[i+1].loadedconst|=1<<ra;
}
}
else if(rs1[i+1]==0) {
// Load registers with known constants
void load_consts(signed char pre[],signed char regmap[],int is32,int i)
{
- int hr;
+ int hr,hr2;
+ // propagate loaded constant flags
+ if(i==0||bt[i])
+ regs[i].loadedconst=0;
+ else {
+ for(hr=0;hr<HOST_REGS;hr++) {
+ if(hr!=EXCLUDE_REG&®map[hr]>=0&&((regs[i-1].isconst>>hr)&1)&&pre[hr]==regmap[hr]
+ &®map[hr]==regs[i-1].regmap[hr]&&((regs[i-1].loadedconst>>hr)&1))
+ {
+ regs[i].loadedconst|=1<<hr;
+ }
+ }
+ }
// Load 32-bit regs
for(hr=0;hr<HOST_REGS;hr++) {
if(hr!=EXCLUDE_REG&®map[hr]>=0) {
//if(entry[hr]!=regmap[hr]) {
- if(i==0||!((regs[i-1].isconst>>hr)&1)||pre[hr]!=regmap[hr]||bt[i]) {
+ if(!((regs[i].loadedconst>>hr)&1)) {
if(((regs[i].isconst>>hr)&1)&®map[hr]<64&®map[hr]>0) {
- int value;
+ int value,similar=0;
if(get_final_value(hr,i,&value)) {
- if(value==0) {
+ // see if some other register has similar value
+ for(hr2=0;hr2<HOST_REGS;hr2++) {
+ if(hr2!=EXCLUDE_REG&&((regs[i].loadedconst>>hr2)&1)) {
+ if(is_similar_value(value,constmap[i][hr2])) {
+ similar=1;
+ break;
+ }
+ }
+ }
+ if(similar) {
+ int value2;
+ if(get_final_value(hr2,i,&value2)) // is this needed?
+ emit_movimm_from(value2,hr2,value,hr);
+ else
+ emit_movimm(value,hr);
+ }
+ else if(value==0) {
emit_zeroreg(hr);
}
else {
emit_movimm(value,hr);
}
}
+ regs[i].loadedconst|=1<<hr;
}
}
}
regs[i].wasconst=current.isconst;
regs[i].was32=current.is32;
regs[i].wasdirty=current.dirty;
+ regs[i].loadedconst=0;
#if defined(DESTRUCTIVE_WRITEBACK) && !defined(FORCE32)
// To change a dirty register from 32 to 64 bits, we must write
// it out during the previous cycle (for branches, 2 cycles)