📄 isel.c
字号:
/*---------------------------------------------------------------*//*--- ---*//*--- This file (host-x86/isel.c) is ---*//*--- Copyright (C) OpenWorks LLP. All rights reserved. ---*//*--- ---*//*---------------------------------------------------------------*//* This file is part of LibVEX, a library for dynamic binary instrumentation and translation. Copyright (C) 2004-2006 OpenWorks LLP. All rights reserved. This library is made available under a dual licensing scheme. If you link LibVEX against other code all of which is itself licensed under the GNU General Public License, version 2 dated June 1991 ("GPL v2"), then you may use LibVEX under the terms of the GPL v2, as appearing in the file LICENSE.GPL. If the file LICENSE.GPL is missing, you can obtain a copy of the GPL v2 from the Free Software Foundation Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. For any other uses of LibVEX, you must first obtain a commercial license from OpenWorks LLP. Please contact info@open-works.co.uk for information about commercial licensing. This software is provided by OpenWorks LLP "as is" and any express or implied warranties, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose are disclaimed. In no event shall OpenWorks LLP be liable for any direct, indirect, incidental, special, exemplary, or consequential damages (including, but not limited to, procurement of substitute goods or services; loss of use, data, or profits; or business interruption) however caused and on any theory of liability, whether in contract, strict liability, or tort (including negligence or otherwise) arising in any way out of the use of this software, even if advised of the possibility of such damage. Neither the names of the U.S. Department of Energy nor the University of California nor the names of its contributors may be used to endorse or promote products derived from this software without prior written permission.*/#include "libvex_basictypes.h"#include "libvex_ir.h"#include "libvex.h"#include "ir/irmatch.h"#include "main/vex_util.h"#include "main/vex_globals.h"#include "host-generic/h_generic_regs.h"#include "host-generic/h_generic_simd64.h"#include "host-x86/hdefs.h"/* TODO 21 Apr 2005: -- (Really an assembler issue) don't emit CMov32 as a cmov insn, since that's expensive on P4 and conditional branch is cheaper if (as we expect) the condition is highly predictable -- preserve xmm registers across function calls (by declaring them as trashed by call insns) -- preserve x87 ST stack discipline across function calls. Sigh. -- Check doHelperCall: if a call is conditional, we cannot safely compute any regparm args directly to registers. Hence, the fast-regparm marshalling should be restricted to unconditional calls only.*//*---------------------------------------------------------*//*--- x87 control word stuff ---*//*---------------------------------------------------------*//* Vex-generated code expects to run with the FPU set as follows: all exceptions masked, round-to-nearest, precision = 53 bits. This corresponds to a FPU control word value of 0x027F. Similarly the SSE control word (%mxcsr) should be 0x1F80. %fpucw and %mxcsr should have these values on entry to Vex-generated code, and should those values should be unchanged at exit.*/#define DEFAULT_FPUCW 0x027F/* debugging only, do not use *//* define DEFAULT_FPUCW 0x037F *//*---------------------------------------------------------*//*--- misc helpers ---*//*---------------------------------------------------------*//* These are duplicated in guest-x86/toIR.c */static IRExpr* unop ( IROp op, IRExpr* a ){ return IRExpr_Unop(op, a);}static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 ){ return IRExpr_Binop(op, a1, a2);}static IRExpr* bind ( Int binder ){ return IRExpr_Binder(binder);}/*---------------------------------------------------------*//*--- ISelEnv ---*//*---------------------------------------------------------*//* This carries around: - A mapping from IRTemp to IRType, giving the type of any IRTemp we might encounter. This is computed before insn selection starts, and does not change. - A mapping from IRTemp to HReg. This tells the insn selector which virtual register(s) are associated with each IRTemp temporary. This is computed before insn selection starts, and does not change. We expect this mapping to map precisely the same set of IRTemps as the type mapping does. - vregmap holds the primary register for the IRTemp. - vregmapHI is only used for 64-bit integer-typed IRTemps. It holds the identity of a second 32-bit virtual HReg, which holds the high half of the value. - The code array, that is, the insns selected so far. - A counter, for generating new virtual registers. - The host subarchitecture we are selecting insns for. This is set at the start and does not change. Note, this is all host-independent. */typedef struct { IRTypeEnv* type_env; HReg* vregmap; HReg* vregmapHI; Int n_vregmap; HInstrArray* code; Int vreg_ctr; UInt hwcaps; } ISelEnv;static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp ){ vassert(tmp >= 0); vassert(tmp < env->n_vregmap); return env->vregmap[tmp];}static void lookupIRTemp64 ( HReg* vrHI, HReg* vrLO, ISelEnv* env, IRTemp tmp ){ vassert(tmp >= 0); vassert(tmp < env->n_vregmap); vassert(env->vregmapHI[tmp] != INVALID_HREG); *vrLO = env->vregmap[tmp]; *vrHI = env->vregmapHI[tmp];}static void addInstr ( ISelEnv* env, X86Instr* instr ){ addHInstr(env->code, instr); if (vex_traceflags & VEX_TRACE_VCODE) { ppX86Instr(instr, False); vex_printf("\n"); }}static HReg newVRegI ( ISelEnv* env ){ HReg reg = mkHReg(env->vreg_ctr, HRcInt32, True/*virtual reg*/); env->vreg_ctr++; return reg;}static HReg newVRegF ( ISelEnv* env ){ HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True/*virtual reg*/); env->vreg_ctr++; return reg;}static HReg newVRegV ( ISelEnv* env ){ HReg reg = mkHReg(env->vreg_ctr, HRcVec128, True/*virtual reg*/); env->vreg_ctr++; return reg;}/*---------------------------------------------------------*//*--- ISEL: Forward declarations ---*//*---------------------------------------------------------*//* These are organised as iselXXX and iselXXX_wrk pairs. The iselXXX_wrk do the real work, but are not to be called directly. For each XXX, iselXXX calls its iselXXX_wrk counterpart, then checks that all returned registers are virtual. You should not call the _wrk version directly.*/static X86RMI* iselIntExpr_RMI_wrk ( ISelEnv* env, IRExpr* e );static X86RMI* iselIntExpr_RMI ( ISelEnv* env, IRExpr* e );static X86RI* iselIntExpr_RI_wrk ( ISelEnv* env, IRExpr* e );static X86RI* iselIntExpr_RI ( ISelEnv* env, IRExpr* e );static X86RM* iselIntExpr_RM_wrk ( ISelEnv* env, IRExpr* e );static X86RM* iselIntExpr_RM ( ISelEnv* env, IRExpr* e );static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e );static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e );static X86AMode* iselIntExpr_AMode_wrk ( ISelEnv* env, IRExpr* e );static X86AMode* iselIntExpr_AMode ( ISelEnv* env, IRExpr* e );static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e );static void iselInt64Expr ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e );static X86CondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e );static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e );static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e );static HReg iselDblExpr ( ISelEnv* env, IRExpr* e );static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e );static HReg iselFltExpr ( ISelEnv* env, IRExpr* e );static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e );static HReg iselVecExpr ( ISelEnv* env, IRExpr* e );/*---------------------------------------------------------*//*--- ISEL: Misc helpers ---*//*---------------------------------------------------------*//* Make a int reg-reg move. */static X86Instr* mk_iMOVsd_RR ( HReg src, HReg dst ){ vassert(hregClass(src) == HRcInt32); vassert(hregClass(dst) == HRcInt32); return X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(src), dst);}/* Make a vector reg-reg move. */static X86Instr* mk_vMOVsd_RR ( HReg src, HReg dst ){ vassert(hregClass(src) == HRcVec128); vassert(hregClass(dst) == HRcVec128); return X86Instr_SseReRg(Xsse_MOV, src, dst);}/* Advance/retreat %esp by n. */static void add_to_esp ( ISelEnv* env, Int n ){ vassert(n > 0 && n < 256 && (n%4) == 0); addInstr(env, X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(n), hregX86_ESP()));}static void sub_from_esp ( ISelEnv* env, Int n ){ vassert(n > 0 && n < 256 && (n%4) == 0); addInstr(env, X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(n), hregX86_ESP()));}/* Given an amode, return one which references 4 bytes further along. */static X86AMode* advance4 ( X86AMode* am ){ X86AMode* am4 = dopyX86AMode(am); switch (am4->tag) { case Xam_IRRS: am4->Xam.IRRS.imm += 4; break; case Xam_IR: am4->Xam.IR.imm += 4; break; default: vpanic("advance4(x86,host)"); } return am4;}/* Push an arg onto the host stack, in preparation for a call to a helper function of some kind. Returns the number of 32-bit words pushed. */static Int pushArg ( ISelEnv* env, IRExpr* arg ){ IRType arg_ty = typeOfIRExpr(env->type_env, arg); if (arg_ty == Ity_I32) { addInstr(env, X86Instr_Push(iselIntExpr_RMI(env, arg))); return 1; } 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; } ppIRExpr(arg); vpanic("pushArg(x86): can't handle arg of this type");}/* Complete the call to a helper function, by calling the helper and clearing the args off the stack. */static void callHelperAndClearArgs ( ISelEnv* env, X86CondCode 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); addInstr(env, X86Instr_Call( cc, toUInt(Ptr_to_ULong(cee->addr)), cee->regparms)); if (n_arg_ws > 0) add_to_esp(env, 4*n_arg_ws);}/* Used only in doHelperCall. See big comment in doHelperCall re handling of regparm 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 ){ X86CondCode cc; HReg argregs[3]; HReg tmpregs[3]; Bool danger; Int not_done_yet, n_args, n_arg_ws, stack_limit, i, argreg, argregX;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -