예제 #1
0
파일: main_util.cpp 프로젝트: sos22/SLI
void LibVEX_ShowAllocStats ( void )
{
   vex_printf("vex storage: T total %lld bytes allocated\n",
              (Long)temporary_bytes_allocd_TOT );
   vex_printf("vex storage: P total %lld bytes allocated\n",
              (Long)(permanent_curr - permanent_first) );
}
예제 #2
0
void ppHRegClass ( HRegClass hrc )
{
   switch (hrc) {
      case HRcInt32:   vex_printf("HRcInt32"); break;
      case HRcInt64:   vex_printf("HRcInt64"); break;
      case HRcFlt64:   vex_printf("HRcFlt64"); break;
      case HRcVec64:   vex_printf("HRcVec64"); break;
      case HRcVec128:  vex_printf("HRcVec128"); break;
      default: vpanic("ppHRegClass");
   }
}
예제 #3
0
void ppHRegRemap ( HRegRemap* map )
{
   Int   i;
   vex_printf("HRegRemap {\n");
   for (i = 0; i < map->n_used; i++) {
      vex_printf("   ");
      ppHReg(map->orig[i]);
      vex_printf("  -->  ");
      ppHReg(map->replacement[i]);
      vex_printf("\n");
   }
   vex_printf("}\n");
}
예제 #4
0
/* Generic printing for registers. */
void ppHReg ( HReg r ) 
{
   HChar* maybe_v = hregIsVirtual(r) ? "v" : "";
   Int    regNo   = hregNumber(r);
   switch (hregClass(r)) {
      case HRcInt32:   vex_printf("%%%sr%d", maybe_v, regNo); return;
      case HRcInt64:   vex_printf("%%%sR%d", maybe_v, regNo); return;
      case HRcFlt64:   vex_printf("%%%sF%d", maybe_v, regNo); return;
      case HRcVec64:   vex_printf("%%%sv%d", maybe_v, regNo); return;
      case HRcVec128:  vex_printf("%%%sV%d", maybe_v, regNo); return;
      default: vpanic("ppHReg");
   }
}
예제 #5
0
파일: main_util.cpp 프로젝트: sos22/SLI
void private_LibVEX_alloc_OOM(void)
{
   const char* pool = "???";
   if (private_LibVEX_alloc_first == &temporary[0]) pool = "TEMP";
   if (private_LibVEX_alloc_first == &permanent[0]) pool = "PERM";
   vex_printf("VEX temporary storage exhausted.\n");
   vex_printf("Pool = %s,  start %p curr %p end %p (size %lld)\n",
              pool, 
              private_LibVEX_alloc_first,
              private_LibVEX_alloc_curr,
              private_LibVEX_alloc_last,
              (Long)(private_LibVEX_alloc_last + 1 - private_LibVEX_alloc_first));
   vpanic("VEX temporary storage exhausted.\n"
          "Increase N_{TEMPORARY,PERMANENT}_BYTES and recompile.");
}
예제 #6
0
static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
{
    ARMBranchDest* bd;
    if (vex_traceflags & VEX_TRACE_VCODE) {
	vex_printf("\n-- goto {");
	ppIRJumpKind(jk);
	vex_printf("} ");
	ppIRExpr(next);
	vex_printf("\n");
    }
    bd = iselIntExpr_BD(env, next);
    
    // CAB: jk ?

    addInstr( env, ARMInstr_Branch(ARMccAL, bd) );
}
예제 #7
0
파일: main_util.c 프로젝트: sos22/ppres
void vex_assert_fail ( const HChar* expr,
                       const HChar* file, Int line, const HChar* fn )
{
   vex_printf( "\nvex: %s:%d (%s): Assertion `%s' failed.\n",
               file, line, fn, expr );
   (*vex_failure_exit)();
}
예제 #8
0
/*static*/
UInt armg_calculate_condition ( UInt/*ARMCondcode*/ cond, 
                                UInt cc_op, 
                                UInt cc_dep1, 
                                UInt cc_dep2 )
{
   UInt nf,zf,vf,cf;
   UInt inv = cond & 1;

   UInt nzvc = armg_calculate_flags_all(cc_op, cc_dep1, cc_dep2);

   switch (cond) {
   case ARMCondEQ:    // Z=1         => z
   case ARMCondNE:    // Z=0
      zf = nzvc >> ARMG_CC_SHIFT_Z;
      return 1 & (inv ^ zf);

   case ARMCondHS:    // C=1         => c
   case ARMCondLO:    // C=0
      cf = nzvc >> ARMG_CC_SHIFT_C;
      return 1 & (inv ^ cf);

   case ARMCondMI:    // N=1         => n
   case ARMCondPL:    // N=0
      nf = nzvc >> ARMG_CC_SHIFT_N;
      return 1 & (inv ^ nf);

   case ARMCondVS:    // V=1         => v
   case ARMCondVC:    // V=0
      vf = nzvc >> ARMG_CC_SHIFT_V;
      return 1 & (inv ^ vf);

   case ARMCondHI:    // C=1 && Z=0   => c & ~z
   case ARMCondLS:    // C=0 || Z=1
      cf = nzvc >> ARMG_CC_SHIFT_C;
      zf = nzvc >> ARMG_CC_SHIFT_Z;
      return 1 & (inv ^ (cf & ~zf));

   case ARMCondGE:    // N=V          => ~(n^v)
   case ARMCondLT:    // N!=V
      nf = nzvc >> ARMG_CC_SHIFT_N;
      vf = nzvc >> ARMG_CC_SHIFT_V;
      return 1 & (inv ^ ~(nf ^ vf));

   case ARMCondGT:    // Z=0 && N=V   => (~z & ~(n^v)  =>  ~(z | (n^v)
   case ARMCondLE:    // Z=1 || N!=V
      nf = nzvc >> ARMG_CC_SHIFT_N;
      vf = nzvc >> ARMG_CC_SHIFT_V;
      zf = nzvc >> ARMG_CC_SHIFT_Z;
       return 1 & (inv ^ ~(zf | (nf ^ vf)));

   case ARMCondAL:   // should never get here: Always => no flags to calc
   case ARMCondNV:   // should never get here: Illegal instr
   default:
      /* shouldn't really make these calls from generated code */
      vex_printf("armg_calculate_condition(ARM)( %u, %u, 0x%x, 0x%x )\n",
                 cond, cc_op, cc_dep1, cc_dep2 );
      vpanic("armg_calculate_condition(ARM)");
   }
}
예제 #9
0
static void addInstr ( ISelEnv* env, ARMInstr* instr )
{
   addHInstr(env->code, instr);
   if (vex_traceflags & VEX_TRACE_VCODE) {
      ppARMInstr(instr);
      vex_printf("\n");
   }
}
예제 #10
0
void ppHRegUsage ( HRegUsage* tab )
{
   Int    i;
   HChar* str;
   vex_printf("HRegUsage {\n");
   for (i = 0; i < tab->n_used; i++) {
      switch (tab->mode[i]) {
         case HRmRead:   str = "Read   "; break;
         case HRmWrite:  str = "Write  "; break;
         case HRmModify: str = "Modify "; break;
         default: vpanic("ppHRegUsage");
      }
      vex_printf("   %s ", str);
      ppHReg(tab->hreg[i]);
      vex_printf("\n");
   }
   vex_printf("}\n");
}
예제 #11
0
void ppHRegUsage ( const RRegUniverse* univ, HRegUsage* tab )
{
   /* This is going to fail miserably if N_RREGUNIVERSE_REGS exceeds
      64.  So let's cause it to fail in an obvious way. */
   vassert(N_RREGUNIVERSE_REGS == 64);

   vex_printf("HRegUsage {\n");
   /* First print the real regs */
   for (UInt i = 0; i < N_RREGUNIVERSE_REGS; i++) {
      Bool rRd = (tab->rRead    & (1ULL << i)) != 0;
      Bool rWr = (tab->rWritten & (1ULL << i)) != 0;
      const HChar* str = "Modify ";
      /**/ if (!rRd && !rWr) { continue; }
      else if ( rRd && !rWr) { str = "Read   "; }
      else if (!rRd &&  rWr) { str = "Write  "; }
      /* else "Modify" is correct */
      vex_printf("   %s ", str);
      ppHReg(univ->regs[i]);
      vex_printf("\n");
   }
   /* and now the virtual registers */
   for (UInt i = 0; i < tab->n_vRegs; i++) {
      const HChar* str = NULL;
      switch (tab->vMode[i]) {
         case HRmRead:   str = "Read   "; break;
         case HRmWrite:  str = "Write  "; break;
         case HRmModify: str = "Modify "; break;
         default: vpanic("ppHRegUsage");
      }
      vex_printf("   %s ", str);
      ppHReg(tab->vRegs[i]);
      vex_printf("\n");
   }
   vex_printf("}\n");
}
예제 #12
0
void
vexAudioDebugChipTone()
{
    int i;
    vsl_ct  *p;

    if( VSL_ctarray != NULL )
        {
        for(i=0;i<ctSize;i++)
            {
            p = &(VSL_ctarray[ i ]);

#ifdef VSL_AMP_PER_TONE
            vex_printf("%d %d %d\r\n", p->freq, p->amplitude, p->timems );
#else
            vex_printf("%d %d %d\r\n", p->freq, ctAmplitude, p->timems );
#endif
            }
        }

    return;
}
예제 #13
0
/* Double the size of the real-reg live-range array, if needed. */
static void ensureRRLRspace ( RRegLR** info, Int* size, Int used )
{
   Int     k;
   RRegLR* arr2;
   if (used < *size) return;
   if (0)
      vex_printf("ensureRRISpace: %d -> %d\n", *size, 2 * *size);
   vassert(used == *size);
   arr2 = LibVEX_Alloc(2 * *size * sizeof(RRegLR));
   for (k = 0; k < *size; k++)
      arr2[k] = (*info)[k];
   *size *= 2;
   *info = arr2;
}
예제 #14
0
void ppARMAMode1 ( ARMAMode1* am ) {
   switch (am->tag) {
   case ARMam1_I12A:
   case ARMam1_ShlI:
   case ARMam1_ShrI:
   case ARMam1_SarI:
   case ARMam1_ShlR:
   case ARMam1_ShrR:
   case ARMam1_SarR:
       vex_printf("ppARMAMode1: Not implemented");
       break;
   default:
       vpanic("ppARMAMode1");
   }
}
예제 #15
0
/* Calculate all the 4 flags from the supplied thunk parameters. */
UInt armg_calculate_flags_all ( UInt cc_op, 
                                UInt cc_dep1_formal, 
                                UInt cc_dep2_formal )
{
   switch (cc_op) {
   case ARMG_CC_OP_LOGIC:  ACTIONS_LOGIC();
   case ARMG_CC_OP_ADD:  ACTIONS_ADD();
   case ARMG_CC_OP_SUB:  ACTIONS_SUB();

   default:
      /* shouldn't really make these calls from generated code */
      vex_printf("armg_calculate_flags_all(ARM)( %u, 0x%x, 0x%x )\n",
                 cc_op, cc_dep1_formal, cc_dep2_formal );
      vpanic("armg_calculate_flags_all(ARM)");
   }
}
예제 #16
0
void ppHRegARM ( HReg reg )  {
   Int r;
   static HChar* ireg32_names[16] 
     = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8",
	 "r9", "r10", "r11", "r12", "r13", "r14", "r15" };

   /* Be generic for all virtual regs. */
   if (hregIsVirtual(reg)) {
      ppHReg(reg);
      return;
   }
   /* But specific for real regs. */
   switch (hregClass(reg)) {
      case HRcInt32:
         r = hregNumber(reg);
         vassert(r >= 0 && r < 16);
         vex_printf("%s", ireg32_names[r]);
         return;
      default:
         vpanic("ppHRegARM");
   }
}
예제 #17
0
/* Generic printing for registers. */
void ppHReg ( HReg r ) 
{
   if (hregIsInvalid(r)) {
      vex_printf("HReg_INVALID");
      return;
   }
   const Bool   isV     = hregIsVirtual(r);
   const HChar* maybe_v = isV ? "v" : "";
   const UInt   regNN   = isV ? hregIndex(r) : hregEncoding(r);
   /* For real registers, we show the encoding.  But the encoding is
      always zero for virtual registers, so that's pointless -- hence
      show the index number instead. */
   switch (hregClass(r)) {
      case HRcInt32:   vex_printf("%%%sr%u", maybe_v, regNN); return;
      case HRcInt64:   vex_printf("%%%sR%u", maybe_v, regNN); return;
      case HRcFlt32:   vex_printf("%%%sF%u", maybe_v, regNN); return;
      case HRcFlt64:   vex_printf("%%%sD%u", maybe_v, regNN); return;
      case HRcVec64:   vex_printf("%%%sv%u", maybe_v, regNN); return;
      case HRcVec128:  vex_printf("%%%sV%u", maybe_v, regNN); return;
      default: vpanic("ppHReg");
   }
}
예제 #18
0
void ppRetLoc ( RetLoc ska )
{
   switch (ska.pri) {
      case RLPri_INVALID:
         vex_printf("RLPri_INVALID"); return;
      case RLPri_None:
         vex_printf("RLPri_None");    return;
      case RLPri_Int:
         vex_printf("RLPri_Int");     return;
      case RLPri_2Int:
         vex_printf("RLPri_2Int");    return;
      case RLPri_V128SpRel:
         vex_printf("RLPri_V128SpRel(%d)", ska.spOff); return;
      case RLPri_V256SpRel:
         vex_printf("RLPri_V256SpRel(%d)", ska.spOff); return;
      default:
         vpanic("ppRetLoc");
   }
}
예제 #19
0
/* Inject IR stmts depending on the data provided in the control
   block iricb. */
void
vex_inject_ir(IRSB *irsb, IREndness endian)
{
   IRExpr *data, *rounding_mode, *opnd1, *opnd2, *opnd3, *opnd4;

   rounding_mode = NULL;
   if (iricb.rounding_mode != NO_ROUNDING_MODE) {
      rounding_mode = mkU32(iricb.rounding_mode);
   }

   switch (iricb.num_operands) {
   case 1:
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
      if (rounding_mode)
         data = binop(iricb.op, rounding_mode, opnd1);
      else
         data = unop(iricb.op, opnd1);
      break;

   case 2:
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);

      if (iricb.shift_amount_is_immediate) {
         // This implies that the IROp is a shift op
         vassert(iricb.t_opnd2 == Ity_I8);
         opnd2 = mkU8(*((Char *)iricb.opnd2));
      } else {
         opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
      }

      if (rounding_mode)
         data = triop(iricb.op, rounding_mode, opnd1, opnd2);
      else
         data = binop(iricb.op, opnd1, opnd2);
      break;

   case 3:
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
      opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
      opnd3 = load(endian, iricb.t_opnd3, iricb.opnd3);
      if (rounding_mode)
         data = qop(iricb.op, rounding_mode, opnd1, opnd2, opnd3);
      else
         data = triop(iricb.op, opnd1, opnd2, opnd3);
      break;

   case 4:
      vassert(rounding_mode == NULL);
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
      opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
      opnd3 = load(endian, iricb.t_opnd3, iricb.opnd3);
      opnd4 = load(endian, iricb.t_opnd4, iricb.opnd4);
      data = qop(iricb.op, opnd1, opnd2, opnd3, opnd4);
      break;

   default:
      vpanic("unsupported operator");
   }

   store(irsb, endian, iricb.result, data);

   if (0) {
      vex_printf("BEGIN inject\n");
      if (iricb.t_result == Ity_I1 || sizeofIRType(iricb.t_result) <= 8) {
         ppIRStmt(irsb->stmts[irsb->stmts_used - 1]);
      } else if (sizeofIRType(iricb.t_result) == 16) {
         ppIRStmt(irsb->stmts[irsb->stmts_used - 2]);
         vex_printf("\n");
         ppIRStmt(irsb->stmts[irsb->stmts_used - 1]);
      }
      vex_printf("\nEND inject\n");
   }
}
예제 #20
0
void traceIRStmt (IRSB * sb,  IRStmt* st , ULong caMainBBCounter)
{
   //  unsigned long n_old_typestates_state_instance = 0; 
   IRExpr * rhs; 
   static Addr current_addr = 0;
   counter = caMainBBCounter; 
   if (!st) {
      vex_printf("IRStmt* which is NULL !!!");
      return;
   }
   switch (st->tag) {
      case Ist_NoOp:
	 break; /* Nothing to emit. */
      case Ist_IMark:
	 current_addr = st->Ist.IMark.addr;
//	 VG_(message)(Vg_UserMsg, "addr is %lx \n", current_addr);
//	 VG_(message)(Vg_UserMsg, "(void*)current_addr is %p\n ", (void*)current_addr);
//	 VG_(message)(Vg_UserMsg, "&malloc is %p\n ", &malloc);
/*
	 if((void*)current_addr == VG_(fnptr_to_fnentry)( &SC_malloc ) ||
	    (void*)current_addr == VG_(fnptr_to_fnentry)( &SC__builtin_new ) ||
	    (void*)current_addr == VG_(fnptr_to_fnentry)( &SC__builtin_vec_new )
	   )
	   {
		argNum = 1;
	   }
	 if((void*)current_addr == VG_(fnptr_to_fnentry)( &SC_calloc ) ||
	    (void*)current_addr == VG_(fnptr_to_fnentry)( &SC_memalign )
	   )
	   {
		argNum = 2;
	   }
	 if((void*)current_addr == VG_(fnptr_to_fnentry)( &SC_realloc ) )
	   {
		isRealloc = 1;
		argNum = 1;
	   }
*/
	 if(current_addr == 0x4c2b20d )
	   {
		argNum = 1;
	   }
	 if(current_addr == 0x4c294e0 )
	   {
		argNum = 2;
	   }
	 if(current_addr == 0x4c2b3b8 )
	   {
		isRealloc = 1;
		argNum = 1;
	   }

	 break; 
      case Ist_AbiHint:
	 break; /* Nothing to emit. */ 

      case Ist_Put:
	 /* TODO: update map of names -> typestate vars */ 
	 /* PUT(30) = t32 --> VarOf(reg.30) := VarOf(eipX.t32) */ 
	 /* PUT(30) = const --> VarOf(reg.30) := NONE */ 
	 rhs = st->Ist.Put.data;
	 AddPutHelper(sb, st->Ist.Put.offset,rhs);
         break;

      case Ist_PutI:
	 /* TODO: update map of names -> typestate vars */ 
         break;

      case Ist_WrTmp:
//	 rhs = st->Ist.Tmp.data; 
	 traceIRExpr(sb,st,current_addr); 

         break;
      case Ist_Store:
	 /* TODO: update map of names -> typestate vars */ 
	 AddStoreHelper(sb,st->Ist.Store.addr,st->Ist.Store.data); 
         break;
      case Ist_Dirty:
	 /* TODO: handle common dirty helpers here */ 
         break;
      case Ist_MBE: 
         break; /* Nothing to emit. */ 

      case Ist_Exit:
	 /* No need to emit constraints here; catch earlier at CMP or */
	 /* at x86g_calc_condition. Do nothing. */ 
         break;
      default: 
	 return; 
   }
}
예제 #21
0
IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
                 /*IN*/ void*            callback_opaque,
                 /*IN*/ DisOneInstrFn    dis_instr_fn,
                 /*IN*/ UChar*           guest_code,
                 /*IN*/ Addr64           guest_IP_bbstart,
                 /*IN*/ Bool             (*chase_into_ok)(void*,Addr64),
                 /*IN*/ Bool             host_bigendian,
                 /*IN*/ VexArch          arch_guest,
                 /*IN*/ VexArchInfo*     archinfo_guest,
                 /*IN*/ IRType           guest_word_type,
                 /*IN*/ Bool             do_self_check,
                 /*IN*/ Bool             (*preamble_function)(void*,IRBB*),
                 /*IN*/ Int              offB_TISTART,
                 /*IN*/ Int              offB_TILEN )
{
   Long       delta;
   Int        i, n_instrs, first_stmt_idx;
   Bool       resteerOK, need_to_put_IP, debug_print;
   DisResult  dres;
   IRStmt*    imark;
   static Int n_resteers = 0;
   Int        d_resteers = 0;
   Int        selfcheck_idx = 0;
   IRBB*      irbb;
   Addr64     guest_IP_curr_instr;
   IRConst*   guest_IP_bbstart_IRConst = NULL;

   Bool (*resteerOKfn)(void*,Addr64) = NULL;

   debug_print = toBool(vex_traceflags & VEX_TRACE_FE);

   /* Note: for adler32 to work without % operation for the self
      check, need to limit length of stuff it scans to 5552 bytes.
      Therefore limiting the max bb len to 100 insns seems generously
      conservative. */

   /* check sanity .. */
   vassert(sizeof(HWord) == sizeof(void*));
   vassert(vex_control.guest_max_insns >= 1);
   vassert(vex_control.guest_max_insns < 100);
   vassert(vex_control.guest_chase_thresh >= 0);
   vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns);
   vassert(guest_word_type == Ity_I32 || guest_word_type == Ity_I64);

   /* Start a new, empty extent. */
   vge->n_used  = 1;
   vge->base[0] = guest_IP_bbstart;
   vge->len[0]  = 0;

   /* And a new IR BB to dump the result into. */
   irbb = emptyIRBB();

   /* Delta keeps track of how far along the guest_code array we have
      so far gone. */
   delta    = 0;
   n_instrs = 0;

   /* Guest addresses as IRConsts.  Used in the two self-checks
      generated. */
   if (do_self_check) {
      guest_IP_bbstart_IRConst
         = guest_word_type==Ity_I32 
              ? IRConst_U32(toUInt(guest_IP_bbstart))
              : IRConst_U64(guest_IP_bbstart);
   }

   /* If asked to make a self-checking translation, leave 5 spaces
      in which to put the check statements.  We'll fill them in later
      when we know the length and adler32 of the area to check. */
   if (do_self_check) {
      selfcheck_idx = irbb->stmts_used;
      addStmtToIRBB( irbb, IRStmt_NoOp() );
      addStmtToIRBB( irbb, IRStmt_NoOp() );
      addStmtToIRBB( irbb, IRStmt_NoOp() );
      addStmtToIRBB( irbb, IRStmt_NoOp() );
      addStmtToIRBB( irbb, IRStmt_NoOp() );
   }

   /* If the caller supplied a function to add its own preamble, use
      it now. */
   if (preamble_function) {
      Bool stopNow = preamble_function( callback_opaque, irbb );
      if (stopNow) {
         /* The callback has completed the IR block without any guest
            insns being disassembled into it, so just return it at
            this point, even if a self-check was requested - as there
            is nothing to self-check.  The five self-check no-ops will
            still be in place, but they are harmless. */
         return irbb;
      }
   }

   /* Process instructions. */
   while (True) {
      vassert(n_instrs < vex_control.guest_max_insns);

      /* Regardless of what chase_into_ok says, is chasing permissible
         at all right now?  Set resteerOKfn accordingly. */
      resteerOK 
         = toBool(
              n_instrs < vex_control.guest_chase_thresh
              /* If making self-checking translations, don't chase
                 .. it makes the checks too complicated.  We only want
                 to scan just one sequence of bytes in the check, not
                 a whole bunch. */
              && !do_self_check
              /* we can't afford to have a resteer once we're on the
                 last extent slot. */
              && vge->n_used < 3
           );

      resteerOKfn
         = resteerOK ? chase_into_ok : const_False;

      /* This is the IP of the instruction we're just about to deal
         with. */
      guest_IP_curr_instr = guest_IP_bbstart + delta;

      /* This is the irbb statement array index of the first stmt in
         this insn.  That will always be the instruction-mark
         descriptor. */
      first_stmt_idx = irbb->stmts_used;

      /* Add an instruction-mark statement.  We won't know until after
         disassembling the instruction how long it instruction is, so
         just put in a zero length and we'll fix it up later. */
      addStmtToIRBB( irbb, IRStmt_IMark( guest_IP_curr_instr, 0 ));

      /* for the first insn, the dispatch loop will have set
         %IP, but for all the others we have to do it ourselves. */
      need_to_put_IP = toBool(n_instrs > 0);

      /* Finally, actually disassemble an instruction. */
      dres = dis_instr_fn ( irbb,
                            need_to_put_IP,
                            resteerOKfn,
                            callback_opaque,
                            guest_code,
                            delta,
                            guest_IP_curr_instr,
                            arch_guest,
                            archinfo_guest,
                            host_bigendian );

      /* stay sane ... */
      vassert(dres.whatNext == Dis_StopHere
              || dres.whatNext == Dis_Continue
              || dres.whatNext == Dis_Resteer);
      vassert(dres.len >= 0 && dres.len <= 20);
      if (dres.whatNext != Dis_Resteer)
         vassert(dres.continueAt == 0);

      /* Fill in the insn-mark length field. */
      vassert(first_stmt_idx >= 0 && first_stmt_idx < irbb->stmts_used);
      imark = irbb->stmts[first_stmt_idx];
      vassert(imark);
      vassert(imark->tag == Ist_IMark);
      vassert(imark->Ist.IMark.len == 0);
      imark->Ist.IMark.len = toUInt(dres.len);

      /* Print the resulting IR, if needed. */
      if (vex_traceflags & VEX_TRACE_FE) {
         for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
            vex_printf("              ");
            ppIRStmt(irbb->stmts[i]);
            vex_printf("\n");
         }
      }

      /* If dis_instr_fn terminated the BB at this point, check it
	 also filled in the irbb->next field. */
      if (dres.whatNext == Dis_StopHere) {
         vassert(irbb->next != NULL);
         if (debug_print) {
            vex_printf("              ");
            vex_printf( "goto {");
            ppIRJumpKind(irbb->jumpkind);
            vex_printf( "} ");
            ppIRExpr( irbb->next );
            vex_printf( "\n");
         }
      }

      /* Update the VexGuestExtents we are constructing. */
      /* If vex_control.guest_max_insns is required to be < 100 and
	 each insn is at max 20 bytes long, this limit of 5000 then
	 seems reasonable since the max possible extent length will be
	 100 * 20 == 2000. */
      vassert(vge->len[vge->n_used-1] < 5000);
      vge->len[vge->n_used-1] 
         = toUShort(toUInt( vge->len[vge->n_used-1] + dres.len ));
      n_instrs++;
      if (debug_print) 
         vex_printf("\n");

      /* Advance delta (inconspicuous but very important :-) */
      delta += (Long)dres.len;

      switch (dres.whatNext) {
         case Dis_Continue:
            vassert(irbb->next == NULL);
            if (n_instrs < vex_control.guest_max_insns) {
               /* keep going */
            } else {
               /* We have to stop. */
               irbb->next 
                  = IRExpr_Const(
                       guest_word_type == Ity_I32
                          ? IRConst_U32(toUInt(guest_IP_bbstart+delta))
                          : IRConst_U64(guest_IP_bbstart+delta)
                    );
               goto done;
            }
            break;
         case Dis_StopHere:
            vassert(irbb->next != NULL);
            goto done;
         case Dis_Resteer:
            /* Check that we actually allowed a resteer .. */
            vassert(resteerOK);
            vassert(irbb->next == NULL);
            /* figure out a new delta to continue at. */
            vassert(resteerOKfn(callback_opaque,dres.continueAt));
            delta = dres.continueAt - guest_IP_bbstart;
            /* we now have to start a new extent slot. */
            vge->n_used++;
            vassert(vge->n_used <= 3);
            vge->base[vge->n_used-1] = dres.continueAt;
            vge->len[vge->n_used-1] = 0;
            n_resteers++;
            d_resteers++;
            if (0 && (n_resteers & 0xFF) == 0)
            vex_printf("resteer[%d,%d] to 0x%llx (delta = %lld)\n",
                       n_resteers, d_resteers,
                       dres.continueAt, delta);
            break;
         default:
            vpanic("bb_to_IR");
      }
   }
   /*NOTREACHED*/
   vassert(0);

  done:
   /* We're done.  The only thing that might need attending to is that
      a self-checking preamble may need to be created. */
   if (do_self_check) {

      UInt     len2check, adler32;
      IRTemp   tistart_tmp, tilen_tmp;

      vassert(vge->n_used == 1);
      len2check = vge->len[0];
      if (len2check == 0) 
         len2check = 1;

     adler32 = genericg_compute_adler32( (HWord)guest_code, len2check );

     /* Set TISTART and TILEN.  These will describe to the despatcher
        the area of guest code to invalidate should we exit with a
        self-check failure. */

     tistart_tmp = newIRTemp(irbb->tyenv, guest_word_type);
     tilen_tmp   = newIRTemp(irbb->tyenv, guest_word_type);

     irbb->stmts[selfcheck_idx+0]
        = IRStmt_Tmp(tistart_tmp, IRExpr_Const(guest_IP_bbstart_IRConst) );

     irbb->stmts[selfcheck_idx+1]
        = IRStmt_Tmp(tilen_tmp,
                     guest_word_type==Ity_I32 
                        ? IRExpr_Const(IRConst_U32(len2check)) 
                        : IRExpr_Const(IRConst_U64(len2check))
          );

     irbb->stmts[selfcheck_idx+2]
        = IRStmt_Put( offB_TISTART, IRExpr_Tmp(tistart_tmp) );

     irbb->stmts[selfcheck_idx+3]
        = IRStmt_Put( offB_TILEN, IRExpr_Tmp(tilen_tmp) );

     irbb->stmts[selfcheck_idx+4]
        = IRStmt_Exit( 
             IRExpr_Binop( 
                Iop_CmpNE32, 
                mkIRExprCCall( 
                   Ity_I32, 
                   2/*regparms*/, 
                   "genericg_compute_adler32",
#if defined(__powerpc__) && defined(__powerpc64__)
                   (void*)((ULong*)(&genericg_compute_adler32))[0],
#else
                   &genericg_compute_adler32,
#endif
                   mkIRExprVec_2( 
                      mkIRExpr_HWord( (HWord)guest_code ), 
                      mkIRExpr_HWord( (HWord)len2check )
                   )
                ),
                IRExpr_Const(IRConst_U32(adler32))
             ),
             Ijk_TInval,
             guest_IP_bbstart_IRConst
          );
   }

   return irbb;
}
예제 #22
0
파일: main_util.c 프로젝트: sos22/ppres
void vpanic ( HChar* str )
{
   vex_printf("\nvex: the `impossible' happened:\n   %s\n", str);
   (*vex_failure_exit)();
}
예제 #23
0
static void iselStmt ( ISelEnv* env, IRStmt* stmt )
{
   if (vex_traceflags & VEX_TRACE_VCODE) {
      vex_printf("\n-- ");
      ppIRStmt(stmt);
      vex_printf("\n");
   }
   switch (stmt->tag) {

   /* --------- STORE --------- */
   /* little-endian write to memory */
   case Ist_Store: {
       HReg   reg;
       IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr);
       IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
       IREndness end = stmt->Ist.Store.end;

       if (tya != Ity_I32 || end != Iend_LE) 
          goto stmt_fail;

       reg = iselIntExpr_R(env, stmt->Ist.Store.data);

       if (tyd == Ity_I8) {
	   ARMAMode2* am2 = iselIntExpr_AMode2(env, stmt->Ist.Store.addr);
	   addInstr(env, ARMInstr_StoreB(reg,am2));
	   return;
       }
       if (tyd == Ity_I16) {
	   ARMAMode3* am3 = iselIntExpr_AMode3(env, stmt->Ist.Store.addr);
	   addInstr(env, ARMInstr_StoreH(reg,am3));
	   return;
       }
       if (tyd == Ity_I32) {
	   ARMAMode2* am2 = iselIntExpr_AMode2(env, stmt->Ist.Store.addr);
	   addInstr(env, ARMInstr_StoreW(reg,am2));
	   return;
       }       
   }

   /* --------- PUT --------- */
   /* write guest state, fixed offset */
   case Ist_Put: {
       IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
       HReg reg = iselIntExpr_R(env, stmt->Ist.Put.data);

       // CAB: This anywhere near right?!
       if (tyd == Ity_I32) {
	   ARMAMode2* am2 = ARMAMode2_RI(GET_BP_REG(), stmt->Ist.Put.offset);
	   addInstr(env, ARMInstr_StoreW(reg, am2));
	   return;
       }
       if (tyd == Ity_I16) {
	   ARMAMode3* am3 = ARMAMode3_RI(GET_BP_REG(), stmt->Ist.Put.offset);
	   addInstr(env, ARMInstr_StoreH(reg, am3));
	   return;
       }
       if (tyd == Ity_I8) {
	   ARMAMode2* am2 = ARMAMode2_RI(GET_BP_REG(), stmt->Ist.Put.offset);
	   addInstr(env, ARMInstr_StoreB(reg, am2));
	   return;
       }
// CAB: Ity_I32, Ity_I16 ?
       break;
   }

   /* --------- Indexed PUT --------- */
   /* write guest state, run-time offset */
   case Ist_PutI: {
      ARMAMode2* am2
	   = genGuestArrayOffset(
	       env, stmt->Ist.PutI.descr, 
	       stmt->Ist.PutI.ix, stmt->Ist.PutI.bias );
       
       IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data);
       
       if (tyd == Ity_I8) {
	   HReg reg = iselIntExpr_R(env, stmt->Ist.PutI.data);
	   addInstr(env, ARMInstr_StoreB(reg, am2));
	   return;
       }
// CAB: Ity_I32, Ity_I16 ?
       break;
   }

   /* --------- TMP --------- */
   /* assign value to temporary */
   case Ist_WrTmp: {
      IRTemp tmp = stmt->Ist.WrTmp.tmp;
      IRType ty = typeOfIRTemp(env->type_env, tmp);

      if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
         ARMAMode1* am = iselIntExpr_AMode1(env, stmt->Ist.WrTmp.data);
         HReg dst = lookupIRTemp(env, tmp);
         addInstr(env, ARMInstr_DPInstr1(ARMalu_MOV,dst,am));
         return;
      }

// CAB: Ity_I1 ?

      break;
   }

   /* --------- Call to DIRTY helper --------- */
   /* call complex ("dirty") helper function */
   case Ist_Dirty: {
     //IRType   retty;
       IRDirty* d = stmt->Ist.Dirty.details;
       Bool     passBBP = False;

      if (d->nFxState == 0)
         vassert(!d->needsBBP);

      passBBP = toBool(d->nFxState > 0 && d->needsBBP);

      /* Marshal args, do the call, clear stack. */
      doHelperCall( env, passBBP, d->guard, d->cee, d->args );

      /* Now figure out what to do with the returned value, if any. */
      if (d->tmp == IRTemp_INVALID)
	  /* No return value.  Nothing to do. */
	  return;
      
      //retty = typeOfIRTemp(env->type_env, d->tmp);

// CAB: ?     if (retty == Ity_I64) {

#if 0
      if (retty == Ity_I32 || retty == Ity_I16 || retty == Ity_I8) {
         /* The returned value is in %eax.  Park it in the register
            associated with tmp. */
         HReg dst = lookupIRTemp(env, d->tmp);
         addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dst) );
         return;
      }
#endif
      break;
   }

   /* --------- EXIT --------- */
   /* conditional exit from BB */
   case Ist_Exit: {
      ARMBranchDest* dst;
      ARMCondCode cc;
      if (stmt->Ist.Exit.dst->tag != Ico_U32)
         vpanic("isel_arm: Ist_Exit: dst is not a 32-bit value");

      // CAB: Where does jumpkind fit in ?
      // stmt->Ist.Exit.jk

      dst = iselIntExpr_BD(env, IRExpr_Const(stmt->Ist.Exit.dst));
      cc  = iselCondCode(env,stmt->Ist.Exit.guard);
      addInstr(env, ARMInstr_Branch(cc, dst));
      return;
   }

   default: break;
   }
  stmt_fail:
   ppIRStmt(stmt);
   vpanic("iselStmt");
}
예제 #24
0
static
void doHelperCall ( ISelEnv* env, 
                    Bool passBBP, 
                    IRExpr* guard, IRCallee* cee, IRExpr** args )
{
#if 0
   ARMCondCode cc;
   HReg        argregs[3];
   HReg        tmpregs[3];
   Bool        danger;
   Int         not_done_yet, n_args, n_arg_ws, stack_limit, 
               i, argreg, argregX;

   /* Marshal args for a call, do the call, and clear the stack.
      Complexities to consider:

      * if passBBP is True, %ebp (the baseblock pointer) is to be
        passed as the first arg.

      * If the callee claims regparmness of 1, 2 or 3, we must pass the
        first 1, 2 or 3 args in registers (EAX, EDX, and ECX
        respectively).  To keep things relatively simple, only args of
        type I32 may be passed as regparms -- just bomb out if anything
        else turns up.  Clearly this depends on the front ends not
        trying to pass any other types as regparms.  
   */

   /* 16 Nov 2004: the regparm handling is complicated by the
      following problem.

      Consider a call two a function with two regparm parameters:
      f(e1,e2).  We need to compute e1 into %eax and e2 into %edx.
      Suppose code is first generated to compute e1 into %eax.  Then,
      code is generated to compute e2 into %edx.  Unfortunately, if
      the latter code sequence uses %eax, it will trash the value of
      e1 computed by the former sequence.  This could happen if (for
      example) e2 itself involved a function call.  In the code below,
      args are evaluated right-to-left, not left-to-right, but the
      principle and the problem are the same.

      One solution is to compute all regparm-bound args into vregs
      first, and once they are all done, move them to the relevant
      real regs.  This always gives correct code, but it also gives
      a bunch of vreg-to-rreg moves which are usually redundant but 
      are hard for the register allocator to get rid of.

      A compromise is to first examine all regparm'd argument 
      expressions.  If they are all so simple that it is clear 
      they will be evaluated without use of any fixed registers,
      use the old compute-directly-to-fixed-target scheme.  If not,
      be safe and use the via-vregs scheme.

      Note this requires being able to examine an expression and
      determine whether or not evaluation of it might use a fixed
      register.  That requires knowledge of how the rest of this
      insn selector works.  Currently just the following 3 are 
      regarded as safe -- hopefully they cover the majority of
      arguments in practice: IRExpr_Tmp IRExpr_Const IRExpr_Get.
   */
   vassert(cee->regparms >= 0 && cee->regparms <= 3);

   n_args = n_arg_ws = 0;
   while (args[n_args]) n_args++;

   not_done_yet = n_args;
   if (passBBP)
      not_done_yet++;

   stack_limit = cee->regparms;
   if (cee->regparms > 0 && passBBP) stack_limit--;

   /* ------ BEGIN marshall all arguments ------ */

   /* Push (R to L) the stack-passed args, [n_args-1 .. stack_limit] */
   for (i = n_args-1; i >= stack_limit; i--) {
      n_arg_ws += pushArg(env, args[i]);
      not_done_yet--;
   }

   /* args [stack_limit-1 .. 0] and possibly %ebp are to be passed in
      registers. */

   if (cee->regparms > 0) {

      /* ------ BEGIN deal with regparms ------ */

      /* deal with regparms, not forgetting %ebp if needed. */
      argregs[0] = hregX86_EAX();
      argregs[1] = hregX86_EDX();
      argregs[2] = hregX86_ECX();
      tmpregs[0] = tmpregs[1] = tmpregs[2] = INVALID_HREG;

      argreg = cee->regparms;

      /* In keeping with big comment above, detect potential danger
         and use the via-vregs scheme if needed. */
      danger = False;
      for (i = stack_limit-1; i >= 0; i--) {
         if (mightRequireFixedRegs(args[i])) {
            danger = True;
            break;
         }
      }

      if (danger) {

         /* Move via temporaries */
         argregX = argreg;
         for (i = stack_limit-1; i >= 0; i--) {

            if (0) {
               vex_printf("x86 host: register param is complex: ");
               ppIRExpr(args[i]);
               vex_printf("\n");
            }

            argreg--;
            vassert(argreg >= 0);
            vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32);
            tmpregs[argreg] = iselIntExpr_R(env, args[i]);
            not_done_yet--;
         }
         for (i = stack_limit-1; i >= 0; i--) {
            argregX--;
            vassert(argregX >= 0);
            addInstr( env, mk_iMOVsd_RR( tmpregs[argregX], argregs[argregX] ) );
         }

      } else {
         /* It's safe to compute all regparm args directly into their
            target registers. */
         for (i = stack_limit-1; i >= 0; i--) {
            argreg--;
            vassert(argreg >= 0);
            vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32);
            addInstr(env, X86Instr_Alu32R(Xalu_MOV, 
                                          iselIntExpr_RMI(env, args[i]),
                                          argregs[argreg]));
            not_done_yet--;
         }

      }

      /* Not forgetting %ebp if needed. */
      if (passBBP) {
         vassert(argreg == 1);
         addInstr(env, mk_iMOVsd_RR( hregX86_EBP(), argregs[0]));
         not_done_yet--;
      }

      /* ------ END deal with regparms ------ */

   } else {

      /* No regparms.  Heave %ebp on the stack if needed. */
      if (passBBP) {
         addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP())));
         n_arg_ws++;
         not_done_yet--;
      }

   }

   vassert(not_done_yet == 0);

   /* ------ END marshall all arguments ------ */

   /* Now we can compute the condition.  We can't do it earlier
      because the argument computations could trash the condition
      codes.  Be a bit clever to handle the common case where the
      guard is 1:Bit. */
   cc = Xcc_ALWAYS;
   if (guard) {
      if (guard->tag == Iex_Const 
          && guard->Iex.Const.con->tag == Ico_U1
          && guard->Iex.Const.con->Ico.U1 == True) {
         /* unconditional -- do nothing */
      } else {
         cc = iselCondCode( env, guard );
      }
   }

   /* call the helper, and get the args off the stack afterwards. */
   callHelperAndClearArgs( env, cc, cee, n_arg_ws );
#endif
}
예제 #25
0
/* Inject IR stmts depending on the data provided in the control
   block iricb. */
void
vex_inject_ir(IRSB *irsb, IREndness endian)
{
   IRExpr *data, *rounding_mode, *opnd1, *opnd2, *opnd3, *opnd4;

   rounding_mode = NULL;
   if (iricb.rounding_mode != NO_ROUNDING_MODE) {
      rounding_mode = mkU32(iricb.rounding_mode);
   }

   switch (iricb.num_operands) {
   case 1:
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
      if (rounding_mode)
         data = binop(iricb.op, rounding_mode, opnd1);
      else
         data = unop(iricb.op, opnd1);
      break;

   case 2:
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
      /* HACK, compiler warning ‘opnd2’ may be used uninitialized */
      opnd2 = opnd1;

      /* immediate_index = 0  immediate value is not used.
       * immediate_index = 2  opnd2 is an immediate value.
       */
      vassert(iricb.immediate_index == 0 || iricb.immediate_index == 2);

      if (iricb.immediate_index == 2) {
         vassert((iricb.t_opnd2 == Ity_I8) || (iricb.t_opnd2 == Ity_I16)
                 || (iricb.t_opnd2 == Ity_I32));

         /* Interpret the memory as an ULong. */
         if (iricb.immediate_type == Ity_I8) {
            opnd2 = mkU8(*((ULong *)iricb.opnd2));
         } else if (iricb.immediate_type == Ity_I16) {
            opnd2 = mkU16(*((ULong *)iricb.opnd2));
         } else if (iricb.immediate_type == Ity_I32) {
            opnd2 = mkU32(*((ULong *)iricb.opnd2));
         }
      } else {
         opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
      }

      if (rounding_mode)
         data = triop(iricb.op, rounding_mode, opnd1, opnd2);
      else
         data = binop(iricb.op, opnd1, opnd2);
      break;

   case 3:
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
      opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
      /* HACK, compiler warning ‘opnd3’ may be used uninitialized */
      opnd3 = opnd2;

      /* immediate_index = 0  immediate value is not used.
       * immediate_index = 3  opnd3 is an immediate value.
       */
      vassert(iricb.immediate_index == 0 || iricb.immediate_index == 3);

      if (iricb.immediate_index == 3) {
         vassert((iricb.t_opnd3 == Ity_I8) || (iricb.t_opnd3 == Ity_I16)
                 || (iricb.t_opnd2 == Ity_I32));

         if (iricb.immediate_type == Ity_I8) {
            opnd3 = mkU8(*((ULong *)iricb.opnd3));
         } else if (iricb.immediate_type == Ity_I16) {
            opnd3 = mkU16(*((ULong *)iricb.opnd3));
         } else if (iricb.immediate_type == Ity_I32) {
            opnd3 = mkU32(*((ULong *)iricb.opnd3));
         }
      } else {
         opnd3 = load(endian, iricb.t_opnd3, iricb.opnd3);
      }
      if (rounding_mode)
         data = qop(iricb.op, rounding_mode, opnd1, opnd2, opnd3);
      else
         data = triop(iricb.op, opnd1, opnd2, opnd3);
      break;

   case 4:
      vassert(rounding_mode == NULL);
      opnd1 = load(endian, iricb.t_opnd1, iricb.opnd1);
      opnd2 = load(endian, iricb.t_opnd2, iricb.opnd2);
      opnd3 = load(endian, iricb.t_opnd3, iricb.opnd3);
      /* HACK, compiler warning ‘opnd4’ may be used uninitialized */
      opnd4 = opnd3;

      /* immediate_index = 0  immediate value is not used.
       * immediate_index = 4  opnd4 is an immediate value.
       */
      vassert(iricb.immediate_index == 0 || iricb.immediate_index == 4);

      if (iricb.immediate_index == 4) {
         vassert((iricb.t_opnd3 == Ity_I8) || (iricb.t_opnd3 == Ity_I16)
                 || (iricb.t_opnd2 == Ity_I32));

         if (iricb.immediate_type == Ity_I8) {
            opnd4 = mkU8(*((ULong *)iricb.opnd4));
         } else if (iricb.immediate_type == Ity_I16) {
            opnd4 = mkU16(*((ULong *)iricb.opnd4));
         } else if (iricb.immediate_type == Ity_I32) {
            opnd4 = mkU32(*((ULong *)iricb.opnd4));
         }
      } else {
         opnd4 = load(endian, iricb.t_opnd4, iricb.opnd4);
      }
      data = qop(iricb.op, opnd1, opnd2, opnd3, opnd4);
      break;

   default:
      vpanic("unsupported operator");
   }

   store(irsb, endian, iricb.result, data);

   if (0) {
      vex_printf("BEGIN inject\n");
      if (iricb.t_result == Ity_I1 || sizeofIRType(iricb.t_result) <= 8) {
         ppIRStmt(irsb->stmts[irsb->stmts_used - 1]);
      } else if (sizeofIRType(iricb.t_result) == 16) {
         ppIRStmt(irsb->stmts[irsb->stmts_used - 2]);
         vex_printf("\n");
         ppIRStmt(irsb->stmts[irsb->stmts_used - 1]);
      }
      vex_printf("\nEND inject\n");
   }
}
예제 #26
0
/* A target-independent register allocator.  Requires various
   functions which it uses to deal abstractly with instructions and
   registers, since it cannot have any target-specific knowledge.

   Returns a new list of instructions, which, as a result of the
   behaviour of mapRegs, will be in-place modifications of the
   original instructions.

   Requires that the incoming code has been generated using
   vreg numbers 0, 1 .. n_vregs-1.  Appearance of a vreg outside
   that range is a checked run-time error.

   Takes an expandable array of pointers to unallocated insns.
   Returns an expandable array of pointers to allocated insns.
*/
HInstrArray* doRegisterAllocation (

   /* Incoming virtual-registerised code. */
   HInstrArray* instrs_in,

   /* An array listing all the real registers the allocator may use,
      in no particular order. */
   HReg* available_real_regs,
   Int   n_available_real_regs,

   /* Return True iff the given insn is a reg-reg move, in which
      case also return the src and dst regs. */
   Bool (*isMove) (HInstr*, HReg*, HReg*),

   /* Get info about register usage in this insn. */
   void (*getRegUsage) (HRegUsage*, HInstr*),

   /* Apply a reg-reg mapping to an insn. */
   void (*mapRegs) (HRegRemap*, HInstr*),

   /* Return an insn to spill/restore a real reg to a spill slot
      byte offset. */
   HInstr* (*genSpill) ( HReg, Int ),
   HInstr* (*genReload) ( HReg, Int ),
   Int     guest_sizeB,

   /* For debug printing only. */
   void (*ppInstr) ( HInstr* ),
   void (*ppReg) ( HReg )
)
{
#  define N_SPILL64S  (LibVEX_N_SPILL_BYTES / 8)

   /* Iterators and temporaries. */
   Int       ii, j, k, m, spillee, k_suboptimal;
   HReg      rreg, vreg, vregS, vregD;
   HRegUsage reg_usage;

   /* Info on vregs and rregs.  Computed once and remains
      unchanged. */
   Int     n_vreg_lrs;
   VRegLR* vreg_lrs; /* [0 .. n_vreg_lrs-1] */

   RRegLR* rreg_lrs;
   Int     rreg_lrs_size;
   Int     rreg_lrs_used;

   /* Used when constructing vreg_lrs (for allocating stack
      slots). */
   Int ss_busy_until_before[N_SPILL64S];

   /* Used when constructing rreg_lrs. */
   Int* rreg_live_after;
   Int* rreg_dead_before;

   /* Running state of the core allocation algorithm. */
   RRegState* state;
   Int        n_state;

   /* The vreg -> rreg map constructed and then applied to each
      instr. */
   HRegRemap remap;

   /* The output array of instructions. */
   HInstrArray* instrs_out;

   vassert(0 == LibVEX_N_SPILL_BYTES % 16);
   vassert(0 == guest_sizeB % 8);

   /* The live range numbers are signed shorts, and so limiting the
      number of insns to 10000 comfortably guards against them
      overflowing 32k. */
   vassert(instrs_in->arr_used <= 10000);

#  define INVALID_INSTRNO (-2)

#  define EMIT_INSTR(_instr)                  \
      do {                                    \
        HInstr* _tmp = (_instr);              \
        if (DEBUG_REGALLOC) {                 \
           vex_printf("**  ");                \
           (*ppInstr)(_tmp);                  \
           vex_printf("\n\n");                \
        }                                     \
        addHInstr ( instrs_out, _tmp );       \
      } while (0)

#   define PRINT_STATE						\
      do {							\
         Int z;							\
         for (z = 0; z < n_state; z++) {			\
            vex_printf("   ");					\
            (*ppReg)(state[z].rreg);				\
            vex_printf("\t  ");					\
            switch (state[z].disp) {				\
               case Free:    vex_printf("Free\n"); break;	\
               case Unavail: vex_printf("Unavail\n"); break;	\
               case Bound:   vex_printf("BoundTo "); 		\
                             (*ppReg)(state[z].vreg);		\
                             vex_printf("\n"); break;		\
            }							\
         }							\
      } while (0)


   /* --------- Stage 0: set up output array. --------- */
   instrs_out = newHInstrArray();

   /* ... and initialise running state. */
   /* n_state is no more than a short name for n_available_real_regs. */
   n_state = n_available_real_regs;
   state = LibVEX_Alloc(n_available_real_regs * sizeof(RRegState));

   for (j = 0; j < n_state; j++) {
      state[j].rreg          = available_real_regs[j];
      state[j].has_hlrs      = False;
      state[j].disp          = Free;
      state[j].vreg          = INVALID_HREG;
      state[j].is_spill_cand = False;
   }

   /* --------- Stage 1: compute vreg live ranges. --------- */
   /* --------- Stage 2: compute rreg live ranges. --------- */

   /* ------ start of SET UP TO COMPUTE VREG LIVE RANGES ------ */

   /* This is relatively simple, because (1) we only seek the complete
      end-to-end live range of each vreg, and are not interested in
      any holes in it, and (2) the vregs are conveniently numbered 0
      .. n_vreg_lrs-1, so we can just dump the results in a
      pre-allocated array. */

   n_vreg_lrs = instrs_in->n_vregs;
   vreg_lrs = NULL;
   if (n_vreg_lrs > 0)
      vreg_lrs = LibVEX_Alloc(sizeof(VRegLR) * n_vreg_lrs);

   for (j = 0; j < n_vreg_lrs; j++) {
      vreg_lrs[j].live_after     = INVALID_INSTRNO;
      vreg_lrs[j].dead_before    = INVALID_INSTRNO;
      vreg_lrs[j].spill_offset   = 0;
      vreg_lrs[j].spill_size     = 0;
      vreg_lrs[j].reg_class      = HRcINVALID;
   }

   /* ------ end of SET UP TO COMPUTE VREG LIVE RANGES ------ */

   /* ------ start of SET UP TO COMPUTE RREG LIVE RANGES ------ */

   /* This is more complex than Stage 1, because we need to compute
      exactly all the live ranges of all the allocatable real regs,
      and we don't know in advance how many there will be. */

   rreg_lrs_used = 0;
   rreg_lrs_size = 4;
   rreg_lrs = LibVEX_Alloc(rreg_lrs_size * sizeof(RRegLR));

   /* We'll need to track live range start/end points seperately for
      each rreg.  Sigh. */
   vassert(n_available_real_regs > 0);
   rreg_live_after  = LibVEX_Alloc(n_available_real_regs * sizeof(Int));
   rreg_dead_before = LibVEX_Alloc(n_available_real_regs * sizeof(Int));

   for (j = 0; j < n_available_real_regs; j++) {
      rreg_live_after[j] =
      rreg_dead_before[j] = INVALID_INSTRNO;
   }

   /* ------ end of SET UP TO COMPUTE RREG LIVE RANGES ------ */

   /* ------ start of ITERATE OVER INSNS ------ */

   for (ii = 0; ii < instrs_in->arr_used; ii++) {

      (*getRegUsage)( &reg_usage, instrs_in->arr[ii] );

#     if 0
      vex_printf("\n%d  stage1: ", ii);
      (*ppInstr)(instrs_in->arr[ii]);
      vex_printf("\n");
      ppHRegUsage(&reg_usage);
#     endif

      /* ------ start of DEAL WITH VREG LIVE RANGES ------ */

      /* for each reg mentioned in the insn ... */
      for (j = 0; j < reg_usage.n_used; j++) {

         vreg = reg_usage.hreg[j];
         /* only interested in virtual registers right now. */
         if (!hregIsVirtual(vreg))
            continue;
         k = hregNumber(vreg);
         if (k < 0 || k >= n_vreg_lrs) {
            vex_printf("\n");
            (*ppInstr)(instrs_in->arr[ii]);
            vex_printf("\n");
            vex_printf("vreg %d, n_vreg_lrs %d\n", k, n_vreg_lrs);
            vpanic("doRegisterAllocation: out-of-range vreg");
         }

         /* Take the opportunity to note its regclass.  We'll need
            that when allocating spill slots. */
         if (vreg_lrs[k].reg_class == HRcINVALID) {
            /* First mention of this vreg. */
            vreg_lrs[k].reg_class = hregClass(vreg);
         } else {
            /* Seen it before, so check for consistency. */
            vassert(vreg_lrs[k].reg_class == hregClass(vreg));
         }

         /* Now consider live ranges. */
         switch (reg_usage.mode[j]) {
            case HRmRead:
               if (vreg_lrs[k].live_after == INVALID_INSTRNO) {
                  vex_printf("\n\nOFFENDING VREG = %d\n", k);
                  vpanic("doRegisterAllocation: "
                         "first event for vreg is Read");
               }
               vreg_lrs[k].dead_before = toShort(ii + 1);
               break;
            case HRmWrite:
               if (vreg_lrs[k].live_after == INVALID_INSTRNO)
                  vreg_lrs[k].live_after = toShort(ii);
               vreg_lrs[k].dead_before = toShort(ii + 1);
               break;
            case HRmModify:
               if (vreg_lrs[k].live_after == INVALID_INSTRNO) {
                  vex_printf("\n\nOFFENDING VREG = %d\n", k);
                  vpanic("doRegisterAllocation: "
                         "first event for vreg is Modify");
               }
               vreg_lrs[k].dead_before = toShort(ii + 1);
               break;
            default:
               vpanic("doRegisterAllocation(1)");
         } /* switch */

      } /* iterate over registers */

      /* ------ end of DEAL WITH VREG LIVE RANGES ------ */

      /* ------ start of DEAL WITH RREG LIVE RANGES ------ */

      /* for each reg mentioned in the insn ... */
      for (j = 0; j < reg_usage.n_used; j++) {

         /* Dummy initialisations of flush_la and flush_db to avoid
            possible bogus uninit-var warnings from gcc. */
         Int  flush_la = INVALID_INSTRNO, flush_db = INVALID_INSTRNO;
         Bool flush;

         rreg = reg_usage.hreg[j];

         /* only interested in real registers right now. */
         if (hregIsVirtual(rreg))
            continue;

         /* Furthermore, we're not interested in this rreg unless it's
            one of the allocatable ones.  For example, it could be a
            stack pointer register, or some other register beyond our
            control, in which case we should just ignore it. */
         for (k = 0; k < n_available_real_regs; k++)
            if (available_real_regs[k] == rreg)
               break;
         if (k == n_available_real_regs)
            continue; /* not found -- ignore. */
         flush = False;
         switch (reg_usage.mode[j]) {
            case HRmWrite:
               flush_la = rreg_live_after[k];
               flush_db = rreg_dead_before[k];
               if (flush_la != INVALID_INSTRNO
                   && flush_db != INVALID_INSTRNO)
                  flush = True;
               rreg_live_after[k]  = ii;
               rreg_dead_before[k] = ii+1;
               break;
            case HRmRead:
               if (rreg_live_after[k] == INVALID_INSTRNO) {
                  vex_printf("\nOFFENDING RREG = ");
                  (*ppReg)(available_real_regs[k]);
                  vex_printf("\n");
                  vex_printf("\nOFFENDING instr = ");
                  (*ppInstr)(instrs_in->arr[ii]);
                  vex_printf("\n");
                  vpanic("doRegisterAllocation: "
                         "first event for rreg is Read");
               }
               rreg_dead_before[k] = ii+1;
               break;
            case HRmModify:
               if (rreg_live_after[k] == INVALID_INSTRNO) {
                  vex_printf("\nOFFENDING RREG = ");
                  (*ppReg)(available_real_regs[k]);
                  vex_printf("\n");
                  vex_printf("\nOFFENDING instr = ");
                  (*ppInstr)(instrs_in->arr[ii]);
                  vex_printf("\n");
                  vpanic("doRegisterAllocation: "
                         "first event for rreg is Modify");
               }
               rreg_dead_before[k] = ii+1;
               break;
            default:
               vpanic("doRegisterAllocation(2)");
         }

         if (flush) {
            vassert(flush_la != INVALID_INSTRNO);
            vassert(flush_db != INVALID_INSTRNO);
            ensureRRLRspace(&rreg_lrs, &rreg_lrs_size, rreg_lrs_used);
            if (0)
               vex_printf("FLUSH 1 (%d,%d)\n", flush_la, flush_db);
            rreg_lrs[rreg_lrs_used].rreg        = rreg;
            rreg_lrs[rreg_lrs_used].live_after  = toShort(flush_la);
            rreg_lrs[rreg_lrs_used].dead_before = toShort(flush_db);
            rreg_lrs_used++;
         }

      } /* iterate over regs in the instr */

      /* ------ end of DEAL WITH RREG LIVE RANGES ------ */

   } /* iterate over insns */

   /* ------ end of ITERATE OVER INSNS ------ */

   /* ------ start of FINALISE RREG LIVE RANGES ------ */

   /* Now finish up any live ranges left over. */
   for (j = 0; j < n_available_real_regs; j++) {

#     if 0
      vex_printf("residual %d:  %d %d\n", j, rreg_live_after[j],
                                             rreg_dead_before[j]);
#     endif
      vassert( (rreg_live_after[j] == INVALID_INSTRNO
               && rreg_dead_before[j] == INVALID_INSTRNO)
              ||
              (rreg_live_after[j] != INVALID_INSTRNO
               && rreg_dead_before[j] != INVALID_INSTRNO)
            );

      if (rreg_live_after[j] == INVALID_INSTRNO)
         continue;

      ensureRRLRspace(&rreg_lrs, &rreg_lrs_size, rreg_lrs_used);
      if (0)
         vex_printf("FLUSH 2 (%d,%d)\n",
                    rreg_live_after[j], rreg_dead_before[j]);
      rreg_lrs[rreg_lrs_used].rreg        = available_real_regs[j];
      rreg_lrs[rreg_lrs_used].live_after  = toShort(rreg_live_after[j]);
      rreg_lrs[rreg_lrs_used].dead_before = toShort(rreg_dead_before[j]);
      rreg_lrs_used++;
   }

   /* Compute summary hints for choosing real regs.  If a real reg is
      involved in a hard live range, record that fact in the fixed
      part of the running state.  Later, when offered a choice between
      rregs, it's better to choose one which is not marked as having
      any HLRs, since ones with HLRs may need to be spilled around
      their HLRs.  Correctness of final assignment is unaffected by
      this mechanism -- it is an optimisation only. */

   for (j = 0; j < rreg_lrs_used; j++) {
      rreg = rreg_lrs[j].rreg;
      vassert(!hregIsVirtual(rreg));
      /* rreg is involved in a HLR.  Record this info in the array, if
         there is space. */
      for (k = 0; k < n_state; k++)
         if (state[k].rreg == rreg)
            break;
      vassert(k < n_state); /* else rreg was not found in state?! */
      state[k].has_hlrs = True;
   }
   if (0) {
      for (j = 0; j < n_state; j++) {
         if (!state[j].has_hlrs)
            continue;
         ppReg(state[j].rreg);
         vex_printf(" hinted\n");
      }
   }

   /* ------ end of FINALISE RREG LIVE RANGES ------ */

#  if DEBUG_REGALLOC
   for (j = 0; j < n_vreg_lrs; j++) {
      vex_printf("vreg %d:  la = %d,  db = %d\n",
                 j, vreg_lrs[j].live_after, vreg_lrs[j].dead_before );
   }
#  endif

#  if DEBUG_REGALLOC
   for (j = 0; j < rreg_lrs_used; j++) {
      (*ppReg)(rreg_lrs[j].rreg);
      vex_printf("      la = %d,  db = %d\n",
                 rreg_lrs[j].live_after, rreg_lrs[j].dead_before );
   }
#  endif

   /* --------- Stage 3: allocate spill slots. --------- */

   /* Each spill slot is 8 bytes long.  For 128-bit vregs
      we have to allocate two spill slots.

      Do a rank-based allocation of vregs to spill slot numbers.  We
      put as few values as possible in spill slows, but nevertheless
      need to have a spill slot available for all vregs, just in case.
   */
   /* max_ss_no = -1; */

   for (j = 0; j < N_SPILL64S; j++)
      ss_busy_until_before[j] = 0;

   for (j = 0; j < n_vreg_lrs; j++) {

      /* True iff this vreg is unused.  In which case we also expect
         that the reg_class field for it has not been set.  */
      if (vreg_lrs[j].live_after == INVALID_INSTRNO) {
         vassert(vreg_lrs[j].reg_class == HRcINVALID);
         continue;
      }

      /* The spill slots are 64 bits in size.  That means, to spill a
         Vec128-class vreg, we'll need to find two adjacent spill
         slots to use.  Note, this special-casing needs to happen for
         all 128-bit sized register classes.  Currently though
         HRcVector is the only such class. */

      if (vreg_lrs[j].reg_class != HRcVec128) {

         /* The ordinary case -- just find a single spill slot. */

         /* Find the lowest-numbered spill slot which is available at
            the start point of this interval, and assign the interval
            to it. */
         for (k = 0; k < N_SPILL64S; k++)
            if (ss_busy_until_before[k] <= vreg_lrs[j].live_after)
               break;
         if (k == N_SPILL64S) {
            vpanic("LibVEX_N_SPILL_BYTES is too low.  "
                   "Increase and recompile.");
         }
         ss_busy_until_before[k] = vreg_lrs[j].dead_before;

      } else {

	/* Find two adjacent free slots in which to spill a 128-bit
           vreg. */

         for (k = 0; k < N_SPILL64S-1; k++)
            if (ss_busy_until_before[k] <= vreg_lrs[j].live_after
                && ss_busy_until_before[k+1] <= vreg_lrs[j].live_after)
               break;
         if (k == N_SPILL64S-1) {
            vpanic("LibVEX_N_SPILL_BYTES is too low.  "
                   "Increase and recompile.");
         }
         ss_busy_until_before[k+0] = vreg_lrs[j].dead_before;
         ss_busy_until_before[k+1] = vreg_lrs[j].dead_before;

      }

      /* This reflects LibVEX's hard-wired knowledge of the baseBlock
         layout: the guest state, then an equal sized area following
         it for shadow state, and then the spill area. */
      vreg_lrs[j].spill_offset = toShort(guest_sizeB * 2 + k * 8);

      /* if (j > max_ss_no) */
      /*    max_ss_no = j; */
   }

#  if 0
   vex_printf("\n\n");
   for (j = 0; j < n_vreg_lrs; j++)
      vex_printf("vreg %d    --> spill offset %d\n",
                 j, vreg_lrs[j].spill_offset);
#  endif

   /* --------- Stage 4: establish rreg preferences --------- */

   /* It may be advantageous to allocating certain vregs to specific
      rregs, as a way of avoiding reg-reg moves later.  Here we
      establish which, if any, rreg each vreg would prefer to be in.
      Note that this constrains the allocator -- ideally we end up
      with as few as possible vregs expressing a preference.

      This is an optimisation: if the .preferred_rreg field is never
      set to anything different from INVALID_HREG, the allocator still
      works. */

   /* 30 Dec 04: removed this mechanism as it does not seem to
      help. */

   /* --------- Stage 5: process instructions --------- */

   /* This is the main loop of the allocator.  First, we need to
      correctly set up our running state, which tracks the status of
      each real register. */

   /* ------ BEGIN: Process each insn in turn. ------ */

   for (ii = 0; ii < instrs_in->arr_used; ii++) {

#     if DEBUG_REGALLOC
      vex_printf("\n====----====---- Insn %d ----====----====\n", ii);
      vex_printf("---- ");
      (*ppInstr)(instrs_in->arr[ii]);
      vex_printf("\n\nInitial state:\n");
      PRINT_STATE;
      vex_printf("\n");
#     endif

      /* ------------ Sanity checks ------------ */

      /* Sanity check 1: all rregs with a hard live range crossing
         this insn must be marked as unavailable in the running
         state. */
      for (j = 0; j < rreg_lrs_used; j++) {
         if (rreg_lrs[j].live_after < ii
             && ii < rreg_lrs[j].dead_before) {
            /* ii is the middle of a hard live range for some real reg.
               Check it's marked as such in the running state. */

#           if 0
            vex_printf("considering la %d .. db %d   reg = ",
                       rreg_lrs[j].live_after,
                       rreg_lrs[j].dead_before);
            (*ppReg)(rreg_lrs[j].rreg);
            vex_printf("\n");
#           endif

            /* find the state entry for this rreg */
            for (k = 0; k < n_state; k++)
               if (state[k].rreg == rreg_lrs[j].rreg)
                  break;

            /* and assert that this rreg is marked as unavailable */
            vassert(state[k].disp == Unavail);
         }
      }

      /* Sanity check 2: conversely, all rregs marked as unavailable in
         the running state must have a corresponding hard live range
         entry in the rreg_lrs array. */
      for (j = 0; j < n_available_real_regs; j++) {
         vassert(state[j].disp == Bound
                 || state[j].disp == Free
                 || state[j].disp == Unavail);
         if (state[j].disp != Unavail)
            continue;
         for (k = 0; k < rreg_lrs_used; k++)
            if (rreg_lrs[k].rreg == state[j].rreg
                && rreg_lrs[k].live_after < ii
                && ii < rreg_lrs[k].dead_before)
               break;
         /* If this vassertion fails, we couldn't find a corresponding
            HLR. */
         vassert(k < rreg_lrs_used);
      }

      /* Sanity check 3: No vreg is bound to more than one rreg. */
      for (j = 0; j < n_state; j++) {
         if (state[j].disp != Bound)
            continue;
         for (k = j+1; k < n_state; k++)
            if (state[k].disp == Bound)
               vassert(state[k].vreg != state[j].vreg);
      }

      /* Sanity check 4: all vreg-rreg bindings must bind registers of
         the same class. */
      for (j = 0; j < n_state; j++) {
         if (state[j].disp != Bound)
            continue;
         vassert(hregClass(state[j].rreg) == hregClass(state[j].vreg));
         vassert( hregIsVirtual(state[j].vreg));
         vassert(!hregIsVirtual(state[j].rreg));
      }

      /* ------------ end of Sanity checks ------------ */

      /* Do various optimisations pertaining to register coalescing
         and preferencing:
            MOV  v <-> v   coalescing (done here).
            MOV  v <-> r   coalescing (not yet, if ever)
      */
      /* If doing a reg-reg move between two vregs, and the src's live
         range ends here and the dst's live range starts here, bind
         the dst to the src's rreg, and that's all. */
      if ( (*isMove)( instrs_in->arr[ii], &vregS, &vregD ) ) {
         if (!hregIsVirtual(vregS)) goto cannot_coalesce;
         if (!hregIsVirtual(vregD)) goto cannot_coalesce;
         /* Check that *isMove is not telling us a bunch of lies ... */
         vassert(hregClass(vregS) == hregClass(vregD));
         k = hregNumber(vregS);
         m = hregNumber(vregD);
         vassert(k >= 0 && k < n_vreg_lrs);
         vassert(m >= 0 && m < n_vreg_lrs);
         if (vreg_lrs[k].dead_before != ii + 1) goto cannot_coalesce;
         if (vreg_lrs[m].live_after != ii) goto cannot_coalesce;
#        if DEBUG_REGALLOC
         vex_printf("COALESCE ");
         (*ppReg)(vregS);
         vex_printf(" -> ");
         (*ppReg)(vregD);
         vex_printf("\n\n");
#        endif
         /* Find the state entry for vregS. */
         for (m = 0; m < n_state; m++)
            if (state[m].disp == Bound && state[m].vreg == vregS)
               break;
         if (m == n_state)
            /* We failed to find a binding for vregS, which means it's
               currently not in a register.  So we can't do the
               coalescing.  Give up. */
            goto cannot_coalesce;

         /* Finally, we can do the coalescing.  It's trivial -- merely
            claim vregS's register for vregD. */
         state[m].vreg = vregD;

         /* Move on to the next insn.  We skip the post-insn stuff for
            fixed registers, since this move should not interact with
            them in any way. */
         continue;
      }
     cannot_coalesce:

      /* ------ Free up rregs bound to dead vregs ------ */

      /* Look for vregs whose live range has just ended, and
	 mark the associated rreg as free. */

      for (j = 0; j < n_state; j++) {
         if (state[j].disp != Bound)
            continue;
         vreg = hregNumber(state[j].vreg);
         vassert(vreg >= 0 && vreg < n_vreg_lrs);
         if (vreg_lrs[vreg].dead_before <= ii) {
            state[j].disp = Free;
            if (DEBUG_REGALLOC) {
               vex_printf("free up ");
               (*ppReg)(state[j].rreg);
               vex_printf("\n");
            }
         }
      }

      /* ------ Pre-instruction actions for fixed rreg uses ------ */

      /* Now we have to deal with rregs which are about to be made
         live by this instruction -- in other words, are entering into
         one of their live ranges.  If any such rreg holds a vreg, we
         will have to free up the rreg.  The simplest solution which
         is correct is to spill the rreg.

         Note we could do better:
         * Could move it into some other free rreg, if one is available

         Simplest way to do this is to iterate over the collection
         of rreg live ranges.
      */
      for (j = 0; j < rreg_lrs_used; j++) {
         if (rreg_lrs[j].live_after == ii) {
            /* rreg_lrs[j].rreg needs to be freed up.  Find
               the associated state entry. */
            /* Note, re rreg_lrs[j].live_after == ii.  Real register
               live ranges are guaranteed to be well-formed in that
               they start with a write to the register -- Stage 2
               rejects any code not satisfying this.  So the correct
               question to ask is whether rreg_lrs[j].live_after ==
               ii, that is, whether the reg becomes live after this
               insn -- rather than before it. */
#           if DEBUG_REGALLOC
            vex_printf("need to free up rreg: ");
            (*ppReg)(rreg_lrs[j].rreg);
            vex_printf("\n\n");
#           endif
            for (k = 0; k < n_state; k++)
               if (state[k].rreg == rreg_lrs[j].rreg)
                  break;
            /* If this fails, we don't have an entry for this rreg.
               Which we should. */
            vassert(k < n_state);
            if (state[k].disp == Bound) {
               /* Yes, there is an associated vreg.  Spill it if it's
                  still live. */
               m = hregNumber(state[k].vreg);
               vassert(m >= 0 && m < n_vreg_lrs);
               if (vreg_lrs[m].dead_before > ii) {
                  vassert(vreg_lrs[m].reg_class != HRcINVALID);
                  EMIT_INSTR( (*genSpill)( state[k].rreg,
                                           vreg_lrs[m].spill_offset ) );
               }
            }
            state[k].disp = Unavail;
            state[k].vreg = INVALID_HREG;
         }
      }

#     if DEBUG_REGALLOC
      vex_printf("After pre-insn actions for fixed regs:\n");
      PRINT_STATE;
      vex_printf("\n");
#     endif


      /* ------ Deal with the current instruction. ------ */

      /* Finally we can begin the processing of this instruction
         itself.  The aim is to free up enough rregs for this insn.
         This may generate spill stores since we may have to evict
         some vregs currently in rregs.  Also generates spill loads.
         We also build up the final vreg->rreg mapping to be applied
         to the insn. */

      (*getRegUsage)( &reg_usage, instrs_in->arr[ii] );

      initHRegRemap(&remap);

      /* for each reg mentioned in the insn ... */
      for (j = 0; j < reg_usage.n_used; j++) {

         vreg = reg_usage.hreg[j];

         /* only interested in virtual registers right now. */
         if (!hregIsVirtual(vreg))
            continue;

#        if 0
         vex_printf("considering "); (*ppReg)(vreg); vex_printf("\n");
#        endif

         /* Now we're trying to find a rreg for "vreg".  First of all,
            if it already has an rreg assigned, we don't need to do
            anything more.  Search the current state to find out. */
         for (k = 0; k < n_state; k++)
            if (state[k].vreg == vreg && state[k].disp == Bound)
               break;
         if (k < n_state) {
            addToHRegRemap(&remap, vreg, state[k].rreg);
            continue;
         }

         /* No luck.  The next thing to do is see if there is a
            currently free rreg available, of the correct class.  If
            so, bag it.  NOTE, we could improve this by selecting an
            rreg for which the next live-range event is as far ahead
            as possible. */
         k_suboptimal = -1;
         for (k = 0; k < n_state; k++) {
            if (state[k].disp != Free
                || hregClass(state[k].rreg) != hregClass(vreg))
               continue;
            if (state[k].has_hlrs) {
               /* Well, at least we can use k_suboptimal if we really
                  have to.  Keep on looking for a better candidate. */
               k_suboptimal = k;
            } else {
               /* Found a preferable reg.  Use it. */
               k_suboptimal = -1;
               break;
            }
         }
         if (k_suboptimal >= 0)
            k = k_suboptimal;

         if (k < n_state) {
            state[k].disp = Bound;
            state[k].vreg = vreg;
            addToHRegRemap(&remap, vreg, state[k].rreg);
            /* Generate a reload if needed. */
            if (reg_usage.mode[j] != HRmWrite) {
               m = hregNumber(vreg);
               vassert(m >= 0 && m < n_vreg_lrs);
               vassert(vreg_lrs[m].reg_class != HRcINVALID);
               EMIT_INSTR( (*genReload)( state[k].rreg,
                                         vreg_lrs[m].spill_offset ) );
            }
            continue;
         }

         /* Well, now we have no option but to spill a vreg.  It's
            important to make a good choice of vreg to spill, and of
            course we need to be careful not to spill a vreg which is
            needed by this insn. */

         /* First, mark in the state, those rregs which are not spill
            candidates, due to holding a vreg mentioned by this
            instruction.  Or being of the wrong class. */
         for (k = 0; k < n_state; k++) {
            state[k].is_spill_cand = False;
            if (state[k].disp != Bound)
               continue;
            if (hregClass(state[k].rreg) != hregClass(vreg))
               continue;
            state[k].is_spill_cand = True;
            for (m = 0; m < reg_usage.n_used; m++) {
               if (state[k].vreg == reg_usage.hreg[m]) {
                  state[k].is_spill_cand = False;
                  break;
               }
            }
         }

         /* We can choose to spill any rreg satisfying
            state[r].is_spill_cand (so to speak).  Choose r so that
            the next use of its associated vreg is as far ahead as
            possible, in the hope that this will minimise the number
            of consequent reloads required. */
         spillee
            = findMostDistantlyMentionedVReg (
                 getRegUsage, instrs_in, ii+1, state, n_state );

         if (spillee == -1) {
            /* Hmmmmm.  There don't appear to be any spill candidates.
               We're hosed. */
            vex_printf("reg_alloc: can't find a register in class: ");
            ppHRegClass(hregClass(vreg));
            vex_printf("\n");
            vpanic("reg_alloc: can't create a free register.");
         }

         /* Right.  So we're going to spill state[spillee]. */
         vassert(spillee >= 0 && spillee < n_state);
         vassert(state[spillee].disp == Bound);
         /* check it's the right class */
         vassert(hregClass(state[spillee].rreg) == hregClass(vreg));
         /* check we're not ejecting the vreg for which we are trying
            to free up a register. */
         vassert(state[spillee].vreg != vreg);

         m = hregNumber(state[spillee].vreg);
         vassert(m >= 0 && m < n_vreg_lrs);

         /* So here's the spill store.  Assert that we're spilling a
            live vreg. */
         vassert(vreg_lrs[m].dead_before > ii);
         vassert(vreg_lrs[m].reg_class != HRcINVALID);
         EMIT_INSTR( (*genSpill)( state[spillee].rreg,
                                  vreg_lrs[m].spill_offset ) );

         /* Update the state to reflect the new assignment for this
            rreg. */
         state[spillee].vreg = vreg;

         /* Now, if this vreg is being read or modified (as opposed to
            written), we have to generate a reload for it. */
         if (reg_usage.mode[j] != HRmWrite) {
            m = hregNumber(vreg);
            vassert(m >= 0 && m < n_vreg_lrs);
            vassert(vreg_lrs[m].reg_class != HRcINVALID);
            EMIT_INSTR( (*genReload)( state[spillee].rreg,
                                      vreg_lrs[m].spill_offset ) );
         }

         /* So after much twisting and turning, we have vreg mapped to
            state[furthest_k].rreg.  Note that in the map. */
         addToHRegRemap(&remap, vreg, state[spillee].rreg);

      } /* iterate over registers in this instruction. */

      /* We've finished clowning around with registers in this instruction.
         Three results:
         - the running state[] has been updated
         - a suitable vreg->rreg mapping for this instruction has been
           constructed
         - spill and reload instructions may have been emitted.

        The final step is to apply the mapping to the instruction,
        and emit that.
      */

      /* NOTE, DESTRUCTIVELY MODIFIES instrs_in->arr[ii]. */
      (*mapRegs)( &remap, instrs_in->arr[ii] );
      EMIT_INSTR( instrs_in->arr[ii] );

#     if DEBUG_REGALLOC
      vex_printf("After dealing with current insn:\n");
      PRINT_STATE;
      vex_printf("\n");
#     endif

      /* ------ Post-instruction actions for fixed rreg uses ------ */

      /* Now we need to check for rregs exiting fixed live ranges
         after this instruction, and if so mark them as free. */
      for (j = 0; j < rreg_lrs_used; j++) {
         if (rreg_lrs[j].dead_before == ii+1) {
            /* rreg_lrs[j].rreg is exiting a hard live range.  Mark
               it as such in the main state array. */
            for (k = 0; k < n_state; k++)
               if (state[k].rreg == rreg_lrs[j].rreg)
                  break;
            /* If this vassertion fails, we don't have an entry for
               this rreg.  Which we should. */
            vassert(k < n_state);
            vassert(state[k].disp == Unavail);
            state[k].disp = Free;
            state[k].vreg = INVALID_HREG;
         }
      }

#     if DEBUG_REGALLOC
      vex_printf("After post-insn actions for fixed regs:\n");
      PRINT_STATE;
      vex_printf("\n");
#     endif

   } /* iterate over insns */

   /* ------ END: Process each insn in turn. ------ */

   /* free(state); */
   /* free(rreg_lrs); */
   /* if (vreg_lrs) free(vreg_lrs); */

   /* Paranoia */
   for (j = 0; j < n_state; j++)
      vassert(state[j].rreg == available_real_regs[j]);

   return instrs_out;

#  undef INVALID_INSTRNO
#  undef EMIT_INSTR
#  undef PRINT_STATE
}