📄 isel.c
字号:
aluOp = Xalu_AND; break; case Iop_Or8: case Iop_Or16: case Iop_Or32: aluOp = Xalu_OR; break; case Iop_Xor8: case Iop_Xor16: case Iop_Xor32: aluOp = Xalu_XOR; break; case Iop_Mul16: case Iop_Mul32: aluOp = Xalu_MUL; break; default: aluOp = Xalu_INVALID; break; } /* For commutative ops we assume any literal values are on the second operand. */ if (aluOp != Xalu_INVALID) { HReg dst = newVRegI(env); HReg reg = iselIntExpr_R(env, e->Iex.Binop.arg1); X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2); addInstr(env, mk_iMOVsd_RR(reg,dst)); addInstr(env, X86Instr_Alu32R(aluOp, rmi, dst)); return dst; } /* Could do better here; forcing the first arg into a reg isn't always clever. -- t70 = Xor32(And32(Xor32(LDle:I32(Add32(t41,0xFFFFFFA0:I32)), LDle:I32(Add32(t41,0xFFFFFFA4:I32))),LDle:I32(Add32( t41,0xFFFFFFA8:I32))),LDle:I32(Add32(t41,0xFFFFFFA0:I32))) movl 0xFFFFFFA0(%vr41),%vr107 movl 0xFFFFFFA4(%vr41),%vr108 movl %vr107,%vr106 xorl %vr108,%vr106 movl 0xFFFFFFA8(%vr41),%vr109 movl %vr106,%vr105 andl %vr109,%vr105 movl 0xFFFFFFA0(%vr41),%vr110 movl %vr105,%vr104 xorl %vr110,%vr104 movl %vr104,%vr70 */ /* Perhaps a shift op? */ switch (e->Iex.Binop.op) { case Iop_Shl32: case Iop_Shl16: case Iop_Shl8: shOp = Xsh_SHL; break; case Iop_Shr32: case Iop_Shr16: case Iop_Shr8: shOp = Xsh_SHR; break; case Iop_Sar32: case Iop_Sar16: case Iop_Sar8: shOp = Xsh_SAR; break; default: shOp = Xsh_INVALID; break; } if (shOp != Xsh_INVALID) { HReg dst = newVRegI(env); /* regL = the value to be shifted */ HReg regL = iselIntExpr_R(env, e->Iex.Binop.arg1); addInstr(env, mk_iMOVsd_RR(regL,dst)); /* Do any necessary widening for 16/8 bit operands */ switch (e->Iex.Binop.op) { case Iop_Shr8: addInstr(env, X86Instr_Alu32R( Xalu_AND, X86RMI_Imm(0xFF), dst)); break; case Iop_Shr16: addInstr(env, X86Instr_Alu32R( Xalu_AND, X86RMI_Imm(0xFFFF), dst)); break; case Iop_Sar8: addInstr(env, X86Instr_Sh32(Xsh_SHL, 24, dst)); addInstr(env, X86Instr_Sh32(Xsh_SAR, 24, dst)); break; case Iop_Sar16: addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, dst)); addInstr(env, X86Instr_Sh32(Xsh_SAR, 16, dst)); break; default: break; } /* Now consider the shift amount. If it's a literal, we can do a much better job than the general case. */ if (e->Iex.Binop.arg2->tag == Iex_Const) { /* assert that the IR is well-typed */ Int nshift; vassert(e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U8); nshift = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8; vassert(nshift >= 0); if (nshift > 0) /* Can't allow nshift==0 since that means %cl */ addInstr(env, X86Instr_Sh32( shOp, nshift, dst )); } else { /* General case; we have to force the amount into %cl. */ HReg regR = iselIntExpr_R(env, e->Iex.Binop.arg2); addInstr(env, mk_iMOVsd_RR(regR,hregX86_ECX())); addInstr(env, X86Instr_Sh32(shOp, 0/* %cl */, dst)); } return dst; } /* Handle misc other ops. */ if (e->Iex.Binop.op == Iop_8HLto16) { HReg hi8 = newVRegI(env); HReg lo8 = newVRegI(env); HReg hi8s = iselIntExpr_R(env, e->Iex.Binop.arg1); HReg lo8s = iselIntExpr_R(env, e->Iex.Binop.arg2); addInstr(env, mk_iMOVsd_RR(hi8s, hi8)); addInstr(env, mk_iMOVsd_RR(lo8s, lo8)); addInstr(env, X86Instr_Sh32(Xsh_SHL, 8, hi8)); addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0xFF), lo8)); addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(lo8), hi8)); return hi8; } if (e->Iex.Binop.op == Iop_16HLto32) { HReg hi16 = newVRegI(env); HReg lo16 = newVRegI(env); HReg hi16s = iselIntExpr_R(env, e->Iex.Binop.arg1); HReg lo16s = iselIntExpr_R(env, e->Iex.Binop.arg2); addInstr(env, mk_iMOVsd_RR(hi16s, hi16)); addInstr(env, mk_iMOVsd_RR(lo16s, lo16)); addInstr(env, X86Instr_Sh32(Xsh_SHL, 16, hi16)); addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0xFFFF), lo16)); addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Reg(lo16), hi16)); return hi16; } if (e->Iex.Binop.op == Iop_MullS16 || e->Iex.Binop.op == Iop_MullS8 || e->Iex.Binop.op == Iop_MullU16 || e->Iex.Binop.op == Iop_MullU8) { HReg a16 = newVRegI(env); HReg b16 = newVRegI(env); HReg a16s = iselIntExpr_R(env, e->Iex.Binop.arg1); HReg b16s = iselIntExpr_R(env, e->Iex.Binop.arg2); Int shift = (e->Iex.Binop.op == Iop_MullS8 || e->Iex.Binop.op == Iop_MullU8) ? 24 : 16; X86ShiftOp shr_op = (e->Iex.Binop.op == Iop_MullS8 || e->Iex.Binop.op == Iop_MullS16) ? Xsh_SAR : Xsh_SHR; addInstr(env, mk_iMOVsd_RR(a16s, a16)); addInstr(env, mk_iMOVsd_RR(b16s, b16)); addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, a16)); addInstr(env, X86Instr_Sh32(Xsh_SHL, shift, b16)); addInstr(env, X86Instr_Sh32(shr_op, shift, a16)); addInstr(env, X86Instr_Sh32(shr_op, shift, b16)); addInstr(env, X86Instr_Alu32R(Xalu_MUL, X86RMI_Reg(a16), b16)); return b16; } if (e->Iex.Binop.op == Iop_CmpF64) { HReg fL = iselDblExpr(env, e->Iex.Binop.arg1); HReg fR = iselDblExpr(env, e->Iex.Binop.arg2); HReg dst = newVRegI(env); addInstr(env, X86Instr_FpCmp(fL,fR,dst)); /* shift this right 8 bits so as to conform to CmpF64 definition. */ addInstr(env, X86Instr_Sh32(Xsh_SHR, 8, dst)); return dst; } if (e->Iex.Binop.op == Iop_F64toI32 || e->Iex.Binop.op == Iop_F64toI16) { Int sz = e->Iex.Binop.op == Iop_F64toI16 ? 2 : 4; HReg rf = iselDblExpr(env, e->Iex.Binop.arg2); HReg dst = newVRegI(env); /* Used several times ... */ X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP()); /* rf now holds the value to be converted, and rrm holds the rounding mode value, encoded as per the IRRoundingMode enum. The first thing to do is set the FPU's rounding mode accordingly. */ /* Create a space for the format conversion. */ /* subl $4, %esp */ sub_from_esp(env, 4); /* Set host rounding mode */ set_FPU_rounding_mode( env, e->Iex.Binop.arg1 ); /* gistw/l %rf, 0(%esp) */ addInstr(env, X86Instr_FpLdStI(False/*store*/, toUChar(sz), rf, zero_esp)); if (sz == 2) { /* movzwl 0(%esp), %dst */ addInstr(env, X86Instr_LoadEX(2,False,zero_esp,dst)); } else { /* movl 0(%esp), %dst */ vassert(sz == 4); addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(zero_esp), dst)); } /* Restore default FPU rounding. */ set_FPU_rounding_default( env ); /* addl $4, %esp */ add_to_esp(env, 4); return dst; } /* C3210 flags following FPU partial remainder (fprem), both IEEE compliant (PREM1) and non-IEEE compliant (PREM). */ if (e->Iex.Binop.op == Iop_PRemC3210F64 || e->Iex.Binop.op == Iop_PRem1C3210F64) { HReg junk = newVRegF(env); HReg dst = newVRegI(env); HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1); HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2); addInstr(env, X86Instr_FpBinary( e->Iex.Binop.op==Iop_PRemC3210F64 ? Xfp_PREM : Xfp_PREM1, srcL,srcR,junk )); /* The previous pseudo-insn will have left the FPU's C3210 flags set correctly. So bag them. */ addInstr(env, X86Instr_FpStSW_AX()); addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), dst)); addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0x4700), dst)); return dst; } break; } /* --------- UNARY OP --------- */ case Iex_Unop: { /* 1Uto8(32to1(expr32)) */ DEFINE_PATTERN(p_32to1_then_1Uto8, unop(Iop_1Uto8,unop(Iop_32to1,bind(0)))); if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) { IRExpr* expr32 = mi.bindee[0]; HReg dst = newVRegI(env); HReg src = iselIntExpr_R(env, expr32); addInstr(env, mk_iMOVsd_RR(src,dst) ); addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(1), dst)); return dst; } /* 16Uto32(LDle(expr32)) */ { DECLARE_PATTERN(p_LDle16_then_16Uto32); DEFINE_PATTERN(p_LDle16_then_16Uto32, unop(Iop_16Uto32, IRExpr_Load(Iend_LE,Ity_I16,bind(0))) ); if (matchIRExpr(&mi,p_LDle16_then_16Uto32,e)) { HReg dst = newVRegI(env); X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] ); addInstr(env, X86Instr_LoadEX(2,False,amode,dst)); return dst; } } switch (e->Iex.Unop.op) { case Iop_8Uto16: case Iop_8Uto32: case Iop_16Uto32: { HReg dst = newVRegI(env); HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); UInt mask = e->Iex.Unop.op==Iop_16Uto32 ? 0xFFFF : 0xFF; addInstr(env, mk_iMOVsd_RR(src,dst) ); addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(mask), dst)); return dst; } case Iop_8Sto16: case Iop_8Sto32: case Iop_16Sto32: { HReg dst = newVRegI(env); HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); UInt amt = e->Iex.Unop.op==Iop_16Sto32 ? 16 : 24; addInstr(env, mk_iMOVsd_RR(src,dst) ); addInstr(env, X86Instr_Sh32(Xsh_SHL, amt, dst)); addInstr(env, X86Instr_Sh32(Xsh_SAR, amt, dst)); return dst; } case Iop_Not8: case Iop_Not16: case Iop_Not32: { HReg dst = newVRegI(env); HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); addInstr(env, mk_iMOVsd_RR(src,dst) ); addInstr(env, X86Instr_Unary32(Xun_NOT,dst)); return dst; } case Iop_64HIto32: { HReg rHi, rLo; iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg); return rHi; /* and abandon rLo .. poor wee thing :-) */ } case Iop_64to32: { HReg rHi, rLo; iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg); return rLo; /* similar stupid comment to the above ... */ } case Iop_16HIto8: case Iop_32HIto16: { HReg dst = newVRegI(env); HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); Int shift = e->Iex.Unop.op == Iop_16HIto8 ? 8 : 16; addInstr(env, mk_iMOVsd_RR(src,dst) ); addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, dst)); return dst; } case Iop_1Uto32: case Iop_1Uto8: { HReg dst = newVRegI(env); X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg); addInstr(env, X86Instr_Set32(cond,dst)); return dst; } case Iop_1Sto8: case Iop_1Sto16: case Iop_1Sto32: { /* could do better than this, but for now ... */ HReg dst = newVRegI(env); X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg); addInstr(env, X86Instr_Set32(cond,dst)); addInstr(env, X86Instr_Sh32(Xsh_SHL, 31, dst)); addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, dst)); return dst; } case Iop_Ctz32: { /* Count trailing zeroes, implemented by x86 'bsfl' */ HReg dst = newVRegI(env); HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); addInstr(env, X86Instr_Bsfr32(True,src,dst)); return dst; } case Iop_Clz32: { /* Count leading zeroes. Do 'bsrl' to establish the index of the highest set bit, and subtract that value from 31. */ HReg tmp = newVRegI(env); HReg dst = newVRegI(env); HReg src = iselIntExpr_R(env, e->Iex.Unop.arg); addInstr(env, X86Instr_Bsfr32(False,src,tmp)); addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(31), dst)); addInstr(env, X86Instr_Alu32R(Xalu_SUB, X86RMI_Reg(tmp), dst)); return dst; } case Iop_Neg8: case Iop_Neg16: case Iop_Neg32: { HReg dst = newVRegI(env); HReg reg = iselIntExpr_R(env, e->Iex.Unop.arg); addInstr(env, mk_iMOVsd_RR(reg,dst)); addInstr(env, X86Instr_Unary32(Xun_NEG,dst)); return dst; } case Iop_V128to32: { HReg dst = newVRegI(env); HReg vec = iselVecExpr(env, e->Iex.Unop.arg); X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP()); sub_from_esp(env, 16); addInstr(env, X86Instr_SseLdSt(False/*store*/, vec, esp0)); addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(esp0), dst )); add_to_esp(env, 16); return dst; } case Iop_16to8: case Iop_32to8: case Iop_32to16: /* These are no-ops. */ return iselIntExpr_R(env, e->Iex.Unop.arg); default: break; } break; } /* --------- GET --------- */ case Iex_Get: { if (ty == Ity_I32) { HReg dst = newVRegI(env); addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(X86AMode_IR(e->Iex.Get.offset, hregX86_EBP())), dst)); return dst; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -