+/* Register allocation */
+
+// Note: registers are allocated clean (unmodified state)
+// if you intend to modify the register, you must call dirty_reg().
+static void alloc_reg(struct regstat *cur,int i,signed char reg)
+{
+ int r,hr;
+ int preferred_reg = (reg&7);
+ if(reg==CCREG) preferred_reg=HOST_CCREG;
+ if(reg==PTEMP||reg==FTEMP) preferred_reg=12;
+
+ // Don't allocate unused registers
+ if((cur->u>>reg)&1) return;
+
+ // see if it's already allocated
+ for(hr=0;hr<HOST_REGS;hr++)
+ {
+ if(cur->regmap[hr]==reg) return;
+ }
+
+ // Keep the same mapping if the register was already allocated in a loop
+ preferred_reg = loop_reg(i,reg,preferred_reg);
+
+ // Try to allocate the preferred register
+ if(cur->regmap[preferred_reg]==-1) {
+ cur->regmap[preferred_reg]=reg;
+ cur->dirty&=~(1<<preferred_reg);
+ cur->isconst&=~(1<<preferred_reg);
+ return;
+ }
+ r=cur->regmap[preferred_reg];
+ assert(r < 64);
+ if((cur->u>>r)&1) {
+ cur->regmap[preferred_reg]=reg;
+ cur->dirty&=~(1<<preferred_reg);
+ cur->isconst&=~(1<<preferred_reg);
+ return;
+ }
+
+ // Clear any unneeded registers
+ // We try to keep the mapping consistent, if possible, because it
+ // makes branches easier (especially loops). So we try to allocate
+ // first (see above) before removing old mappings. If this is not
+ // possible then go ahead and clear out the registers that are no
+ // longer needed.
+ for(hr=0;hr<HOST_REGS;hr++)
+ {
+ r=cur->regmap[hr];
+ if(r>=0) {
+ assert(r < 64);
+ if((cur->u>>r)&1) {cur->regmap[hr]=-1;break;}
+ }
+ }
+ // Try to allocate any available register, but prefer
+ // registers that have not been used recently.
+ if(i>0) {
+ for(hr=0;hr<HOST_REGS;hr++) {
+ if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
+ if(regs[i-1].regmap[hr]!=rs1[i-1]&®s[i-1].regmap[hr]!=rs2[i-1]&®s[i-1].regmap[hr]!=rt1[i-1]&®s[i-1].regmap[hr]!=rt2[i-1]) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<<hr);
+ cur->isconst&=~(1<<hr);
+ return;
+ }
+ }
+ }
+ }
+ // Try to allocate any available register
+ for(hr=0;hr<HOST_REGS;hr++) {
+ if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<<hr);
+ cur->isconst&=~(1<<hr);
+ return;
+ }
+ }
+
+ // Ok, now we have to evict someone
+ // Pick a register we hopefully won't need soon
+ u_char hsn[MAXREG+1];
+ memset(hsn,10,sizeof(hsn));
+ int j;
+ lsn(hsn,i,&preferred_reg);
+ //printf("eax=%d ecx=%d edx=%d ebx=%d ebp=%d esi=%d edi=%d\n",cur->regmap[0],cur->regmap[1],cur->regmap[2],cur->regmap[3],cur->regmap[5],cur->regmap[6],cur->regmap[7]);
+ //printf("hsn(%x): %d %d %d %d %d %d %d\n",start+i*4,hsn[cur->regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]);
+ if(i>0) {
+ // Don't evict the cycle count at entry points, otherwise the entry
+ // stub will have to write it.
+ if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2;
+ if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP)) hsn[CCREG]=2;
+ for(j=10;j>=3;j--)
+ {
+ // Alloc preferred register if available
+ if(hsn[r=cur->regmap[preferred_reg]&63]==j) {
+ for(hr=0;hr<HOST_REGS;hr++) {
+ // Evict both parts of a 64-bit register
+ if((cur->regmap[hr]&63)==r) {
+ cur->regmap[hr]=-1;
+ cur->dirty&=~(1<<hr);
+ cur->isconst&=~(1<<hr);
+ }
+ }
+ cur->regmap[preferred_reg]=reg;
+ return;
+ }
+ for(r=1;r<=MAXREG;r++)
+ {
+ if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) {
+ for(hr=0;hr<HOST_REGS;hr++) {
+ if(hr!=HOST_CCREG||j<hsn[CCREG]) {
+ if(cur->regmap[hr]==r) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<<hr);
+ cur->isconst&=~(1<<hr);
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ for(j=10;j>=0;j--)
+ {
+ for(r=1;r<=MAXREG;r++)
+ {
+ if(hsn[r]==j) {
+ for(hr=0;hr<HOST_REGS;hr++) {
+ if(cur->regmap[hr]==r) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<<hr);
+ cur->isconst&=~(1<<hr);
+ return;
+ }
+ }
+ }
+ }
+ }
+ SysPrintf("This shouldn't happen (alloc_reg)");abort();
+}
+
+// Allocate a temporary register. This is done without regard to
+// dirty status or whether the register we request is on the unneeded list
+// Note: This will only allocate one register, even if called multiple times
+static void alloc_reg_temp(struct regstat *cur,int i,signed char reg)
+{
+ int r,hr;
+ int preferred_reg = -1;
+
+ // see if it's already allocated
+ for(hr=0;hr<HOST_REGS;hr++)
+ {
+ if(hr!=EXCLUDE_REG&&cur->regmap[hr]==reg) return;
+ }
+
+ // Try to allocate any available register
+ for(hr=HOST_REGS-1;hr>=0;hr--) {
+ if(hr!=EXCLUDE_REG&&cur->regmap[hr]==-1) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<<hr);
+ cur->isconst&=~(1<<hr);
+ return;
+ }
+ }
+
+ // Find an unneeded register
+ for(hr=HOST_REGS-1;hr>=0;hr--)
+ {
+ r=cur->regmap[hr];
+ if(r>=0) {
+ assert(r < 64);
+ if((cur->u>>r)&1) {
+ if(i==0||((unneeded_reg[i-1]>>r)&1)) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<<hr);
+ cur->isconst&=~(1<<hr);
+ return;
+ }
+ }
+ }
+ }
+
+ // Ok, now we have to evict someone
+ // Pick a register we hopefully won't need soon
+ // TODO: we might want to follow unconditional jumps here
+ // TODO: get rid of dupe code and make this into a function
+ u_char hsn[MAXREG+1];
+ memset(hsn,10,sizeof(hsn));
+ int j;
+ lsn(hsn,i,&preferred_reg);
+ //printf("hsn: %d %d %d %d %d %d %d\n",hsn[cur->regmap[0]&63],hsn[cur->regmap[1]&63],hsn[cur->regmap[2]&63],hsn[cur->regmap[3]&63],hsn[cur->regmap[5]&63],hsn[cur->regmap[6]&63],hsn[cur->regmap[7]&63]);
+ if(i>0) {
+ // Don't evict the cycle count at entry points, otherwise the entry
+ // stub will have to write it.
+ if(bt[i]&&hsn[CCREG]>2) hsn[CCREG]=2;
+ if(i>1&&hsn[CCREG]>2&&(itype[i-2]==RJUMP||itype[i-2]==UJUMP||itype[i-2]==CJUMP||itype[i-2]==SJUMP)) hsn[CCREG]=2;
+ for(j=10;j>=3;j--)
+ {
+ for(r=1;r<=MAXREG;r++)
+ {
+ if(hsn[r]==j&&r!=rs1[i-1]&&r!=rs2[i-1]&&r!=rt1[i-1]&&r!=rt2[i-1]) {
+ for(hr=0;hr<HOST_REGS;hr++) {
+ if(hr!=HOST_CCREG||hsn[CCREG]>2) {
+ if(cur->regmap[hr]==r) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<<hr);
+ cur->isconst&=~(1<<hr);
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ for(j=10;j>=0;j--)
+ {
+ for(r=1;r<=MAXREG;r++)
+ {
+ if(hsn[r]==j) {
+ for(hr=0;hr<HOST_REGS;hr++) {
+ if(cur->regmap[hr]==r) {
+ cur->regmap[hr]=reg;
+ cur->dirty&=~(1<<hr);
+ cur->isconst&=~(1<<hr);
+ return;
+ }
+ }
+ }
+ }
+ }
+ SysPrintf("This shouldn't happen");abort();
+}
+