📄 isel.c
字号:
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) { argiregs |= (1 << (argreg+3)); addInstr(env, mk_iMOVds_RR( argregs[argreg], GuestStatePtr(mode64) )); argreg++; } for (i = 0; i < n_args; i++) { vassert(argreg < PPC_N_REGPARMS); vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32 || typeOfIRExpr(env->type_env, args[i]) == Ity_I64); if (!mode64) { if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) { argiregs |= (1 << (argreg+3)); addInstr(env, mk_iMOVds_RR( argregs[argreg], iselWordExpr_R(env, args[i]) )); } else { // Ity_I64 HReg rHi, rLo; if (argreg%2 == 1) // ppc32 abi spec for passing LONG_LONG argreg++; // XXX: odd argreg => even rN vassert(argreg < PPC_N_REGPARMS-1); iselInt64Expr(&rHi,&rLo, env, args[i]); argiregs |= (1 << (argreg+3)); addInstr(env, mk_iMOVds_RR( argregs[argreg++], rHi )); argiregs |= (1 << (argreg+3)); addInstr(env, mk_iMOVds_RR( argregs[argreg], rLo)); } } else { // mode64 argiregs |= (1 << (argreg+3)); addInstr(env, mk_iMOVds_RR( argregs[argreg], iselWordExpr_R(env, args[i]) )); } argreg++; } /* Fast scheme only applies for unconditional calls. Hence: */ cc.test = Pct_ALWAYS; } else { /* SLOW SCHEME; move via temporaries */ argreg = 0; if (passBBP) { /* This is pretty stupid; better to move directly to r3 after the rest of the args are done. */ tmpregs[argreg] = newVRegI(env); addInstr(env, mk_iMOVds_RR( tmpregs[argreg], GuestStatePtr(mode64) )); argreg++; } for (i = 0; i < n_args; i++) { vassert(argreg < PPC_N_REGPARMS); vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32 || typeOfIRExpr(env->type_env, args[i]) == Ity_I64); if (!mode64) { if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) { tmpregs[argreg] = iselWordExpr_R(env, args[i]); } else { // Ity_I64 HReg rHi, rLo; if (argreg%2 == 1) // ppc32 abi spec for passing LONG_LONG argreg++; // XXX: odd argreg => even rN vassert(argreg < PPC_N_REGPARMS-1); iselInt64Expr(&rHi,&rLo, env, args[i]); tmpregs[argreg++] = rHi; tmpregs[argreg] = rLo; } } else { // mode64 tmpregs[argreg] = iselWordExpr_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.test = Pct_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++) { if (tmpregs[i] == INVALID_HREG) // Skip invalid regs continue; /* None of these insns, including any spill code that might be generated, may alter the condition codes. */ argiregs |= (1 << (i+3)); addInstr( env, mk_iMOVds_RR( argregs[i], tmpregs[i] ) ); } } target = mode64 ? Ptr_to_ULong(cee->addr) : toUInt(Ptr_to_ULong(cee->addr)); /* Finally, the call itself. */ addInstr(env, PPCInstr_Call( cc, (Addr64)target, argiregs ));}/*---------------------------------------------------------*//*--- ISEL: FP rounding mode helpers ---*//*---------------------------------------------------------*////* Set FPU's rounding mode to the default *///static //void set_FPU_rounding_default ( ISelEnv* env )//{// HReg fr_src = newVRegF(env);// HReg r_src = newVRegI(env);//// /* Default rounding mode = 0x0// Only supporting the rounding-mode bits - the rest of FPSCR is 0x0// - so we can set the whole register at once (faster)// note: upper 32 bits ignored by FpLdFPSCR// */// addInstr(env, PPCInstr_LI(r_src, 0x0, env->mode64));// if (env->mode64) {// fr_src = mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64// } else {// fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64// }// addInstr(env, PPCInstr_FpLdFPSCR( fr_src ));//}/* Convert IR rounding mode to PPC encoding */static HReg roundModeIRtoPPC ( ISelEnv* env, HReg r_rmIR ){ /* rounding mode | PPC | IR ------------------------ to nearest | 00 | 00 to zero | 01 | 11 to +infinity | 10 | 10 to -infinity | 11 | 01 */ HReg r_rmPPC = newVRegI(env); HReg r_tmp1 = newVRegI(env); vassert(hregClass(r_rmIR) == HRcGPR(env->mode64)); // r_rmPPC = XOR(r_rmIR, r_rmIR << 1) & 3 // // slwi tmp1, r_rmIR, 1 // xor tmp1, r_rmIR, tmp1 // andi r_rmPPC, tmp1, 3 addInstr(env, PPCInstr_Shft(Pshft_SHL, True/*32bit shift*/, r_tmp1, r_rmIR, PPCRH_Imm(False,1))); addInstr(env, PPCInstr_Alu( Palu_XOR, r_tmp1, r_rmIR, PPCRH_Reg(r_tmp1) )); addInstr(env, PPCInstr_Alu( Palu_AND, r_rmPPC, r_tmp1, PPCRH_Imm(False,3) )); return r_rmPPC;}/* Set 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 PPC FPSCR to have the same rounding. For speed & simplicity, we're setting the *entire* FPSCR here. Setting the rounding mode is expensive. So this function tries to avoid repeatedly setting the rounding mode to the same thing by first comparing 'mode' to the 'mode' tree supplied in the previous call to this function, if any. (The previous value is stored in env->previous_rm.) If 'mode' is a single IR temporary 't' and env->previous_rm is also just 't', then the setting is skipped. This is safe because of the SSA property of IR: an IR temporary can only be defined once and so will have the same value regardless of where it appears in the block. Cool stuff, SSA. A safety condition: all attempts to set the RM must be aware of this mechanism - by being routed through the functions here. Of course this only helps if blocks where the RM is set more than once and it is set to the same value each time, *and* that value is held in the same IR temporary each time. In order to assure the latter as much as possible, the IR optimiser takes care to do CSE on any block with any sign of floating point activity.*/staticvoid set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode ){ HReg fr_src = newVRegF(env); HReg r_src; vassert(typeOfIRExpr(env->type_env,mode) == Ity_I32); /* Do we need to do anything? */ if (env->previous_rm && env->previous_rm->tag == Iex_Tmp && mode->tag == Iex_Tmp && env->previous_rm->Iex.Tmp.tmp == mode->Iex.Tmp.tmp) { /* no - setting it to what it was before. */ vassert(typeOfIRExpr(env->type_env, env->previous_rm) == Ity_I32); return; } /* No luck - we better set it, and remember what we set it to. */ env->previous_rm = mode; /* Only supporting the rounding-mode bits - the rest of FPSCR is 0x0 - so we can set the whole register at once (faster). */ // Resolve rounding mode and convert to PPC representation r_src = roundModeIRtoPPC( env, iselWordExpr_R(env, mode) ); // gpr -> fpr if (env->mode64) { fr_src = mk_LoadR64toFPR( env, r_src ); // 1*I64 -> F64 } else { fr_src = mk_LoadRR32toFPR( env, r_src, r_src ); // 2*I32 -> F64 } // Move to FPSCR addInstr(env, PPCInstr_FpLdFPSCR( fr_src ));}/*---------------------------------------------------------*//*--- ISEL: vector helpers ---*//*---------------------------------------------------------*//* Generate all-zeroes into a new vector register.*/static HReg generate_zeroes_V128 ( ISelEnv* env ){ HReg dst = newVRegV(env); addInstr(env, PPCInstr_AvBinary(Pav_XOR, dst, dst, dst)); return dst;}/* Generates code for AvSplat - takes in IRExpr* of type 8|16|32 returns vector reg of duplicated lanes of input - uses AvSplat(imm) for imms up to simm6. otherwise must use store reg & load vector*/static HReg mk_AvDuplicateRI( ISelEnv* env, IRExpr* e ){ HReg r_src; HReg dst = newVRegV(env); PPCRI* ri = iselWordExpr_RI(env, e); IRType ty = typeOfIRExpr(env->type_env,e); UInt sz = (ty == Ity_I8) ? 8 : (ty == Ity_I16) ? 16 : 32; vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32); /* special case: immediate */ if (ri->tag == Pri_Imm) { Int simm32 = (Int)ri->Pri.Imm; /* figure out if it's do-able with imm splats. */ if (simm32 >= -32 && simm32 <= 31) { Char simm6 = (Char)simm32; if (simm6 > 15) { /* 16:31 inclusive */ HReg v1 = newVRegV(env); HReg v2 = newVRegV(env); addInstr(env, PPCInstr_AvSplat(sz, v1, PPCVI5s_Imm(-16))); addInstr(env, PPCInstr_AvSplat(sz, v2, PPCVI5s_Imm(simm6-16))); addInstr(env, (sz== 8) ? PPCInstr_AvBin8x16(Pav_SUBU, dst, v2, v1) : (sz==16) ? PPCInstr_AvBin16x8(Pav_SUBU, dst, v2, v1) : PPCInstr_AvBin32x4(Pav_SUBU, dst, v2, v1) ); return dst; } if (simm6 < -16) { /* -32:-17 inclusive */ HReg v1 = newVRegV(env); HReg v2 = newVRegV(env); addInstr(env, PPCInstr_AvSplat(sz, v1, PPCVI5s_Imm(-16))); addInstr(env, PPCInstr_AvSplat(sz, v2, PPCVI5s_Imm(simm6+16))); addInstr(env, (sz== 8) ? PPCInstr_AvBin8x16(Pav_ADDU, dst, v2, v1) : (sz==16) ? PPCInstr_AvBin16x8(Pav_ADDU, dst, v2, v1) : PPCInstr_AvBin32x4(Pav_ADDU, dst, v2, v1) ); return dst; } /* simplest form: -16:15 inclusive */ addInstr(env, PPCInstr_AvSplat(sz, dst, PPCVI5s_Imm(simm6))); return dst; } /* no luck; use the Slow way. */ r_src = newVRegI(env); addInstr(env, PPCInstr_LI(r_src, (Long)simm32, env->mode64)); } else { r_src = ri->Pri.Reg; } /* default case: store r_src in lowest lane of 16-aligned mem, load vector, splat lowest lane to dst */ { /* CAB: Maybe faster to store r_src multiple times (sz dependent), and simply load the vector? */ HReg r_aligned16; HReg v_src = newVRegV(env); PPCAMode *am_off12; sub_from_sp( env, 32 ); // Move SP down /* Get a 16-aligned address within our stack space */ r_aligned16 = get_sp_aligned16( env ); am_off12 = PPCAMode_IR( 12, r_aligned16 ); /* Store r_src in low word of 16-aligned mem */ addInstr(env, PPCInstr_Store( 4, am_off12, r_src, env->mode64 )); /* Load src to vector[low lane] */ addInstr(env, PPCInstr_AvLdSt( True/*ld*/, 4, v_src, am_off12 ) ); add_to_sp( env, 32 ); // Reset SP /* Finally, splat v_src[low_lane] to dst */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -