⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 isel.c

📁 The Valgrind distribution has multiple tools. The most popular is the memory checking tool (called M
💻 C
📖 第 1 页 / 共 5 页
字号:
   /* 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 );}/* Given a guest-state array descriptor, an index expression and a   bias, generate an X86AMode holding the relevant guest state   offset. */staticX86AMode* genGuestArrayOffset ( ISelEnv* env, IRArray* descr,                                 IRExpr* off, Int bias ){   HReg tmp, roff;   Int  elemSz = sizeofIRType(descr->elemTy);   Int  nElems = descr->nElems;   Int  shift  = 0;   /* 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)       vpanic("genGuestArrayOffset(x86 host)(1)");   switch (elemSz) {      case 1:  shift = 0; break;      case 4:  shift = 2; break;      case 8:  shift = 3; break;      default: vpanic("genGuestArrayOffset(x86 host)(2)");   }   /* 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) {      addInstr(env,                X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(bias), tmp));   }   addInstr(env,             X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(7), tmp));   return      X86AMode_IRRS( descr->base, hregX86_EBP(), tmp, shift );}/* Mess with the FPU's rounding mode: set to the default rounding mode   (DEFAULT_FPUCW). */static void set_FPU_rounding_default ( ISelEnv* env ){   /* pushl $DEFAULT_FPUCW      fldcw 0(%esp)      addl $4, %esp    */   X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());   addInstr(env, X86Instr_Push(X86RMI_Imm(DEFAULT_FPUCW)));   addInstr(env, X86Instr_FpLdCW(zero_esp));   add_to_esp(env, 4);}/* Mess with the FPU's rounding mode: 'mode' is an I32-typed   expression denoting a value in the range 0 .. 3, indicating a round   mode encoded as per type IRRoundingMode.  Set the x87 FPU to have   the same rounding.*/staticvoid set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode ){   HReg rrm  = iselIntExpr_R(env, mode);   HReg rrm2 = newVRegI(env);   X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());   /* movl  %rrm, %rrm2      andl  $3, %rrm2   -- shouldn't be needed; paranoia      shll  $10, %rrm2      orl   $DEFAULT_FPUCW, %rrm2      pushl %rrm2      fldcw 0(%esp)      addl  $4, %esp   */   addInstr(env, mk_iMOVsd_RR(rrm, rrm2));   addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(3), rrm2));   addInstr(env, X86Instr_Sh32(Xsh_SHL, 10, rrm2));   addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Imm(DEFAULT_FPUCW), rrm2));   addInstr(env, X86Instr_Push(X86RMI_Reg(rrm2)));   addInstr(env, X86Instr_FpLdCW(zero_esp));   add_to_esp(env, 4);}/* Generate !src into a new vector register, and be sure that the code   is SSE1 compatible.  Amazing that Intel doesn't offer a less crappy   way to do this. */static HReg do_sse_Not128 ( ISelEnv* env, HReg src ){   HReg dst = newVRegV(env);   /* Set dst to zero.  If dst contains a NaN then all hell might      break loose after the comparison.  So, first zero it. */   addInstr(env, X86Instr_SseReRg(Xsse_XOR, dst, dst));   /* And now make it all 1s ... */   addInstr(env, X86Instr_Sse32Fx4(Xsse_CMPEQF, dst, dst));   /* Finally, xor 'src' into it. */   addInstr(env, X86Instr_SseReRg(Xsse_XOR, src, dst));   /* Doesn't that just totally suck? */   return dst;}/* Round an x87 FPU value to 53-bit-mantissa precision, to be used   after most non-simple FPU operations (simple = +, -, *, / and   sqrt).   This could be done a lot more efficiently if needed, by loading   zero and adding it to the value to be rounded (fldz ; faddp?).*/static void roundToF64 ( ISelEnv* env, HReg reg ){   X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());   sub_from_esp(env, 8);   addInstr(env, X86Instr_FpLdSt(False/*store*/, 8, reg, zero_esp));   addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, reg, zero_esp));   add_to_esp(env, 8);}/*---------------------------------------------------------*//*--- ISEL: Integer expressions (32/16/8 bit)           ---*//*---------------------------------------------------------*//* Select insns for an integer-typed expression, and add them to the   code list.  Return a reg holding the result.  This reg will be a   virtual register.  THE RETURNED REG MUST NOT BE MODIFIED.  If you   want to modify it, ask for a new vreg, copy it in there, and modify   the copy.  The register allocator will do its best to map both   vregs to the same real register, so the copies will often disappear   later in the game.   This should handle expressions of 32, 16 and 8-bit type.  All   results are returned in a 32-bit register.  For 16- and 8-bit   expressions, the upper 16/24 bits are arbitrary, so you should mask   or sign extend partial values if necessary.*/static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e ){   HReg r = iselIntExpr_R_wrk(env, e);   /* sanity checks ... */#  if 0   vex_printf("\n"); ppIRExpr(e); vex_printf("\n");#  endif   vassert(hregClass(r) == HRcInt32);   vassert(hregIsVirtual(r));   return r;}/* DO NOT CALL THIS DIRECTLY ! */static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ){   MatchInfo mi;   DECLARE_PATTERN(p_32to1_then_1Uto8);   IRType ty = typeOfIRExpr(env->type_env,e);   vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);   switch (e->tag) {   /* --------- TEMP --------- */   case Iex_Tmp: {      return lookupIRTemp(env, e->Iex.Tmp.tmp);   }   /* --------- LOAD --------- */   case Iex_Load: {      HReg dst = newVRegI(env);      X86AMode* amode = iselIntExpr_AMode ( env, e->Iex.Load.addr );      if (e->Iex.Load.end != Iend_LE)         goto irreducible;      if (ty == Ity_I32) {         addInstr(env, X86Instr_Alu32R(Xalu_MOV,                                       X86RMI_Mem(amode), dst) );         return dst;      }      if (ty == Ity_I16) {         addInstr(env, X86Instr_LoadEX(2,False,amode,dst));         return dst;      }      if (ty == Ity_I8) {         addInstr(env, X86Instr_LoadEX(1,False,amode,dst));         return dst;      }      break;   }   /* --------- TERNARY OP --------- */   case Iex_Triop: {      /* C3210 flags following FPU partial remainder (fprem), both         IEEE compliant (PREM1) and non-IEEE compliant (PREM). */      if (e->Iex.Triop.op == Iop_PRemC3210F64          || e->Iex.Triop.op == Iop_PRem1C3210F64) {         HReg junk = newVRegF(env);         HReg dst  = newVRegI(env);         HReg srcL = iselDblExpr(env, e->Iex.Triop.arg2);         HReg srcR = iselDblExpr(env, e->Iex.Triop.arg3);         /* XXXROUNDINGFIXME */         /* set roundingmode here */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -