📄 isel.c
字号:
as signed or not. If yes, this will never return -32768 as an immediate; this guaranteed that all signed immediates that are return can have their sign inverted if need be. */static PPCRH* iselWordExpr_RH_wrk ( ISelEnv* env, Bool syned, IRExpr* e );static PPCRH* iselWordExpr_RH ( ISelEnv* env, Bool syned, IRExpr* e );/* 32-bit mode: compute an I32 into a RI (reg or 32-bit immediate). 64-bit mode: compute an I64 into a RI (reg or 64-bit immediate). */static PPCRI* iselWordExpr_RI_wrk ( ISelEnv* env, IRExpr* e );static PPCRI* iselWordExpr_RI ( ISelEnv* env, IRExpr* e );/* In 32 bit mode ONLY, compute an I8 into a reg-or-5-bit-unsigned-immediate, the latter being an immediate in the range 1 .. 31 inclusive. Used for doing shift amounts. */static PPCRH* iselWordExpr_RH5u_wrk ( ISelEnv* env, IRExpr* e );static PPCRH* iselWordExpr_RH5u ( ISelEnv* env, IRExpr* e );/* In 64-bit mode ONLY, compute an I8 into a Compute an I8 into a reg-or-6-bit-unsigned-immediate, the latter being an immediate in the range 1 .. 63 inclusive. Used for doing shift amounts. */static PPCRH* iselWordExpr_RH6u_wrk ( ISelEnv* env, IRExpr* e );static PPCRH* iselWordExpr_RH6u ( ISelEnv* env, IRExpr* e );/* 32-bit mode: compute an I32 into an AMode. 64-bit mode: compute an I64 into an AMode. */static PPCAMode* iselWordExpr_AMode_wrk ( ISelEnv* env, IRExpr* e );static PPCAMode* iselWordExpr_AMode ( ISelEnv* env, IRExpr* e );/* 32-bit mode ONLY: compute an I64 into a GPR pair. */static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e );static void iselInt64Expr ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e );/* 64-bit mode ONLY: compute an I128 into a GPR64 pair. */static void iselInt128Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e );static void iselInt128Expr ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e );static PPCCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e );static PPCCondCode 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 an int reg-reg move. */static PPCInstr* mk_iMOVds_RR ( HReg r_dst, HReg r_src ){ vassert(hregClass(r_dst) == hregClass(r_src)); vassert(hregClass(r_src) == HRcInt32 || hregClass(r_src) == HRcInt64); return PPCInstr_Alu(Palu_OR, r_dst, r_src, PPCRH_Reg(r_src));}/* Advance/retreat %r1 by n. */static void add_to_sp ( ISelEnv* env, UInt n ){ HReg sp = StackFramePtr(env->mode64); vassert(n < 256 && (n%16) == 0); addInstr(env, PPCInstr_Alu( Palu_ADD, sp, sp, PPCRH_Imm(True,toUShort(n)) ));}static void sub_from_sp ( ISelEnv* env, UInt n ){ HReg sp = StackFramePtr(env->mode64); vassert(n < 256 && (n%16) == 0); addInstr(env, PPCInstr_Alu( Palu_SUB, sp, sp, PPCRH_Imm(True,toUShort(n)) ));}/* returns a quadword aligned address on the stack - copies SP, adds 16bytes, aligns to quadword. use sub_from_sp(32) before calling this, as expects to have 32 bytes to play with.*/static HReg get_sp_aligned16 ( ISelEnv* env ){ HReg r = newVRegI(env); HReg align16 = newVRegI(env); addInstr(env, mk_iMOVds_RR(r, StackFramePtr(env->mode64))); // add 16 addInstr(env, PPCInstr_Alu( Palu_ADD, r, r, PPCRH_Imm(True,toUShort(16)) )); // mask to quadword addInstr(env, PPCInstr_LI(align16, 0xFFFFFFFFFFFFFFF0ULL, env->mode64)); addInstr(env, PPCInstr_Alu(Palu_AND, r,r, PPCRH_Reg(align16))); return r;}/* Load 2*I32 regs to fp reg */static HReg mk_LoadRR32toFPR ( ISelEnv* env, HReg r_srcHi, HReg r_srcLo ){ HReg fr_dst = newVRegF(env); PPCAMode *am_addr0, *am_addr1; vassert(!env->mode64); vassert(hregClass(r_srcHi) == HRcInt32); vassert(hregClass(r_srcLo) == HRcInt32); sub_from_sp( env, 16 ); // Move SP down 16 bytes am_addr0 = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); am_addr1 = PPCAMode_IR( 4, StackFramePtr(env->mode64) ); // store hi,lo as Ity_I32's addInstr(env, PPCInstr_Store( 4, am_addr0, r_srcHi, env->mode64 )); addInstr(env, PPCInstr_Store( 4, am_addr1, r_srcLo, env->mode64 )); // load as float addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, am_addr0)); add_to_sp( env, 16 ); // Reset SP return fr_dst;}/* Load I64 reg to fp reg */static HReg mk_LoadR64toFPR ( ISelEnv* env, HReg r_src ){ HReg fr_dst = newVRegF(env); PPCAMode *am_addr0; vassert(env->mode64); vassert(hregClass(r_src) == HRcInt64); sub_from_sp( env, 16 ); // Move SP down 16 bytes am_addr0 = PPCAMode_IR( 0, StackFramePtr(env->mode64) ); // store as Ity_I64 addInstr(env, PPCInstr_Store( 8, am_addr0, r_src, env->mode64 )); // load as float addInstr(env, PPCInstr_FpLdSt(True/*load*/, 8, fr_dst, am_addr0)); add_to_sp( env, 16 ); // Reset SP return fr_dst;}/* Given an amode, return one which references 4 bytes further along. */static PPCAMode* advance4 ( ISelEnv* env, PPCAMode* am ){ PPCAMode* am4 = dopyPPCAMode( am ); if (am4->tag == Pam_IR && am4->Pam.IR.index + 4 <= 32767) { am4->Pam.IR.index += 4; } else { vpanic("advance4(ppc,host)"); } return am4;}/* Given a guest-state array descriptor, an index expression and a bias, generate a PPCAMode pointing at the relevant piece of guest state. Only needed in 64-bit mode. */staticPPCAMode* genGuestArrayOffset ( ISelEnv* env, IRArray* descr, IRExpr* off, Int bias ){ HReg rtmp, roff; Int elemSz = sizeofIRType(descr->elemTy); Int nElems = descr->nElems; Int shift = 0; vassert(env->mode64); /* Throw out any cases we don't need. In theory there might be a day where we need to handle others, but not today. */ if (nElems != 16 && nElems != 32) vpanic("genGuestArrayOffset(ppc64 host)(1)"); switch (elemSz) { case 8: shift = 3; break; default: vpanic("genGuestArrayOffset(ppc64 host)(2)"); } if (bias < -100 || bias > 100) /* somewhat arbitrarily */ vpanic("genGuestArrayOffset(ppc64 host)(3)"); if (descr->base < 0 || descr->base > 2000) /* somewhat arbitrarily */ vpanic("genGuestArrayOffset(ppc64 host)(4)"); /* Compute off into a reg, %off. Then return: addi %tmp, %off, bias (if bias != 0) andi %tmp, nElems-1 sldi %tmp, shift addi %tmp, %tmp, base ... Baseblockptr + %tmp ... */ roff = iselWordExpr_R(env, off); rtmp = newVRegI(env); addInstr(env, PPCInstr_Alu( Palu_ADD, rtmp, roff, PPCRH_Imm(True/*signed*/, toUShort(bias)))); addInstr(env, PPCInstr_Alu( Palu_AND, rtmp, rtmp, PPCRH_Imm(False/*signed*/, toUShort(nElems-1)))); addInstr(env, PPCInstr_Shft( Pshft_SHL, False/*64-bit shift*/, rtmp, rtmp, PPCRH_Imm(False/*unsigned*/, toUShort(shift)))); addInstr(env, PPCInstr_Alu( Palu_ADD, rtmp, rtmp, PPCRH_Imm(True/*signed*/, toUShort(descr->base)))); return PPCAMode_RR( GuestStatePtr(env->mode64), rtmp );}/*---------------------------------------------------------*//*--- ISEL: Function call helpers ---*//*---------------------------------------------------------*//* Used only in doHelperCall. See big comment in doHelperCall re 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 ){ PPCCondCode cc; HReg argregs[PPC_N_REGPARMS]; HReg tmpregs[PPC_N_REGPARMS]; Bool go_fast; Int n_args, i, argreg; UInt argiregs; ULong target; Bool mode64 = env->mode64; /* 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 PPC_N_REGPARMS x (mode32:32 | mode64:64) integer bits in total can be passed. In fact the only supported arg type is (mode32:I32 | mode64: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 PPC32/64 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 (PPC_N_REGPARMS < n_args + (passBBP ? 1 : 0)) { vpanic("doHelperCall(PPC): cannot currently handle > 8 args"); // PPC_N_REGPARMS } argregs[0] = hregPPC_GPR3(mode64); argregs[1] = hregPPC_GPR4(mode64); argregs[2] = hregPPC_GPR5(mode64); argregs[3] = hregPPC_GPR6(mode64); argregs[4] = hregPPC_GPR7(mode64); argregs[5] = hregPPC_GPR8(mode64); argregs[6] = hregPPC_GPR9(mode64); argregs[7] = hregPPC_GPR10(mode64); argiregs = 0; tmpregs[0] = tmpregs[1] = tmpregs[2] = tmpregs[3] = tmpregs[4] = tmpregs[5] = tmpregs[6] = tmpregs[7] = 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -