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

📄 isel.c

📁 The Valgrind distribution has multiple tools. The most popular is the memory checking tool (called M
💻 C
📖 第 1 页 / 共 5 页
字号:
   handling of register-parameter args.  This function figures out   whether evaluation of an expression might require use of a fixed   register.  If in doubt return True (safe but suboptimal).*/staticBool mightRequireFixedRegs ( IRExpr* e ){   switch (e->tag) {      case Iex_Tmp: case Iex_Const: case Iex_Get:          return False;      default:         return True;   }}/* Do a complete function call.  guard is a Ity_Bit expression   indicating whether or not the call happens.  If guard==NULL, the   call is unconditional. */staticvoid doHelperCall ( ISelEnv* env,                     Bool passBBP,                     IRExpr* guard, IRCallee* cee, IRExpr** args ){   AMD64CondCode cc;   HReg          argregs[6];   HReg          tmpregs[6];   Bool          go_fast;   Int           n_args, i, argreg;   /* Marshal args for a call and do the call.      If passBBP is True, %rbp (the baseblock pointer) is to be passed      as the first arg.      This function only deals with a tiny set of possibilities, which      cover all helpers in practice.  The restrictions are that only      arguments in registers are supported, hence only 6x64 integer      bits in total can be passed.  In fact the only supported arg      type is I64.      Generating code which is both efficient and correct when      parameters are to be passed in registers is difficult, for the      reasons elaborated in detail in comments attached to      doHelperCall() in priv/host-x86/isel.c.  Here, we use a variant      of the method described in those comments.      The problem is split into two cases: the fast scheme and the      slow scheme.  In the fast scheme, arguments are computed      directly into the target (real) registers.  This is only safe      when we can be sure that computation of each argument will not      trash any real registers set by computation of any other      argument.      In the slow scheme, all args are first computed into vregs, and      once they are all done, they are moved 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.      To decide which scheme to use, all argument expressions are      first examined.  If they are all so simple that it is clear they      will be evaluated without use of any fixed registers, use the      fast scheme, else use the slow scheme.  Note also that only      unconditional calls may use the fast scheme, since having to      compute a condition expression could itself trash real      registers.      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.   */   /* Note that the cee->regparms field is meaningless on AMD64 host      (since there is only one calling convention) and so we always      ignore it. */   n_args = 0;   for (i = 0; args[i]; i++)      n_args++;   if (6 < n_args + (passBBP ? 1 : 0))      vpanic("doHelperCall(AMD64): cannot currently handle > 6 args");   argregs[0] = hregAMD64_RDI();   argregs[1] = hregAMD64_RSI();   argregs[2] = hregAMD64_RDX();   argregs[3] = hregAMD64_RCX();   argregs[4] = hregAMD64_R8();   argregs[5] = hregAMD64_R9();   tmpregs[0] = tmpregs[1] = tmpregs[2] =   tmpregs[3] = tmpregs[4] = tmpregs[5] = INVALID_HREG;   /* First decide which scheme (slow or fast) is to be used.  First      assume the fast scheme, and select slow if any contraindications      (wow) appear. */   go_fast = True;   if (guard) {      if (guard->tag == Iex_Const           && guard->Iex.Const.con->tag == Ico_U1          && guard->Iex.Const.con->Ico.U1 == True) {         /* unconditional */      } else {         /* Not manifestly unconditional -- be conservative. */         go_fast = False;      }   }   if (go_fast) {      for (i = 0; i < n_args; i++) {         if (mightRequireFixedRegs(args[i])) {            go_fast = False;            break;         }      }   }   /* At this point the scheme to use has been established.  Generate      code to get the arg values into the argument rregs. */   if (go_fast) {      /* FAST SCHEME */      argreg = 0;      if (passBBP) {         addInstr(env, mk_iMOVsd_RR( hregAMD64_RBP(), argregs[argreg]));         argreg++;      }      for (i = 0; i < n_args; i++) {         vassert(argreg < 6);         vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I64);         addInstr(env, AMD64Instr_Alu64R(                          Aalu_MOV,                           iselIntExpr_RMI(env, args[i]),                          argregs[argreg]                       )                 );         argreg++;      }      /* Fast scheme only applies for unconditional calls.  Hence: */      cc = Acc_ALWAYS;   } else {      /* SLOW SCHEME; move via temporaries */      argreg = 0;      if (passBBP) {         /* This is pretty stupid; better to move directly to rdi            after the rest of the args are done. */         tmpregs[argreg] = newVRegI(env);         addInstr(env, mk_iMOVsd_RR( hregAMD64_RBP(), tmpregs[argreg]));         argreg++;      }      for (i = 0; i < n_args; i++) {         vassert(argreg < 6);         vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I64);         tmpregs[argreg] = iselIntExpr_R(env, args[i]);         argreg++;      }      /* 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 = Acc_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 );         }      }      /* Move the args to their final destinations. */      for (i = 0; i < argreg; i++) {         /* None of these insns, including any spill code that might            be generated, may alter the condition codes. */         addInstr( env, mk_iMOVsd_RR( tmpregs[i], argregs[i] ) );      }   }   /* Finally, the call itself. */   addInstr(env, AMD64Instr_Call(                     cc,                     Ptr_to_ULong(cee->addr),                     n_args + (passBBP ? 1 : 0)                  )   );}/* Given a guest-state array descriptor, an index expression and a   bias, generate an AMD64AMode holding the relevant guest state   offset. */staticAMD64AMode* genGuestArrayOffset ( ISelEnv* env, IRArray* descr,                                   IRExpr* off, Int bias ){   HReg tmp, roff;   Int  elemSz = sizeofIRType(descr->elemTy);   Int  nElems = descr->nElems;   /* Throw out any cases not generated by an amd64 front end.  In      theory there might be a day where we need to handle them -- if      we ever run non-amd64-guest on amd64 host. */   if (nElems != 8 || (elemSz != 1 && elemSz != 8))      vpanic("genGuestArrayOffset(amd64 host)");   /* Compute off into a reg, %off.  Then return:         movq %off, %tmp         addq $bias, %tmp  (if bias != 0)         andq %tmp, 7         ... base(%rbp, %tmp, shift) ...   */   tmp  = newVRegI(env);   roff = iselIntExpr_R(env, off);   addInstr(env, mk_iMOVsd_RR(roff, tmp));   if (bias != 0) {      /* Make sure the bias is sane, in the sense that there are         no significant bits above bit 30 in it. */      vassert(-10000 < bias && bias < 10000);      addInstr(env,                AMD64Instr_Alu64R(Aalu_ADD, AMD64RMI_Imm(bias), tmp));   }   addInstr(env,             AMD64Instr_Alu64R(Aalu_AND, AMD64RMI_Imm(7), tmp));   vassert(elemSz == 1 || elemSz == 8);   return      AMD64AMode_IRRS( descr->base, hregAMD64_RBP(), tmp,                                    elemSz==8 ? 3 : 0);}/* Set the SSE unit's rounding mode to default (%mxcsr = 0x1F80) */staticvoid set_SSE_rounding_default ( ISelEnv* env ){   /* pushq $DEFAULT_MXCSR       ldmxcsr 0(%rsp)      addq $8, %rsp   */   AMD64AMode* zero_rsp = AMD64AMode_IR(0, hregAMD64_RSP());   addInstr(env, AMD64Instr_Push(AMD64RMI_Imm(DEFAULT_MXCSR)));   addInstr(env, AMD64Instr_LdMXCSR(zero_rsp));   add_to_rsp(env, 8);}/* Mess with the FPU's rounding mode: set to the default rounding mode   (DEFAULT_FPUCW). */static void set_FPU_rounding_default ( ISelEnv* env ){   /* movq $DEFAULT_FPUCW, -8(%rsp)      fldcw -8(%esp)   */   AMD64AMode* m8_rsp = AMD64AMode_IR(-8, hregAMD64_RSP());   addInstr(env, AMD64Instr_Alu64M(                    Aalu_MOV, AMD64RI_Imm(DEFAULT_FPUCW), m8_rsp));   addInstr(env, AMD64Instr_A87LdCW(m8_rsp));}/* Mess with the SSE unit'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 SSE machinery to   have the same rounding.*/staticvoid set_SSE_rounding_mode ( ISelEnv* env, IRExpr* mode ){   /* Note: this sequence only makes sense because DEFAULT_MXCSR has      both rounding bits == 0.  If that wasn't the case, we couldn't      create a new rounding field simply by ORing the new value into      place. */   /* movq $3, %reg      andq [[mode]], %reg  -- shouldn't be needed; paranoia      shlq $13, %reg      orq $DEFAULT_MXCSR, %reg      pushq %reg      ldmxcsr 0(%esp)      addq $8, %rsp   */         HReg        reg      = newVRegI(env);   AMD64AMode* zero_rsp = AMD64AMode_IR(0, hregAMD64_RSP());   addInstr(env, AMD64Instr_Alu64R(Aalu_MOV, AMD64RMI_Imm(3), reg));   addInstr(env, AMD64Instr_Alu64R(Aalu_AND,                                   iselIntExpr_RMI(env, mode), reg));   addInstr(env, AMD64Instr_Sh64(Ash_SHL, 13, reg));   addInstr(env, AMD64Instr_Alu64R(                    Aalu_OR, AMD64RMI_Imm(DEFAULT_MXCSR), reg));   addInstr(env, AMD64Instr_Push(AMD64RMI_Reg(reg)));   addInstr(env, AMD64Instr_LdMXCSR(zero_rsp));   add_to_rsp(env, 8);}/* 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);   AMD64AMode* m8_rsp = AMD64AMode_IR(-8, hregAMD64_RSP());   /* movq  %rrm, %rrm2      andq  $3, %rrm2   -- shouldn't be needed; paranoia      shlq  $10, %rrm2      orq   $DEFAULT_FPUCW, %rrm2      movq  %rrm2, -8(%rsp)      fldcw -8(%esp)   */   addInstr(env, mk_iMOVsd_RR(rrm, rrm2));   addInstr(env, AMD64Instr_Alu64R(Aalu_AND, AMD64RMI_Imm(3), rrm2));   addInstr(env, AMD64Instr_Sh64(Ash_SHL, 10, rrm2));   addInstr(env, AMD64Instr_Alu64R(Aalu_OR,                                    AMD64RMI_Imm(DEFAULT_FPUCW), rrm2));   addInstr(env, AMD64Instr_Alu64M(Aalu_MOV,                                    AMD64RI_Reg(rrm2), m8_rsp));   addInstr(env, AMD64Instr_A87LdCW(m8_rsp));}/* Generate all-zeroes into a new vector register.*/static HReg generate_zeroes_V128 ( ISelEnv* env ){   HReg dst = newVRegV(env);   addInstr(env, AMD64Instr_SseReRg(Asse_XOR, dst, dst));   return dst;}/* Generate all-ones into a new vector register.*/static HReg generate_ones_V128 ( ISelEnv* env ){   HReg dst = newVRegV(env);   addInstr(env, AMD64Instr_SseReRg(Asse_CMPEQ32, dst, dst));   return dst;}/* Generate !src into a new vector register.  Amazing that there isn't   a less crappy way to do this.*/static HReg do_sse_NotV128 ( ISelEnv* env, HReg src ){

⌨️ 快捷键说明

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