Example #1
0
//Save Return address
void MipsCode::SaveContext() {
	addInstr(MIPSType::sw, $fp, "0", $sp);
	addInstr(MIPSType::move, $fp, $sp);
	addInstr(MIPSType::addi, $sp, $sp, "4");
	addInstr(MIPSType::sw, $ra, "0", $sp);
	addInstr(MIPSType::addi, $sp, $sp, "4");
}
Example #2
0
//Format: ARRASS dst,src1,src2
// src1[src2] = dst
void MipsCode::ArrAssToMips(MiddleInstr* middle) {
	SignaryItem* target = middle->desAddr;
	SignaryItem* src1 = middle->srcAddr1;
	SignaryItem* src2 = middle->srcAddr2;
	VarToReg($t0, src2);
	addInstr(MIPSType::li, $t1,"4");
	addInstr(MIPSType::mult, $t0, $t0, $t1);
	VarToReg($t2, src1);
	addInstr(MIPSType::add, $t0, $t0, $t2);
	VarToReg($t1, target);
	addInstr(MIPSType::sw, $t1, "0", $t0);
}
Example #3
0
void MipsCode::VarToReg(string _$i, SignaryItem* _var) {
	SignaryItem* tmp = cur_sig->querySignary(_var->name);
	if (tmp == NULL)
	{
		//sw $t0,0($t1)
		//sw $t0,4($fp)
		addInstr(MIPSType::lw, _$i, tostring(_var->offset), $global_fp);
	}
	else {
		addInstr(MIPSType::lw, _$i, tostring(_var->offset), $fp);
	}
}
Example #4
0
 void createAndAddBlockWithLabel(
         std::vector<std::string> directives,
         std::string label = "") {
     auto block = createBlockWithLabel(label);
     for (auto directive: directives)
         block.addInstr(directive);
     addBlock(block);
 }
Example #5
0
static void sub_from_sp ( ISelEnv* env, Int n )
{
    HReg tmp;
    ARMImm12A imm12a;
    vassert(n > 0 && n < 256 && (n%4) == 0);

    if ( mk_ARMImm12A( (UInt)n, &imm12a ) ) {
	addInstr(env, ARMInstr_DPInstr2(ARMalu_SUB,
					GET_SP_REG(), GET_SP_REG(),
					ARMAMode1_I12A( imm12a )));
    } else {
        tmp  = newVRegI(env);
        addInstr(env, ARMInstr_Literal( tmp, (UInt)n ));
	addInstr(env, ARMInstr_DPInstr2(ARMalu_SUB,
					GET_SP_REG(), GET_SP_REG(),
					ARMAMode1_ShlI( tmp, 0 )));
    }    
}
Example #6
0
//Format: BXX dst,src1,src2
// if src1 xx src2 goto dst
// src1, src2 : variable
// dst : label
void MipsCode::BranchToMips(MiddleInstr* middle) {
	SignaryItem* target = middle->desAddr;
	SignaryItem* src1 = middle->srcAddr1;
	SignaryItem* src2 = middle->srcAddr2;
	VarToReg($t0, src1);
	VarToReg($t1, src2);
	if (middle->type == MIType::BEQ) {
		addInstr(MIPSType::beq, target->name, $t0, $t1);
	}
	else if (middle->type == MIType::BNE) {
		addInstr(MIPSType::bne, target->name, $t0, $t1);
	}
	else if (middle->type == MIType::BLE) {
		addInstr(MIPSType::ble, target->name, $t0, $t1);
	}
	else if (middle->type == MIType::BLS) {
		addInstr(MIPSType::blt, target->name, $t0, $t1);
	}
	else if (middle->type == MIType::BGE) {
		addInstr(MIPSType::bge, target->name, $t0, $t1);
	}
	else if (middle->type == MIType::BGR) {
		addInstr(MIPSType::bgt, target->name, $t0, $t1);
	}

}
Example #7
0
static Int pushArg ( ISelEnv* env, IRExpr* arg )
{
    IRType arg_ty = typeOfIRExpr(env->type_env, arg);
    if (arg_ty == Ity_I32) {
	
	// CAB: This right?
	addInstr(env, ARMInstr_StoreW( GET_SP_REG(), iselIntExpr_AMode2(env, arg) ) );
	return 1;
    }

#if 0 
   else 
   if (arg_ty == Ity_I64) {
      HReg rHi, rLo;
      iselInt64Expr(&rHi, &rLo, env, arg);
      addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
      addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
      return 2;
   }
#endif
   ppIRExpr(arg);
   vpanic("pushArg(arm): can't handle arg of this type");
}
Example #8
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) );
}
Example #9
0
static
ARMAMode2* genGuestArrayOffset ( ISelEnv* env, IRRegArray* descr, 
				 IRExpr* off, Int bias )
{
   HReg tmp, tmp2, roff;
   Int  elemSz = sizeofIRType(descr->elemTy);
   Int  nElems = descr->nElems;
   ARMImm12A imm12a;

   /* throw out any cases not generated by an x86 front end.  In
      theory there might be a day where we need to handle them -- if
      we ever run non-x86-guest on x86 host. */

   if (nElems != 8 || (elemSz != 1 && elemSz != 8))
      vpanic("genGuestArrayOffset(arm host)");

   /* Compute off into a reg, %off.  Then return:

         movl %off, %tmp
         addl $bias, %tmp  (if bias != 0)
         andl %tmp, 7
         ... base(%ebp, %tmp, shift) ...
   */
   tmp  = newVRegI(env);
   roff = iselIntExpr_R(env, off);
   addInstr(env, mk_iMOVsd_RR(roff, tmp));
   if (bias != 0) {
       if ( mk_ARMImm12A( (UInt)bias, &imm12a ) ) {
	   addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD, tmp, tmp,
					   ARMAMode1_I12A( imm12a )));
       } else {
	   HReg tmp3 = newVRegI(env);
	   addInstr(env, ARMInstr_Literal( tmp, (UInt)bias ));
	   addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD, tmp, tmp,
					   ARMAMode1_ShlI( tmp3, 0 )));
       }
   }

   mk_ARMImm12A( (UInt)7, &imm12a );
   addInstr(env, ARMInstr_DPInstr2(ARMalu_AND, tmp, tmp,
				   ARMAMode1_I12A( imm12a )));
   vassert(elemSz == 1 || elemSz == 8);



// CAB: This anywhere near correct?

// X86AMode_IRRS: Immediate + Reg1 + (Reg2 << Shift)
// return X86AMode_IRRS( descr->base, hregX86_EBP(), tmp, elemSz==8 ? 3 : 0);

   tmp2 = newVRegI(env);  // tmp2 = GET_BP_REG + (tmp << 3|0)
   addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD, tmp2, GET_BP_REG(),
				   ARMAMode1_ShlI(tmp, elemSz==8 ? 3 : 0)));
   return ARMAMode2_RI( tmp2, descr->base );
}
Example #10
0
static 
void callHelperAndClearArgs ( ISelEnv* env, ARMCondCode cc, 
                              IRCallee* cee, Int n_arg_ws )
{
   /* Complication.  Need to decide which reg to use as the fn address
      pointer, in a way that doesn't trash regparm-passed
      parameters. */
   vassert(sizeof(void*) == 4);

// CAB: cee->regparms ?

//   addInstr(env, X86Instr_Call( cc, (UInt)cee->addr, cee->regparms));
   ARMBranchDest* dst = ARMBranchDest_Imm( (UInt)cee->addr );
   addInstr(env, ARMInstr_BranchL(cc, dst));

   if (n_arg_ws > 0)
      add_to_sp(env, 4*n_arg_ws);
}
Example #11
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");
}
Example #12
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
}
Example #13
0
//Restore Return address
void MipsCode::RestoreContext() {
	addInstr(MIPSType::lw, $ra, "4", $fp);
	addInstr(MIPSType::move, $sp, $fp);
	addInstr(MIPSType::lw, $fp, "0", $fp);
}
Example #14
0
//Format: JUMP label
void MipsCode::JumpToMips(MiddleInstr* middle) {
	addInstr(MIPSType::j, middle->desAddr->name);
}
Example #15
0
//Format: SETL label
void MipsCode::SetLabelToMips(MiddleInstr* middle) {
	addInstr(MIPSType::label, middle->desAddr->name);
}