decoder.c 6.75 KB
/*
 * Copyright (C) 1998 by the Board of Trustees
 *    of Leland Stanford Junior University.
 * Copyright (C) 1998 Digital Equipment Corporation
 *
 * This file is part of the SimOS distribution.
 * See LICENSE file for terms of the license.
 *
 */






#include "simtypes.h"
#include "sim_error.h"

#include "tc.h"
#include "arch_specifics.h"
#include "alpha.h"
#include "alpha_regs.h"
#include "gamma.h"

#include "delta.h"
#include "decoder.h"


static inline void PreloadRegister(struct RegAlloc *regAlloc, int reg)
{
   uint32 bit = 1<<reg;
   if (reg==REG_ZERO) return;
   if (!(regAlloc->accessed & bit)) {
      regAlloc->accessed |= bit;     
      if (regAlloc->numRegsAlloc < NUM_SHADOW_REGS) {
         regAlloc->reg[reg] = regAlloc->numRegsAlloc;
         regAlloc->preload[regAlloc->numRegsAlloc++] = reg;
      }
   }
}

static inline void KillRegister(struct RegAlloc *regAlloc,int reg)
{
   uint32 bit = 1<<reg;
   if (!(regAlloc->accessed & bit)) {
      regAlloc->accessed |= bit;     
   }
}


static void DecodeBlock( VA vPC,  MA mPC, BasicBlock *bb) 
{  
   int offset=0;
   register union alpha_instruction inst;
   BasicBlockInstr *bbInst = bb->instr;
   int stop=0;
   int opcode;
   bb->usesFP = 0;

   while(!stop && PAGE_NUMBER(vPC+offset) == PAGE_NUMBER(vPC) && 
         bb->numInstructions <DECODER_MAX_INSTR) {
   
      inst = *(union alpha_instruction *) (mPC+offset);
      bbInst->instr = inst;
      bbInst->offset = offset;
      bbInst->cycles = bb->numCycles++;
      bbInst->saveReg = REG_ZERO;
      bbInst->isBranch = 0;


      opcode = inst.common.opcode;
      switch(opcode) {
       
      case op_call_pal:
      case op_misc:  
      callout_misc:
         bbInst->saveReg |= SAVE_REG_CALLOUT;
         stop = 1;
         break;

      case op_br:
      case op_bsr:
         KillRegister(&bb->regAlloc,inst.b_format.ra);
         bbInst->mergedBranch = 0;
         bbInst->isBranch = 1;
         stop = 1;
         if (delta.mergeBranches) {
            int dist = inst.b_format.branch_displacement<<2;
            VA targetPC = vPC + offset + dist + 4;
            if (VADDR2VPN(vPC)==VADDR2VPN(targetPC)) {
#if 0
               CPUPrint("Merged branch at pc=0x%lx mPC=0x%lx target=0x%lx \n",
                          vPC,mPC,targetPC);
#endif
               stop = 0;
               bbInst->mergedBranch = 1;
               offset+=dist;
            }
         }
         
         break;

      case op_blbc:
      case op_beq:
      case op_blt:
      case op_ble:
      case op_blbs:
      case op_bne:
      case op_bge:
      case op_bgt:
         PreloadRegister(&bb->regAlloc,inst.b_format.ra);
         stop = 1;
         bbInst->isBranch = 1;
         break;

      case op_fbeq:
      case op_fblt:
      case op_fble:
      case op_fbne:
      case op_fbge:
      case op_fbgt:
	 bb->usesFP = 1;
         bbInst->isBranch = 1;
         stop = 1;
         break;
      
      case op_opc14:
	 /* @@@@ */ 
	 NOTREACHED();
	 goto callout_misc;

	 bb->usesFP = 1;
	 goto callout_misc;

      case op_ldf:
      case op_ldg:
      case op_lds:
      case op_ldt:
      case op_stf:
      case op_stg:
      case op_sts:
      case op_stt:
      case op_fltv: 
      case op_flti:
      case op_fltl:
	 bb->usesFP = 1;
	 break;

      case op_jsr:
         PreloadRegister(&bb->regAlloc,inst.j_format.ra);
         stop = 1;
         bbInst->isBranch = 1;
         break;

      case op_intl:
         if (inst.o_format.function == intl_amask
             || inst.o_format.function == intl_implver) {
            goto callout_misc;
            break;
         } else {
            goto int_ops;
         }
      int_ops:
      case op_inta:
      case op_ints:
      case op_intm:
         if (inst.o_format.rc != REG_ZERO) {
            int flags = gammaOperateFlags[opcode*(1<<7)+inst.o_format.function];
	    
            PreloadRegister(&bb->regAlloc,inst.o_format.ra);
            if (!inst.o_format.form) {
               PreloadRegister(&bb->regAlloc,inst.o_format.rb);
            }            
            bbInst->saveReg = inst.o_format.rc;
            if (flags&AXPTYPE_INT_CONDITIONAL) {
               PreloadRegister(&bb->regAlloc,inst.o_format.rc);
            } else {
               KillRegister(&bb->regAlloc,inst.o_format.rc);
            }
            if (flags & AXPTYPE_CANTRAP) {
               bbInst->saveReg |= SAVE_REG_CALLOUT;
            }
         }
         break;

      case op_lda: 
      case op_ldah:
	 bbInst->saveReg = inst.m_format.ra;
	 PreloadRegister(&bb->regAlloc,inst.m_format.rb);
         KillRegister(&bb->regAlloc,inst.m_format.ra);
         break;
  
      case op_ldq_u:
      case op_ldl:
      case op_ldq:
      case op_ldl_l:
      case op_ldq_l:

         bbInst->saveReg = (inst.m_format.ra|SAVE_REG_CALLOUT);
         PreloadRegister(&bb->regAlloc,inst.m_format.rb);
         KillRegister(&bb->regAlloc,inst.m_format.ra);
         break;

      case op_stq_u:
      case op_stl:
      case op_stq:
         bbInst->saveReg = SAVE_REG_CALLOUT;
         PreloadRegister(&bb->regAlloc,inst.m_format.ra);
         PreloadRegister(&bb->regAlloc,inst.m_format.rb);
         break;
        
      case op_stl_c:
      case op_stq_c:
         bbInst->saveReg = (SAVE_REG_CALLOUT | inst.m_format.ra);
         PreloadRegister(&bb->regAlloc,inst.m_format.ra);
         PreloadRegister(&bb->regAlloc,inst.m_format.rb);
         bb->hasSC = 1;
         break;

      default:
         /* nothing */
      } /* switch(opcode) */
  
      offset +=4;
      bb->numInstructions++;
      bbInst++;    

   }

   bb->nextPC = vPC+offset;
   
}  

static void OptimizeSaveReg(BasicBlock *bb)
{
   uint bv=0; /* bitvector of saved registers */
   int i;
   for (i=bb->numInstructions-1;i>=0;i--) {
      int saveReg = bb->instr[i].saveReg;
      int reg = saveReg & REG_ZERO;
      uint mask = (1<<reg);
      if ((reg != REG_ZERO) && (bv&mask)) {
         bb->instr[i].saveReg |= SAVE_REG_OPT;
      } else {
         bv |= mask;
      }
      if (saveReg & SAVE_REG_CALLOUT) {
         bv = 0;
      }
   }
}

         

void Decode( VA vPC,  MA mPC, BasicBlock *bb) 
{  
   int i;
   bb->vPC = vPC;
   bb->mPC = mPC;
   bb->numInstructions = 0;
   bb->numCycles = 0;
   bb->hasPCAnn =0;
   bb->hasSC = 0;
   
   bzero((char *)&bb->regAlloc,sizeof(bb->regAlloc));
   bb->regAlloc.numRegsAlloc= 1; /* 0 fakes out REG_ZERO */
   
   DecodeBlock(vPC,mPC,bb);

   for (i=0;i<bb->numInstructions;i++) {
      BasicBlockInstr *bbInst = &bb->instr[i];
      bbInst->prePCAnn  = (AnnFMLookup(vPC+bbInst->offset,ANNFM_PRE_PC_TYPE)!=0);
      bbInst->postPCAnn = (AnnFMLookup(vPC+bbInst->offset,ANNFM_PC_TYPE)!=0);
      bb->hasPCAnn |= (bbInst->prePCAnn | bbInst->postPCAnn) ;
   }
   
   if (delta.saveRegOpt && !bb->hasPCAnn && !bb->hasSC && !bb->usesFP) {
      OptimizeSaveReg(bb);
   }
}