| |
| /*--------------------------------------------------------------------*/ |
| /*--- begin guest_tilegx_toIR.c ---*/ |
| /*--------------------------------------------------------------------*/ |
| |
| /* |
| This file is part of Valgrind, a dynamic binary instrumentation |
| framework. |
| |
| Copyright (C) 2010-2015 Tilera Corp. |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License as |
| published by the Free Software Foundation; either version 2 of the |
| License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA |
| 02111-1307, USA. |
| |
| The GNU General Public License is contained in the file COPYING. |
| */ |
| |
| /* Contributed by Zhi-Gang Liu <zliu at tilera dot com> */ |
| |
| /* Translates TILEGX code to IR. */ |
| |
| #include "libvex_basictypes.h" |
| #include "libvex_ir.h" |
| #include "libvex.h" |
| #include "libvex_guest_tilegx.h" |
| |
| #include "main_util.h" |
| #include "main_globals.h" |
| #include "guest_generic_bb_to_IR.h" |
| #include "guest_tilegx_defs.h" |
| #include "tilegx_disasm.h" |
| |
| /*------------------------------------------------------------*/ |
| /*--- Globals ---*/ |
| /*------------------------------------------------------------*/ |
| |
| /* These are set at the start of the translation of a instruction, so |
| that we don't have to pass them around endlessly. CONST means does |
| not change during translation of the instruction. |
| */ |
| |
| /* CONST: is the host bigendian? This has to do with float vs double |
| register accesses on VFP, but it's complex and not properly thought |
| out. */ |
| static VexEndness host_endness; |
| |
| /* Pointer to the guest code area. */ |
| static UChar *guest_code; |
| |
| /* The guest address corresponding to guest_code[0]. */ |
| static Addr64 guest_PC_bbstart; |
| |
| /* CONST: The guest address for the instruction currently being |
| translated. */ |
| static Addr64 guest_PC_curr_instr; |
| |
| /* MOD: The IRSB* into which we're generating code. */ |
| static IRSB *irsb; |
| |
| /*------------------------------------------------------------*/ |
| /*--- Debugging output ---*/ |
| /*------------------------------------------------------------*/ |
| |
| #define DIP(format, args...) \ |
| if (vex_traceflags & VEX_TRACE_FE) \ |
| vex_printf(format, ## args) |
| |
| /*------------------------------------------------------------*/ |
| /*--- Helper bits and pieces for deconstructing the ---*/ |
| /*--- tilegx insn stream. ---*/ |
| /*------------------------------------------------------------*/ |
| |
| static Int integerGuestRegOffset ( UInt iregNo ) |
| { |
| return 8 * (iregNo); |
| } |
| |
| /*------------------------------------------------------------*/ |
| /*--- Field helpers ---*/ |
| /*------------------------------------------------------------*/ |
| |
| /*------------------------------------------------------------*/ |
| /*--- Helper bits and pieces for creating IR fragments. ---*/ |
| /*------------------------------------------------------------*/ |
| |
| static IRExpr *mkU8 ( UInt i ) |
| { |
| return IRExpr_Const(IRConst_U8((UChar) i)); |
| } |
| |
| /* Create an expression node for a 32-bit integer constant */ |
| static IRExpr *mkU32 ( UInt i ) |
| { |
| return IRExpr_Const(IRConst_U32(i)); |
| } |
| |
| /* Create an expression node for a 64-bit integer constant */ |
| static IRExpr *mkU64 ( ULong i ) |
| { |
| return IRExpr_Const(IRConst_U64(i)); |
| } |
| |
| static IRExpr *mkexpr ( IRTemp tmp ) |
| { |
| return IRExpr_RdTmp(tmp); |
| } |
| |
| 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 *load ( IRType ty, IRExpr * addr ) |
| { |
| IRExpr *load1 = NULL; |
| |
| load1 = IRExpr_Load(Iend_LE, ty, addr); |
| return load1; |
| } |
| |
| /* Add a statement to the list held by "irsb". */ |
| static void stmt ( IRStmt * st ) |
| { |
| addStmtToIRSB(irsb, st); |
| } |
| |
| #define OFFB_PC offsetof(VexGuestTILEGXState, guest_pc) |
| |
| static void putPC ( IRExpr * e ) |
| { |
| stmt(IRStmt_Put(OFFB_PC, e)); |
| } |
| |
| static void assign ( IRTemp dst, IRExpr * e ) |
| { |
| stmt(IRStmt_WrTmp(dst, e)); |
| } |
| |
| static void store ( IRExpr * addr, IRExpr * data ) |
| { |
| stmt(IRStmt_Store(Iend_LE, addr, data)); |
| } |
| |
| /* Generate a new temporary of the given type. */ |
| static IRTemp newTemp ( IRType ty ) |
| { |
| vassert(isPlausibleIRType(ty)); |
| return newIRTemp(irsb->tyenv, ty); |
| } |
| |
| static ULong extend_s_16to64 ( UInt x ) |
| { |
| return (ULong) ((((Long) x) << 48) >> 48); |
| } |
| |
| static ULong extend_s_8to64 ( UInt x ) |
| { |
| return (ULong) ((((Long) x) << 56) >> 56); |
| } |
| |
| static IRExpr *getIReg ( UInt iregNo ) |
| { |
| IRType ty = Ity_I64; |
| if(!(iregNo < 56 || iregNo == 63 || |
| (iregNo >= 70 && iregNo <= 73))) { |
| vex_printf("iregNo=%u\n", iregNo); |
| vassert(0); |
| } |
| return IRExpr_Get(integerGuestRegOffset(iregNo), ty); |
| } |
| |
| static void putIReg ( UInt archreg, IRExpr * e ) |
| { |
| IRType ty = Ity_I64; |
| if(!(archreg < 56 || archreg == 63 || archreg == 70 || |
| archreg == 72 || archreg == 73)) { |
| vex_printf("archreg=%u\n", archreg); |
| vassert(0); |
| } |
| vassert(typeOfIRExpr(irsb->tyenv, e) == ty); |
| if (archreg != 63) |
| stmt(IRStmt_Put(integerGuestRegOffset(archreg), e)); |
| } |
| |
| /* Narrow 8/16/32 bit int expr to 8/16/32. Clearly only some |
| of these combinations make sense. */ |
| static IRExpr *narrowTo ( IRType dst_ty, IRExpr * e ) |
| { |
| IRType src_ty = typeOfIRExpr(irsb->tyenv, e); |
| if (src_ty == dst_ty) |
| return e; |
| if (src_ty == Ity_I32 && dst_ty == Ity_I16) |
| return unop(Iop_32to16, e); |
| if (src_ty == Ity_I32 && dst_ty == Ity_I8) |
| return unop(Iop_32to8, e); |
| |
| if (src_ty == Ity_I64 && dst_ty == Ity_I8) { |
| return unop(Iop_64to8, e); |
| } |
| if (src_ty == Ity_I64 && dst_ty == Ity_I16) { |
| return unop(Iop_64to16, e); |
| } |
| if (src_ty == Ity_I64 && dst_ty == Ity_I32) { |
| return unop(Iop_64to32, e); |
| } |
| |
| if (vex_traceflags & VEX_TRACE_FE) { |
| vex_printf("\nsrc, dst tys are: "); |
| ppIRType(src_ty); |
| vex_printf(", "); |
| ppIRType(dst_ty); |
| vex_printf("\n"); |
| } |
| vpanic("narrowTo(tilegx)"); |
| return e; |
| } |
| |
| #define signExtend(_e, _n) \ |
| ((_n == 32) ? \ |
| unop(Iop_32Sto64, _e) : \ |
| ((_n == 16) ? \ |
| unop(Iop_16Sto64, _e) : \ |
| (binop(Iop_Sar64, binop(Iop_Shl64, _e, mkU8(63 - (_n))), mkU8(63 - (_n)))))) |
| |
| static IRStmt* dis_branch ( IRExpr* guard, ULong imm ) |
| { |
| IRTemp t0; |
| |
| t0 = newTemp(Ity_I1); |
| assign(t0, guard); |
| return IRStmt_Exit(mkexpr(t0), Ijk_Boring, |
| IRConst_U64(imm), OFFB_PC); |
| } |
| |
| #define MARK_REG_WB(_rd, _td) \ |
| do { \ |
| vassert(rd_wb_index < 6); \ |
| rd_wb_temp[rd_wb_index] = _td; \ |
| rd_wb_reg[rd_wb_index] = _rd; \ |
| rd_wb_index++; \ |
| } while(0) |
| |
| |
| /* Expand/repeat byte _X 8 times to a 64-bit value */ |
| #define V1EXP(_X) \ |
| ({ \ |
| _X = ((((UChar)(_X)) << 8) | ((UChar)(_X))); \ |
| _X = (((_X) << 16) | (_X)); \ |
| (((_X) << 32) | (_X)); \ |
| }) |
| |
| /* Expand/repeat byte _X 4 times to a 64-bit value */ |
| #define V2EXP(_X) \ |
| ({ \ |
| _X = ((((UChar)(_X)) << 16) | ((UChar)(_X))); \ |
| (((_X) << 32) | (_X)); \ |
| }) |
| |
| /*------------------------------------------------------------*/ |
| /*--- Disassemble a single instruction ---*/ |
| /*------------------------------------------------------------*/ |
| |
| /* Disassemble a single instruction bundle into IR. The bundle is |
| located in host memory at guest_instr, and has guest IP of |
| guest_PC_curr_instr, which will have been set before the call |
| here. */ |
| static DisResult disInstr_TILEGX_WRK ( Bool(*resteerOkFn) (void *, Addr), |
| Bool resteerCisOk, |
| void *callback_opaque, |
| Long delta64, |
| const VexArchInfo * archinfo, |
| const VexAbiInfo * abiinfo, |
| Bool sigill_diag ) |
| { |
| struct tilegx_decoded_instruction |
| decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]; |
| ULong cins, opcode = -1, rd, ra, rb, imm = 0; |
| ULong opd[4]; |
| ULong opd_src_map, opd_dst_map, opd_imm_map; |
| Int use_dirty_helper; |
| IRTemp t0, t1, t2, t3, t4; |
| IRTemp tb[4]; |
| IRTemp rd_wb_temp[6]; |
| ULong rd_wb_reg[6]; |
| /* Tilegx is a VLIW processor, we have to commit register write after read.*/ |
| Int rd_wb_index; |
| Int n = 0, nr_insn; |
| DisResult dres; |
| |
| /* The running delta */ |
| Long delta = delta64; |
| |
| /* Holds pc at the start of the insn, so that we can print |
| consistent error messages for unimplemented insns. */ |
| //Long delta_start = delta; |
| |
| UChar *code = (UChar *) (guest_code + delta); |
| |
| IRStmt *bstmt = NULL; /* Branch statement. */ |
| IRExpr *next = NULL; /* Next bundle expr. */ |
| ULong jumpkind = Ijk_Boring; |
| ULong steering_pc; |
| |
| /* Set result defaults. */ |
| dres.whatNext = Dis_Continue; |
| dres.len = 0; |
| dres.continueAt = 0; |
| dres.jk_StopHere = Ijk_INVALID; |
| |
| /* Verify the code addr is 8-byte aligned. */ |
| vassert((((Addr)code) & 7) == 0); |
| |
| /* Get the instruction bundle. */ |
| cins = *((ULong *)(Addr) code); |
| |
| /* "Special" instructions. */ |
| /* Spot the 16-byte preamble: ****tilegx**** |
| 0:02b3c7ff91234fff { moveli zero, 4660 ; moveli zero, 22136 } |
| 8:0091a7ff95678fff { moveli zero, 22136 ; moveli zero, 4660 } |
| */ |
| #define CL_W0 0x02b3c7ff91234fffULL |
| #define CL_W1 0x0091a7ff95678fffULL |
| |
| if (*((ULong*)(Addr)(code)) == CL_W0 && |
| *((ULong*)(Addr)(code + 8)) == CL_W1) { |
| /* Got a "Special" instruction preamble. Which one is it? */ |
| if (*((ULong*)(Addr)(code + 16)) == |
| 0x283a69a6d1483000ULL /* or r13, r13, r13 */ ) { |
| /* r0 = client_request ( r12 ) */ |
| DIP("r0 = client_request ( r12 )\n"); |
| |
| putPC(mkU64(guest_PC_curr_instr + 24)); |
| |
| dres.jk_StopHere = Ijk_ClientReq; |
| dres.whatNext = Dis_StopHere; |
| dres.len = 24; |
| goto decode_success; |
| |
| } else if (*((ULong*)(Addr)(code + 16)) == |
| 0x283a71c751483000ULL /* or r14, r14, r14 */ ) { |
| /* r11 = guest_NRADDR */ |
| DIP("r11 = guest_NRADDR\n"); |
| dres.len = 24; |
| putIReg(11, IRExpr_Get(offsetof(VexGuestTILEGXState, guest_NRADDR), |
| Ity_I64)); |
| putPC(mkU64(guest_PC_curr_instr + 8)); |
| goto decode_success; |
| |
| } else if (*((ULong*)(Addr)(code + 16)) == |
| 0x283a79e7d1483000ULL /* or r15, r15, r15 */ ) { |
| /* branch-and-link-to-noredir r12 */ |
| DIP("branch-and-link-to-noredir r12\n"); |
| dres.len = 24; |
| putIReg(55, mkU64(guest_PC_curr_instr + 24)); |
| |
| putPC(getIReg(12)); |
| |
| dres.jk_StopHere = Ijk_NoRedir; |
| dres.whatNext = Dis_StopHere; |
| goto decode_success; |
| |
| } else if (*((ULong*)(Addr)(code + 16)) == |
| 0x283a5965d1483000ULL /* or r11, r11, r11 */ ) { |
| /* vex-inject-ir */ |
| DIP("vex-inject-ir\n"); |
| dres.len = 24; |
| |
| vex_inject_ir(irsb, Iend_LE); |
| |
| stmt(IRStmt_Put(offsetof(VexGuestTILEGXState, guest_CMSTART), |
| mkU64(guest_PC_curr_instr))); |
| stmt(IRStmt_Put(offsetof(VexGuestTILEGXState, guest_CMLEN), |
| mkU64(24))); |
| |
| /* 2 + 1 = 3 bundles. 24 bytes. */ |
| putPC(mkU64(guest_PC_curr_instr + 24)); |
| |
| dres.jk_StopHere = Ijk_InvalICache; |
| dres.whatNext = Dis_StopHere; |
| goto decode_success; |
| } |
| |
| /* We don't expect this. */ |
| vex_printf("%s: unexpect special bundles at %lx\n", |
| __func__, (Addr)guest_PC_curr_instr); |
| delta += 16; |
| goto decode_failure; |
| /*NOTREACHED*/ |
| } |
| |
| /* To decode the given instruction bundle. */ |
| nr_insn = parse_insn_tilegx((tilegx_bundle_bits)cins, |
| (ULong)(Addr)code, |
| decoded); |
| |
| if (vex_traceflags & VEX_TRACE_FE) |
| decode_and_display(&cins, 1, (ULong)(Addr)code); |
| |
| /* Init. rb_wb_index */ |
| rd_wb_index = 0; |
| |
| steering_pc = -1ULL; |
| |
| for (n = 0; n < nr_insn; n++) { |
| opcode = decoded[n].opcode->mnemonic; |
| Int opi; |
| |
| rd = ra = rb = -1; |
| opd[0] = opd[1] = opd[2] = opd[3] = -1; |
| opd_dst_map = 0; |
| opd_src_map = 0; |
| opd_imm_map = 0; |
| |
| for (opi = 0; opi < decoded[n].opcode->num_operands; opi++) { |
| const struct tilegx_operand *op = decoded[n].operands[opi]; |
| opd[opi] = decoded[n].operand_values[opi]; |
| |
| /* Set the operands. rd, ra, rb and imm. */ |
| if (opi < 3) { |
| if (op->is_dest_reg) { |
| if (rd == -1) |
| rd = decoded[n].operand_values[opi]; |
| else if (ra == -1) |
| ra = decoded[n].operand_values[opi]; |
| } else if (op->is_src_reg) { |
| if (ra == -1) { |
| ra = decoded[n].operand_values[opi]; |
| } else if(rb == -1) { |
| rb = decoded[n].operand_values[opi]; |
| } else { |
| vassert(0); |
| } |
| } else { |
| imm = decoded[n].operand_values[opi]; |
| } |
| } |
| |
| /* Build bit maps of used dest, source registers |
| and immediate. */ |
| if (op->is_dest_reg) { |
| opd_dst_map |= 1ULL << opi; |
| if(op->is_src_reg) |
| opd_src_map |= 1ULL << opi; |
| } else if(op->is_src_reg) { |
| opd_src_map |= 1ULL << opi; |
| } else { |
| opd_imm_map |= 1ULL << opi; |
| } |
| } |
| |
| use_dirty_helper = 0; |
| |
| switch (opcode) { |
| case 0: /* "bpt" */ /* "raise" */ |
| /* "bpt" pseudo instruction is an illegal instruction */ |
| opd_imm_map |= (1 << 0); |
| opd[0] = cins; |
| use_dirty_helper = 1; |
| break; |
| case 1: /* "info" */ /* Ignore this instruction. */ |
| break; |
| case 2: /* "infol" */ /* Ignore this instruction. */ |
| break; |
| case 3: /* "ld4s_tls" */ /* Ignore this instruction. */ |
| break; |
| case 4: /* "ld_tls" */ /* Ignore this instruction. */ |
| break; |
| case 5: /* "move" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, getIReg(ra)); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 6: /* "movei" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, mkU64(extend_s_8to64(imm))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 7: /* "moveli" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, mkU64(extend_s_16to64(imm))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 8: /* "prefetch" */ /* Ignore. */ |
| break; |
| case 9: /* "prefetch_add_l1" */ /* Ignore. */ |
| break; |
| case 10: /* "prefetch_add_l1_fault" */ /* Ignore. */ |
| break; |
| case 11: /* "prefetch_add_l2" */ /* Ignore. */ |
| break; |
| case 12: /* "prefetch_add_l2_fault" */ /* Ignore. */ |
| break; |
| case 13: /* "prefetch_add_l3" */ /* Ignore. */ |
| break; |
| case 14: /* "prefetch_add_l3_fault" */ /* Ignore. */ |
| break; |
| case 15: /* "prefetch_l1" */ /* Ignore. */ |
| break; |
| case 16: /* "prefetch_l1_fault" */ /* Ignore. */ |
| break; |
| case 17: /* "prefetch_l2" */ /* Ignore. */ |
| break; |
| case 18: /* "prefetch_l2_fault" */ /* Ignore. */ |
| break; |
| case 19: /* "prefetch_l3" */ /* Ignore. */ |
| break; |
| case 20: /* "prefetch_l3_fault" */ /* Ignore. */ |
| break; |
| case 21: /* "raise" */ |
| /* "raise" pseudo instruction is an illegal instruction plusing |
| a "moveli zero, <sig>", so we need save whole bundle in the |
| opd[0], which will be used in the dirty helper. */ |
| opd_imm_map |= (1 << 0); |
| opd[0] = cins; |
| use_dirty_helper = 1; |
| break; |
| case 22: /* "add" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Add64, getIReg(ra), getIReg(rb))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 23: /* "addi" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Add64, getIReg(ra), |
| mkU64(extend_s_8to64(imm)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 24: /* "addli" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Add64, getIReg(ra), |
| mkU64(extend_s_16to64(imm)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 25: /* "addx" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, signExtend(binop(Iop_Add32, |
| narrowTo(Ity_I32, getIReg(ra)), |
| narrowTo(Ity_I32, getIReg(rb))), |
| 32)); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 26: /* "addxi" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, signExtend(binop(Iop_Add32, |
| narrowTo(Ity_I32, getIReg(ra)), |
| mkU32(imm)), 32)); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 27: /* "addxli" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, signExtend(binop(Iop_Add32, |
| narrowTo(Ity_I32, getIReg(ra)), |
| mkU32(imm)), 32)); |
| |
| MARK_REG_WB(rd, t2); |
| break; |
| case 28: /* "addxsc" */ |
| use_dirty_helper = 1; |
| break; |
| case 29: /* "and" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_And64, getIReg(ra), getIReg(rb))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 30: /* "andi" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_And64, getIReg(ra), |
| mkU64(extend_s_8to64(imm)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 31: /* "beqz" */ |
| /* Fall-through */ |
| case 32: |
| /* "beqzt" */ |
| bstmt = dis_branch(binop(Iop_CmpEQ64, getIReg(ra), mkU64(0)), |
| imm); |
| break; |
| case 33: /* "bfexts" */ |
| { |
| ULong imm0 = decoded[n].operand_values[3]; |
| ULong mask = ((-1ULL) ^ ((-1ULL << ((imm0 - imm) & 63)) << 1)); |
| t0 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t0, binop(Iop_Xor64, |
| binop(Iop_Sub64, |
| binop(Iop_And64, |
| binop(Iop_Shr64, |
| getIReg(ra), |
| mkU8(imm0)), |
| mkU64(1)), |
| mkU64(1)), |
| mkU64(-1ULL))); |
| assign(t2, |
| binop(Iop_Or64, |
| binop(Iop_And64, |
| binop(Iop_Or64, |
| binop(Iop_Shr64, |
| getIReg(ra), |
| mkU8(imm)), |
| binop(Iop_Shl64, |
| getIReg(ra), |
| mkU8(64 - imm))), |
| mkU64(mask)), |
| binop(Iop_And64, |
| mkexpr(t0), |
| mkU64(~mask)))); |
| |
| MARK_REG_WB(rd, t2); |
| } |
| break; |
| case 34: /* "bfextu" */ |
| { |
| ULong imm0 = decoded[n].operand_values[3]; |
| ULong mask = 0; |
| t2 = newTemp(Ity_I64); |
| mask = ((-1ULL) ^ ((-1ULL << ((imm0 - imm) & 63)) << 1)); |
| |
| assign(t2, |
| binop(Iop_And64, |
| binop(Iop_Or64, |
| binop(Iop_Shr64, |
| getIReg(ra), |
| mkU8(imm)), |
| binop(Iop_Shl64, |
| getIReg(ra), |
| mkU8(64 - imm))), |
| mkU64(mask))); |
| MARK_REG_WB(rd, t2); |
| } |
| break; |
| case 35: /* "bfins" */ |
| { |
| ULong mask; |
| ULong imm0 = decoded[n].operand_values[3]; |
| t0 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| if (imm <= imm0) |
| { |
| mask = ((-1ULL << imm) ^ ((-1ULL << imm0) << 1)); |
| } |
| else |
| { |
| mask = ((-1ULL << imm) | (-1ULL >> (63 - imm0))); |
| } |
| |
| assign(t0, binop(Iop_Or64, |
| binop(Iop_Shl64, |
| getIReg(ra), |
| mkU8(imm)), |
| binop(Iop_Shr64, |
| getIReg(ra), |
| mkU8(64 - imm)))); |
| |
| assign(t2, binop(Iop_Or64, |
| binop(Iop_And64, |
| mkexpr(t0), |
| mkU64(mask)), |
| binop(Iop_And64, |
| getIReg(rd), |
| mkU64(~mask)))); |
| |
| MARK_REG_WB(rd, t2); |
| } |
| break; |
| case 36: /* "bgez" */ |
| /* Fall-through */ |
| case 37: /* "bgezt" */ |
| bstmt = dis_branch(binop(Iop_CmpEQ64, |
| binop(Iop_And64, |
| getIReg(ra), |
| mkU64(0x8000000000000000ULL)), |
| mkU64(0x0)), |
| imm); |
| break; |
| case 38: /* "bgtz" */ |
| /* Fall-through */ |
| case 39: |
| /* "bgtzt" */ |
| bstmt = dis_branch(unop(Iop_Not1, |
| binop(Iop_CmpLE64S, |
| getIReg(ra), |
| mkU64(0))), |
| imm); |
| break; |
| case 40: /* "blbc" */ |
| /* Fall-through */ |
| case 41: /* "blbct" */ |
| bstmt = dis_branch(unop(Iop_64to1, |
| unop(Iop_Not64, getIReg(ra))), |
| imm); |
| |
| break; |
| case 42: /* "blbs" */ |
| /* Fall-through */ |
| case 43: |
| /* "blbst" */ |
| bstmt = dis_branch(unop(Iop_64to1, |
| getIReg(ra)), |
| imm); |
| break; |
| case 44: /* "blez" */ |
| bstmt = dis_branch(binop(Iop_CmpLE64S, getIReg(ra), |
| mkU64(0)), |
| imm); |
| break; |
| case 45: /* "blezt" */ |
| bstmt = dis_branch(binop(Iop_CmpLE64S, getIReg(ra), |
| mkU64(0)), |
| imm); |
| break; |
| case 46: /* "bltz" */ |
| bstmt = dis_branch(binop(Iop_CmpLT64S, getIReg(ra), |
| mkU64(0)), |
| imm); |
| break; |
| case 47: /* "bltzt" */ |
| bstmt = dis_branch(binop(Iop_CmpLT64S, getIReg(ra), |
| mkU64(0)), |
| imm); |
| break; |
| case 48: /* "bnez" */ |
| /* Fall-through */ |
| case 49: |
| /* "bnezt" */ |
| bstmt = dis_branch(binop(Iop_CmpNE64, getIReg(ra), |
| mkU64(0)), |
| imm); |
| break; |
| case 50: /* "clz" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_Clz64, getIReg(ra))); |
| |
| MARK_REG_WB(rd, t2); |
| break; |
| case 51: /* "cmoveqz rd, ra, rb" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, IRExpr_ITE(binop(Iop_CmpEQ64, getIReg(ra), mkU64(0)), |
| getIReg(rb), getIReg(rd))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 52: /* "cmovnez" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, IRExpr_ITE(binop(Iop_CmpEQ64, getIReg(ra), mkU64(0)), |
| getIReg(rd), getIReg(rb))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 53: /* "cmpeq" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_1Uto64, binop(Iop_CmpEQ64, |
| getIReg(ra), getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| |
| case 54: /* "cmpeqi" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_1Uto64, binop(Iop_CmpEQ64, |
| getIReg(ra), |
| mkU64(extend_s_8to64(imm))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 55: /* "cmpexch" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| |
| assign(t1, getIReg(rb)); |
| stmt( IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t2, Iend_LE, |
| getIReg(ra), |
| NULL, binop(Iop_Add64, |
| getIReg(70), |
| getIReg(71)), |
| NULL, mkexpr(t1)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 56: /* "cmpexch4" */ |
| t1 = newTemp(Ity_I32); |
| t2 = newTemp(Ity_I64); |
| t3 = newTemp(Ity_I32); |
| |
| assign(t1, narrowTo(Ity_I32, getIReg(rb))); |
| stmt( IRStmt_CAS(mkIRCAS(IRTemp_INVALID, t3, Iend_LE, |
| getIReg(ra), |
| NULL, |
| narrowTo(Ity_I32, binop(Iop_Add64, |
| getIReg(70), |
| getIReg(71))), |
| NULL, |
| mkexpr(t1)))); |
| assign(t2, unop(Iop_32Uto64, mkexpr(t3))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 57: /* "cmples" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_1Uto64, |
| binop(Iop_CmpLE64S, getIReg(ra), getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 58: /* "cmpleu" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_1Uto64, |
| binop(Iop_CmpLE64U, getIReg(ra), getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 59: /* "cmplts" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_1Uto64, |
| binop(Iop_CmpLT64S, getIReg(ra), getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 60: /* "cmpltsi" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_1Uto64, |
| binop(Iop_CmpLT64S, |
| getIReg(ra), |
| mkU64(extend_s_8to64(imm))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 61: |
| |
| /* "cmpltu" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_1Uto64, |
| binop(Iop_CmpLT64U, getIReg(ra), getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| |
| |
| break; |
| case 62: /* "cmpltui" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_1Uto64, |
| binop(Iop_CmpLT64U, |
| getIReg(ra), |
| mkU64(imm)))); |
| MARK_REG_WB(rd, t2); |
| |
| |
| break; |
| case 63: /* "cmpne" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_1Uto64, |
| binop(Iop_CmpNE64, getIReg(ra), getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| |
| |
| break; |
| case 64: |
| /* Fall-through */ |
| case 65: |
| /* Fall-through */ |
| case 66: |
| /* Fall-through */ |
| case 67: |
| /* Fall-through */ |
| case 68: |
| /* Fall-through */ |
| case 69: |
| /* Fall-through */ |
| case 70: |
| /* Fall-through */ |
| case 71: |
| /* Fall-through */ |
| case 72: |
| use_dirty_helper = 1; |
| break; |
| case 73: /* "ctz" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_Ctz64, getIReg(ra))); |
| |
| MARK_REG_WB(rd, t2); |
| |
| |
| break; |
| case 74: /* "dblalign" */ |
| t0 = newTemp(Ity_I64); |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| |
| /* t0 is the bit shift amount */ |
| assign(t0, binop(Iop_Shl64, |
| binop(Iop_And64, |
| getIReg(rb), |
| mkU64(7)), |
| mkU8(3))); |
| assign(t1, binop(Iop_Sub64, |
| mkU64(64), |
| mkexpr(t0))); |
| |
| assign(t2, binop(Iop_Or64, |
| binop(Iop_Shl64, |
| getIReg(ra), |
| unop(Iop_64to8, mkexpr(t1))), |
| binop(Iop_Shr64, |
| getIReg(rd), |
| unop(Iop_64to8, mkexpr(t0))))); |
| |
| MARK_REG_WB(rd, t2); |
| break; |
| case 75: |
| /* Fall-through */ |
| case 76: |
| /* Fall-through */ |
| case 77: |
| /* Fall-through */ |
| case 78: |
| /* Fall-through */ |
| case 79: |
| use_dirty_helper = 1; |
| break; |
| case 80: /* "exch" */ |
| t2 = newTemp(Ity_I64); |
| stmt( IRStmt_CAS( |
| mkIRCAS(IRTemp_INVALID, |
| t2, |
| Iend_LE, |
| getIReg(ra), |
| NULL, |
| mkU64(0x0), |
| NULL, |
| getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 81: /* "exch4 rd, ra, rb" */ |
| t0 = newTemp(Ity_I32); |
| t2 = newTemp(Ity_I64); |
| stmt( IRStmt_CAS( |
| mkIRCAS(IRTemp_INVALID, |
| t0, |
| Iend_LE, |
| getIReg(ra), |
| NULL, |
| mkU32(0x0), |
| NULL, |
| narrowTo(Ity_I32, |
| getIReg(rb))))); |
| assign(t2, unop(Iop_32Sto64, mkexpr(t0))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 82: |
| /* Fall-through */ |
| case 83: |
| /* Fall-through */ |
| case 84: |
| /* Fall-through */ |
| case 85: |
| /* Fall-through */ |
| case 86: |
| /* Fall-through */ |
| case 87: |
| /* Fall-through */ |
| case 88: |
| /* Fall-through */ |
| case 89: |
| use_dirty_helper = 1; |
| break; |
| case 90: /* "fetchadd" */ |
| t2 = newTemp(Ity_I64); |
| stmt( IRStmt_CAS( |
| mkIRCAS(IRTemp_INVALID, |
| t2, |
| Iend_LE, |
| getIReg(ra), |
| NULL, |
| // fetchadd=3 |
| mkU64(0x3), |
| NULL, |
| getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 91: /* "fetchadd4" */ |
| t0 = newTemp(Ity_I32); |
| t2 = newTemp(Ity_I64); |
| stmt( IRStmt_CAS( |
| mkIRCAS(IRTemp_INVALID, |
| t0, |
| Iend_LE, |
| getIReg(ra), |
| NULL, |
| // fetchadd=3 |
| mkU32(0x3), |
| NULL, |
| narrowTo(Ity_I32, |
| getIReg(rb))))); |
| assign(t2, unop(Iop_32Sto64, mkexpr(t0))); |
| MARK_REG_WB(rd, t2); |
| |
| break; |
| case 92: /* "fetchaddgez" */ |
| t2 = newTemp(Ity_I64); |
| stmt( IRStmt_CAS( |
| mkIRCAS(IRTemp_INVALID, |
| t2, |
| Iend_LE, |
| getIReg(ra), |
| NULL, |
| // fetchaddgez=5 |
| mkU64(0x5), |
| NULL, |
| getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 93: /* "fetchaddgez4" */ |
| t0 = newTemp(Ity_I32); |
| t2 = newTemp(Ity_I64); |
| stmt( IRStmt_CAS( |
| mkIRCAS(IRTemp_INVALID, |
| t0, |
| Iend_LE, |
| getIReg(ra), |
| NULL, |
| // fetchaddgez=5 |
| mkU32(0x5), |
| NULL, |
| narrowTo(Ity_I32, |
| getIReg(rb))))); |
| assign(t2, unop(Iop_32Sto64, mkexpr(t0))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 94: /* "fetchand\n") */ |
| t2 = newTemp(Ity_I64); |
| stmt( IRStmt_CAS( |
| mkIRCAS(IRTemp_INVALID, |
| t2, |
| Iend_LE, |
| getIReg(ra), |
| NULL, |
| mkU64(0x2), |
| NULL, |
| getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 95: |
| /* mkIRCAS. |
| 0: xch### 1: cmpexch###, |
| 2: fetchand## 3: fetchadd## |
| 4: fetchor## 5: fetchaddgez |
| */ |
| /* "fetchand4" */ |
| t0 = newTemp(Ity_I32); |
| t2 = newTemp(Ity_I64); |
| stmt( IRStmt_CAS( |
| mkIRCAS(IRTemp_INVALID, |
| t0, |
| Iend_LE, |
| getIReg(ra), |
| NULL, |
| mkU32(0x2), |
| NULL, |
| narrowTo(Ity_I32, |
| getIReg(rb))))); |
| assign(t2, unop(Iop_32Sto64, mkexpr(t0))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 96: /* "fetchor" */ |
| t2 = newTemp(Ity_I64); |
| stmt( IRStmt_CAS( |
| mkIRCAS(IRTemp_INVALID, |
| t2, |
| Iend_LE, |
| getIReg(ra), |
| NULL, |
| mkU64(0x4), |
| NULL, |
| getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 97: /* "fetchor4" */ |
| t0 = newTemp(Ity_I32); |
| t2 = newTemp(Ity_I64); |
| stmt( IRStmt_CAS( |
| mkIRCAS(IRTemp_INVALID, |
| t0, |
| Iend_LE, |
| getIReg(ra), |
| NULL, |
| mkU32(0x4), |
| NULL, |
| narrowTo(Ity_I32, |
| getIReg(rb))))); |
| assign(t2, unop(Iop_32Sto64, mkexpr(t0))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 98: |
| /* Fall-through */ |
| case 99: |
| /* Fall-through */ |
| case 100: |
| use_dirty_helper = 1; |
| break; |
| case 101: /* "fnop" Ignore */ |
| break; |
| case 102: |
| /* Fall-through */ |
| case 103: |
| /* Fall-through */ |
| case 104: |
| /* Fall-through */ |
| case 105: |
| /* Fall-through */ |
| case 106: |
| /* Fall-through */ |
| case 107: |
| /* Fall-through */ |
| case 108: |
| use_dirty_helper = 1; |
| break; |
| case 109: |
| /* Fall-through */ |
| case 110: |
| /* Fall-through */ |
| case 111: |
| use_dirty_helper = 1; |
| break; |
| case 112: /* "iret" */ |
| next = mkU64(guest_PC_curr_instr + 8); |
| jumpkind = Ijk_Ret; |
| break; |
| case 113: /* "j" */ |
| next = mkU64(imm); |
| /* set steering address. */ |
| steering_pc = imm; |
| jumpkind = Ijk_Boring; |
| break; |
| case 114: |
| t2 = newTemp(Ity_I64); |
| assign(t2, mkU64(guest_PC_curr_instr + 8)); |
| /* set steering address. */ |
| steering_pc = imm; |
| next = mkU64(imm); |
| jumpkind = Ijk_Call; |
| MARK_REG_WB(55, t2); |
| break; |
| case 115: /* "jalr" */ |
| /* Fall-through */ |
| case 116: /* "jalrp" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t1, getIReg(ra)); |
| assign(t2, mkU64(guest_PC_curr_instr + 8)); |
| next = mkexpr(t1); |
| jumpkind = Ijk_Call; |
| MARK_REG_WB(55, t2); |
| break; |
| case 117: /* "jr" */ |
| /* Fall-through */ |
| case 118: /* "jrp" */ |
| next = getIReg(ra); |
| jumpkind = Ijk_Boring; |
| break; |
| case 119: /* "ld" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, load(Ity_I64, (getIReg(ra)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 120: /* "ld1s" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_8Sto64, |
| load(Ity_I8, (getIReg(ra))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 121: /* "ld1s_add" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t1, binop(Iop_Add64, getIReg(ra), mkU64(imm))); |
| assign(t2, unop(Iop_8Sto64, |
| load(Ity_I8, (getIReg(ra))))); |
| MARK_REG_WB(ra, t1); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 122: /* "ld1u" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_8Uto64, |
| load(Ity_I8, (getIReg(ra))))); |
| MARK_REG_WB(rd, t2); |
| |
| break; |
| case 123: /* "ld1u_add" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t1, binop(Iop_Add64, getIReg(ra), mkU64(imm))); |
| assign(t2, unop(Iop_8Uto64, |
| load(Ity_I8, (getIReg(ra))))); |
| MARK_REG_WB(ra, t1); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 124: /* "ld2s" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_16Sto64, |
| load(Ity_I16, getIReg(ra)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 125: /* "ld2s_add" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t1, binop(Iop_Add64, getIReg(ra), mkU64(imm))); |
| assign(t2, unop(Iop_16Sto64, |
| load(Ity_I16, getIReg(ra)))); |
| MARK_REG_WB(rd, t2); |
| MARK_REG_WB(ra, t1); |
| break; |
| case 126: /* "ld2u" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_16Uto64, |
| load(Ity_I16, getIReg(ra)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 127: /* "ld2u_add" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t1, binop(Iop_Add64, getIReg(ra), mkU64(imm))); |
| assign(t2, unop(Iop_16Uto64, |
| load(Ity_I16, getIReg(ra)))); |
| MARK_REG_WB(rd, t2); |
| MARK_REG_WB(ra, t1); |
| break; |
| case 128: /* "ld4s" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_32Sto64, |
| load(Ity_I32, (getIReg(ra))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 129: /* "ld4s_add" */ |
| t2 = newTemp(Ity_I64); |
| t1 = newTemp(Ity_I64); |
| assign(t1, binop(Iop_Add64, getIReg(ra), mkU64(imm))); |
| assign(t2, unop(Iop_32Sto64, |
| load(Ity_I32, (getIReg(ra))))); |
| MARK_REG_WB(rd, t2); |
| MARK_REG_WB(ra, t1); |
| break; |
| case 130: /* "ld4u" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_32Uto64, |
| load(Ity_I32, getIReg(ra)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 131: /* "ld4u_add" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t1, binop(Iop_Add64, getIReg(ra), mkU64(imm))); |
| assign(t2, unop(Iop_32Uto64, |
| load(Ity_I32, getIReg(ra)))); |
| MARK_REG_WB(ra, t1); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 132: /* "ld_add" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t1, load(Ity_I64, getIReg(ra))); |
| assign(t2, binop(Iop_Add64, getIReg(ra), mkU64(imm))); |
| MARK_REG_WB(ra, t2); |
| MARK_REG_WB(rd, t1); |
| break; |
| case 133: /* "ldna" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, load(Ity_I64, |
| binop(Iop_And64, |
| getIReg(ra), |
| unop(Iop_Not64, |
| mkU64(7))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 134: /* "ldna_add" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| |
| assign(t1, binop(Iop_Add64, getIReg(ra), mkU64(imm))); |
| assign(t2, load(Ity_I64, |
| binop(Iop_And64, |
| getIReg(ra), |
| unop(Iop_Not64, |
| mkU64(7))))); |
| MARK_REG_WB(ra, t1); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 135: /* "ldnt" */ |
| /* Valgrind IR has no Non-Temp load. Use normal load. */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, load(Ity_I64, (getIReg(ra)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 136: /* "ldnt1s" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_8Sto64, |
| load(Ity_I8, (getIReg(ra))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 137: /* "ldnt1s_add" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_8Sto64, |
| load(Ity_I8, (getIReg(ra))))); |
| assign(t1, binop(Iop_Add64, getIReg(ra), mkU64(imm))); |
| MARK_REG_WB(ra, t1); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 138: /* "ldnt1u" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_8Uto64, |
| load(Ity_I8, (getIReg(ra))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 139: /* "ldnt1u_add" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| |
| assign(t1, binop(Iop_Add64, getIReg(ra), mkU64(imm))); |
| assign(t2, unop(Iop_8Uto64, |
| load(Ity_I8, (getIReg(ra))))); |
| |
| MARK_REG_WB(ra, t1); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 140: /* "ldnt2s" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_16Sto64, |
| load(Ity_I16, getIReg(ra)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 141: /* "ldnt2s_add" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_16Sto64, |
| load(Ity_I16, getIReg(ra)))); |
| assign(t1, binop(Iop_Add64, getIReg(ra), mkU64(imm))); |
| MARK_REG_WB(ra, t1); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 142: /* "ldnt2u" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_16Uto64, |
| load(Ity_I16, getIReg(ra)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 143: /* "ldnt2u_add" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_16Uto64, |
| load(Ity_I16, getIReg(ra)))); |
| assign(t1, binop(Iop_Add64, getIReg(ra), mkU64(imm))); |
| MARK_REG_WB(ra, t1); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 144: /* "ldnt4s" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_32Sto64, |
| load(Ity_I32, (getIReg(ra))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 145: /* "ldnt4s_add" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_32Sto64, |
| load(Ity_I32, (getIReg(ra))))); |
| assign(t1, binop(Iop_Add64, getIReg(ra), mkU64(imm))); |
| MARK_REG_WB(rd, t2); |
| MARK_REG_WB(ra, t1); |
| break; |
| case 146: /* "ldnt4u" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_32Uto64, |
| load(Ity_I32, getIReg(ra)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 147: /* "ldnt4u_add" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_32Uto64, |
| load(Ity_I32, getIReg(ra)))); |
| assign(t1, binop(Iop_Add64, getIReg(ra), mkU64(imm))); |
| MARK_REG_WB(rd, t2); |
| MARK_REG_WB(ra, t1); |
| break; |
| case 148: /* "ldnt_add" */ |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t1, load(Ity_I64, getIReg(ra))); |
| assign(t2, binop(Iop_Add64, getIReg(ra), mkU64(imm))); |
| MARK_REG_WB(rd, t1); |
| MARK_REG_WB(ra, t2); |
| break; |
| case 149: /* "lnk" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, mkU64(guest_PC_curr_instr + 8)); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 150: /* "mf" */ |
| use_dirty_helper = 1; |
| break; |
| case 151: /* "mfspr" */ |
| t2 = newTemp(Ity_I64); |
| if (imm == 0x2780) { // Get Cmpexch value |
| assign(t2, getIReg(70)); |
| MARK_REG_WB(rd, t2); |
| } else if (imm == 0x2580) { // Get EX_CONTEXT_0_0 |
| assign(t2, getIReg(576 / 8)); |
| MARK_REG_WB(rd, t2); |
| } else if (imm == 0x2581) { // Get EX_CONTEXT_0_1 |
| assign(t2, getIReg(584 / 8)); |
| MARK_REG_WB(rd, t2); |
| } else |
| use_dirty_helper = 1; |
| break; |
| case 152: /* "mm" */ |
| use_dirty_helper = 1; |
| break; |
| case 153: /* "mnz" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_And64, |
| unop(Iop_1Sto64, binop(Iop_CmpNE64, |
| getIReg(ra), |
| mkU64(0))), |
| getIReg(rb))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 154: /* "mtspr imm, ra" */ |
| if (imm == 0x2780) // Set Cmpexch value |
| putIReg(70, getIReg(ra)); |
| else if (imm == 0x2580) // set EX_CONTEXT_0_0 |
| putIReg(576/8, getIReg(ra)); |
| else if (imm == 0x2581) // set EX_CONTEXT_0_1 |
| putIReg(584/8, getIReg(ra)); |
| else |
| use_dirty_helper = 1; |
| break; |
| case 155: /* "mul_hs_hs" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_MullS32, |
| unop(Iop_64to32, |
| binop(Iop_Shr64, |
| getIReg(ra), |
| mkU8(32))), |
| unop(Iop_64to32, |
| binop(Iop_Shr64, |
| getIReg(rb), |
| mkU8(32))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 156: /* "mul_hs_hu" */ |
| t0 = newTemp(Ity_I64); |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| t3 = newTemp(Ity_I64); |
| |
| assign(t0, unop(Iop_32Sto64, |
| unop(Iop_64to32, |
| binop(Iop_Shr64, getIReg(ra), mkU8(32))))); |
| assign(t1, binop(Iop_MullU32, |
| unop(Iop_64to32, mkexpr(t0)), |
| unop(Iop_64to32, binop(Iop_Shr64, getIReg(rb), mkU8(32))))); |
| assign(t3, binop(Iop_MullU32, |
| unop(Iop_64to32, binop(Iop_Shr64, |
| mkexpr(t0), |
| mkU8(32))), |
| unop(Iop_64to32, binop(Iop_Shr64, getIReg(rb), mkU8(32))))); |
| assign(t2, binop(Iop_Add64, |
| mkexpr(t1), |
| binop(Iop_Shl64, |
| mkexpr(t3), |
| mkU8(32)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 157: /* "mul_hs_ls" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_MullS32, |
| unop(Iop_64to32, |
| binop(Iop_Shr64, |
| getIReg(ra), |
| mkU8(32))), |
| unop(Iop_64to32, |
| getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 158: /* "mul_hs_lu" */ |
| t0 = newTemp(Ity_I64); |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| t3 = newTemp(Ity_I64); |
| |
| assign(t0, unop(Iop_32Sto64, |
| unop(Iop_64to32, |
| binop(Iop_Shr64, getIReg(ra), mkU8(32))))); |
| assign(t1, binop(Iop_MullU32, |
| unop(Iop_64to32, mkexpr(t0)), |
| unop(Iop_64to32, getIReg(rb)))); |
| assign(t3, binop(Iop_MullU32, |
| unop(Iop_64to32, binop(Iop_Shr64, |
| mkexpr(t0), |
| mkU8(32))), |
| unop(Iop_64to32, getIReg(rb)))); |
| assign(t2, binop(Iop_Add64, |
| mkexpr(t1), |
| binop(Iop_Shl64, |
| mkexpr(t3), |
| mkU8(32)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 159: /* "mul_hu_hu" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_MullU32, |
| unop(Iop_64to32, |
| binop(Iop_Shr64, |
| getIReg(ra), |
| mkU8(32))), |
| unop(Iop_64to32, |
| binop(Iop_Shr64, |
| getIReg(rb), |
| mkU8(32))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 160: /* "mul_hu_ls" */ |
| t0 = newTemp(Ity_I64); |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| t3 = newTemp(Ity_I64); |
| |
| assign(t0, unop(Iop_32Sto64, |
| unop(Iop_64to32, |
| getIReg(ra)))); |
| |
| assign(t1, binop(Iop_MullU32, |
| unop(Iop_64to32, mkexpr(t0)), |
| unop(Iop_64to32, binop(Iop_Shr64, getIReg(rb), mkU8(32))))); |
| assign(t3, binop(Iop_MullU32, |
| unop(Iop_64to32, binop(Iop_Shr64, |
| mkexpr(t0), |
| mkU8(32))), |
| unop(Iop_64to32, binop(Iop_Shr64, getIReg(rb), mkU8(32))))); |
| assign(t2, binop(Iop_Add64, |
| mkexpr(t1), |
| binop(Iop_Shl64, |
| mkexpr(t3), |
| mkU8(32)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 161: /* "mul_hu_lu" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_MullU32, |
| unop(Iop_64to32, |
| binop(Iop_Shr64, |
| getIReg(ra), |
| mkU8(32))), |
| unop(Iop_64to32, |
| getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 162: /* "mul_ls_ls" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_MullS32, |
| unop(Iop_64to32, getIReg(ra)), |
| unop(Iop_64to32, getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 163: /* "mul_ls_lu" */ |
| t0 = newTemp(Ity_I64); |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| t3 = newTemp(Ity_I64); |
| |
| assign(t0, unop(Iop_32Sto64, |
| unop(Iop_64to32, getIReg(ra)))); |
| assign(t1, binop(Iop_MullU32, |
| unop(Iop_64to32, mkexpr(t0)), |
| unop(Iop_64to32, getIReg(rb)))); |
| assign(t3, binop(Iop_MullU32, |
| unop(Iop_64to32, binop(Iop_Shr64, |
| mkexpr(t0), |
| mkU8(32))), |
| unop(Iop_64to32, getIReg(rb)))); |
| assign(t2, binop(Iop_Add64, |
| mkexpr(t1), |
| binop(Iop_Shl64, |
| mkexpr(t3), |
| mkU8(32)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 164: /* "mul_lu_lu" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_MullU32, |
| unop(Iop_64to32, getIReg(ra)), |
| unop(Iop_64to32, getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 165: /* "mula_hs_hs" */ |
| t0 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| |
| assign(t0, binop(Iop_MullS32, |
| unop(Iop_64to32, binop(Iop_Shr64, |
| getIReg(ra), mkU8(32))), |
| unop(Iop_64to32, binop(Iop_Shr64, |
| getIReg(rb), mkU8(32))))); |
| assign(t2, binop(Iop_Add64, getIReg(rd), mkexpr(t0))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 166: /* "mula_hs_hu" */ |
| t0 = newTemp(Ity_I64); |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| t3 = newTemp(Ity_I64); |
| t4 = newTemp(Ity_I64); |
| assign(t0, unop(Iop_32Sto64, |
| unop(Iop_64to32, |
| binop(Iop_Shr64, getIReg(ra), mkU8(32))))); |
| assign(t1, binop(Iop_MullU32, |
| unop(Iop_64to32, mkexpr(t0)), |
| unop(Iop_64to32, binop(Iop_Shr64, |
| getIReg(rb), mkU8(32))))); |
| assign(t3, binop(Iop_MullU32, |
| unop(Iop_64to32, binop(Iop_Shr64, |
| mkexpr(t0), |
| mkU8(32))), |
| unop(Iop_64to32, binop(Iop_Shr64, |
| getIReg(rb), mkU8(32))))); |
| assign(t2, binop(Iop_Add64, |
| mkexpr(t1), |
| binop(Iop_Shl64, |
| mkexpr(t3), |
| mkU8(32)))); |
| assign(t4, binop(Iop_Add64, getIReg(rd), mkexpr(t2))); |
| MARK_REG_WB(rd, t4); |
| break; |
| case 167: /* "mula_hs_ls" */ |
| t2 = newTemp(Ity_I64); |
| t4 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_MullS32, |
| unop(Iop_64to32, |
| binop(Iop_Shr64, |
| getIReg(ra), |
| mkU8(32))), |
| unop(Iop_64to32, |
| getIReg(rb)))); |
| assign(t4, binop(Iop_Add64, getIReg(rd), mkexpr(t2))); |
| MARK_REG_WB(rd, t4); |
| break; |
| case 168: /* "mula_hs_lu" */ |
| t0 = newTemp(Ity_I64); |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| t3 = newTemp(Ity_I64); |
| t4 = newTemp(Ity_I64); |
| assign(t0, unop(Iop_32Sto64, |
| unop(Iop_64to32, |
| binop(Iop_Shr64, getIReg(ra), mkU8(32))))); |
| assign(t1, binop(Iop_MullU32, |
| unop(Iop_64to32, mkexpr(t0)), |
| unop(Iop_64to32, getIReg(rb)))); |
| assign(t3, binop(Iop_MullU32, |
| unop(Iop_64to32, binop(Iop_Shr64, |
| mkexpr(t0), |
| mkU8(32))), |
| unop(Iop_64to32, getIReg(rb)))); |
| assign(t2, binop(Iop_Add64, |
| mkexpr(t1), |
| binop(Iop_Shl64, |
| mkexpr(t3), |
| mkU8(32)))); |
| assign(t4, binop(Iop_Add64, getIReg(rd), mkexpr(t2))); |
| MARK_REG_WB(rd, t4); |
| break; |
| case 169: /* "mula_hu_hu" */ |
| use_dirty_helper = 1; |
| break; |
| case 170: /* "mula_hu_ls" */ |
| use_dirty_helper = 1; |
| break; |
| case 171: /* "mula_hu_lu" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Add64, |
| binop(Iop_MullU32, |
| unop(Iop_64to32, |
| binop(Iop_Shr64, |
| getIReg(ra), |
| mkU8(32))), |
| unop(Iop_64to32, |
| getIReg(rb))), |
| getIReg(rd))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 172: /* "mula_ls_ls" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Add64, |
| getIReg(rd), |
| binop(Iop_MullS32, |
| unop(Iop_64to32, getIReg(ra)), |
| unop(Iop_64to32, getIReg(rb))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 173: /* "mula_ls_lu" */ |
| t0 = newTemp(Ity_I64); |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| t3 = newTemp(Ity_I64); |
| |
| assign(t0, unop(Iop_32Sto64, |
| unop(Iop_64to32, getIReg(ra)))); |
| assign(t1, binop(Iop_MullU32, |
| unop(Iop_64to32, mkexpr(t0)), |
| unop(Iop_64to32, getIReg(rb)))); |
| assign(t3, binop(Iop_MullU32, |
| unop(Iop_64to32, binop(Iop_Shr64, |
| mkexpr(t0), |
| mkU8(32))), |
| unop(Iop_64to32, getIReg(rb)))); |
| assign(t2, binop(Iop_Add64, |
| getIReg(rd), |
| binop(Iop_Add64, |
| mkexpr(t1), |
| binop(Iop_Shl64, |
| mkexpr(t3), |
| mkU8(32))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 174: /* "mula_lu_lu" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Add64, |
| binop(Iop_MullU32, |
| unop(Iop_64to32, |
| getIReg(ra)), |
| unop(Iop_64to32, |
| getIReg(rb))), |
| getIReg(rd))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 175: /* "mulax" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_32Sto64, |
| unop(Iop_64to32, |
| binop(Iop_Add64, |
| getIReg(rd), |
| binop(Iop_MullU32, |
| narrowTo(Ity_I32, getIReg(ra)), |
| narrowTo(Ity_I32, getIReg(rb))))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 176: /* "mulx" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_32Sto64, |
| unop(Iop_64to32, |
| binop(Iop_MullU32, |
| narrowTo(Ity_I32, getIReg(ra)), |
| narrowTo(Ity_I32, getIReg(rb)))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 177: /* "mz" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_And64, |
| unop(Iop_1Sto64, binop(Iop_CmpEQ64, |
| getIReg(ra), |
| mkU64(0))), |
| getIReg(rb))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 178: /* "nap" */ |
| break; |
| case 179: /* "nop" */ |
| break; |
| case 180: /* "nor" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_Not64, |
| binop(Iop_Or64, |
| getIReg(ra), |
| getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 181: /* "or" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Or64, |
| getIReg(ra), |
| getIReg(rb))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 182: /* "ori" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Or64, |
| getIReg(ra), |
| mkU64(imm))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 183: |
| /* Fall-through */ |
| case 184: |
| /* Fall-through */ |
| case 185: |
| use_dirty_helper = 1; |
| break; |
| case 186: /* "rotl" */ |
| t0 = newTemp(Ity_I64); |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t0, binop(Iop_Shl64, |
| getIReg(ra), |
| unop(Iop_64to8, getIReg(rb)))); |
| assign(t1, binop(Iop_Shr64, |
| getIReg(ra), |
| unop(Iop_64to8, binop(Iop_Sub64, |
| mkU64(0), |
| getIReg(rb))))); |
| assign(t2, binop(Iop_Or64, mkexpr(t0), mkexpr(t1))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 187: /* "rotli" */ |
| t0 = newTemp(Ity_I64); |
| t1 = newTemp(Ity_I64); |
| t2 = newTemp(Ity_I64); |
| assign(t0, binop(Iop_Shl64, |
| getIReg(ra), |
| mkU8(imm))); |
| assign(t1, binop(Iop_Shr64, |
| getIReg(ra), |
| mkU8(0 - imm))); |
| assign(t2, binop(Iop_Or64, mkexpr(t0), mkexpr(t1))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 188: /* "shl" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Shl64, |
| getIReg(ra), |
| unop(Iop_64to8, getIReg(rb)))); |
| MARK_REG_WB(rd, t2); |
| |
| break; |
| case 189: /* "shl16insli" */ |
| t2 = newTemp(Ity_I64); |
| t3 = newTemp(Ity_I64); |
| assign(t3, binop(Iop_Shl64, getIReg(ra), mkU8(16))); |
| imm &= 0xFFFFULL; |
| if (imm & 0x8000) |
| { |
| t4 = newTemp(Ity_I64); |
| assign(t4, mkU64(imm)); |
| assign(t2, binop(Iop_Add64, mkexpr(t3), mkexpr(t4))); |
| } |
| else |
| { |
| assign(t2, binop(Iop_Add64, mkexpr(t3), mkU64(imm))); |
| } |
| MARK_REG_WB(rd, t2); |
| |
| break; |
| case 190: /* "shl1add" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Add64, |
| binop(Iop_Shl64, |
| getIReg(ra), mkU8(1)), |
| getIReg(rb))); |
| |
| MARK_REG_WB(rd, t2); |
| break; |
| case 191: /* "shl1addx" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, |
| unop(Iop_32Sto64, |
| unop(Iop_64to32, |
| binop(Iop_Add64, |
| binop(Iop_Shl64, |
| getIReg(ra), mkU8(1)), |
| getIReg(rb))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 192: /* "shl2add" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Add64, |
| binop(Iop_Shl64, |
| getIReg(ra), mkU8(2)), |
| getIReg(rb))); |
| |
| MARK_REG_WB(rd, t2); |
| |
| break; |
| case 193: /* "shl2addx" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, |
| unop(Iop_32Sto64, |
| unop(Iop_64to32, |
| binop(Iop_Add64, |
| binop(Iop_Shl64, |
| getIReg(ra), mkU8(2)), |
| getIReg(rb))))); |
| MARK_REG_WB(rd, t2); |
| |
| break; |
| case 194: /* "shl3add" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Add64, |
| binop(Iop_Shl64, |
| getIReg(ra), mkU8(3)), |
| getIReg(rb))); |
| |
| MARK_REG_WB(rd, t2); |
| break; |
| case 195: /* "shl3addx" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, |
| unop(Iop_32Sto64, |
| unop(Iop_64to32, |
| binop(Iop_Add64, |
| binop(Iop_Shl64, |
| getIReg(ra), mkU8(3)), |
| getIReg(rb))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 196: /* "shli" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Shl64, getIReg(ra), |
| mkU8(imm))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 197: /* "shlx" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_32Sto64, |
| binop(Iop_Shl32, |
| narrowTo(Ity_I32, getIReg(ra)), |
| narrowTo(Ity_I8, getIReg(rb))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 198: /* "shlxi" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, signExtend(binop(Iop_Shl32, |
| narrowTo(Ity_I32, getIReg(ra)), |
| mkU8(imm)), |
| 32)); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 199: /* "shrs" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Sar64, getIReg(ra), |
| narrowTo(Ity_I8, getIReg(rb)))); |
| |
| MARK_REG_WB(rd, t2); |
| break; |
| case 200: /* "shrsi" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Sar64, getIReg(ra), |
| mkU8(imm))); |
| |
| MARK_REG_WB(rd, t2); |
| break; |
| case 201: /* "shru" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Shr64, |
| getIReg(ra), |
| narrowTo(Ity_I8, (getIReg(rb))))); |
| |
| MARK_REG_WB(rd, t2); |
| break; |
| case 202: /* "shrui" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Shr64, getIReg(ra), mkU8(imm))); |
| |
| MARK_REG_WB(rd, t2); |
| break; |
| case 203: /* "shrux" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_32Sto64, |
| (binop(Iop_Shr32, |
| narrowTo(Ity_I32, getIReg(ra)), |
| narrowTo(Ity_I8, getIReg(rb)))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 204: /* "shruxi" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_32Sto64, |
| (binop(Iop_Shr32, |
| narrowTo(Ity_I32, getIReg(ra)), |
| mkU8(imm))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 205: /* "shufflebytes" */ |
| use_dirty_helper = 1; |
| break; |
| case 206: /* "st" */ |
| store(getIReg(ra), getIReg(rb)); |
| break; |
| case 207: /* "st1" */ |
| store(getIReg(ra), narrowTo(Ity_I8, getIReg(rb))); |
| break; |
| case 208: /* "st1_add" */ |
| t2 = newTemp(Ity_I64); |
| store(getIReg(opd[0]), narrowTo(Ity_I8, getIReg(opd[1]))); |
| assign(t2, binop(Iop_Add64, getIReg(opd[0]), mkU64(opd[2]))); |
| MARK_REG_WB(opd[0], t2); |
| break; |
| case 209: /* "st2" */ |
| store(getIReg(ra), narrowTo(Ity_I16, getIReg(rb))); |
| break; |
| case 210: /* "st2_add" */ |
| t2 = newTemp(Ity_I64); |
| store(getIReg(opd[0]), narrowTo(Ity_I16, getIReg(opd[1]))); |
| assign(t2, binop(Iop_Add64, getIReg(opd[0]), mkU64(opd[2]))); |
| MARK_REG_WB(opd[0], t2); |
| break; |
| case 211: /* "st4" */ |
| store(getIReg(ra), narrowTo(Ity_I32, getIReg(rb))); |
| break; |
| case 212: /* "st4_add" */ |
| t2 = newTemp(Ity_I64); |
| store(getIReg(opd[0]), narrowTo(Ity_I32, getIReg(opd[1]))); |
| assign(t2, binop(Iop_Add64, getIReg(opd[0]), mkU64(opd[2]))); |
| MARK_REG_WB(opd[0], t2); |
| break; |
| case 213: /* "st_add" */ |
| t2 = newTemp(Ity_I64); |
| store(getIReg(opd[0]), getIReg(opd[1])); |
| assign(t2, binop(Iop_Add64, getIReg(opd[0]), mkU64(opd[2]))); |
| MARK_REG_WB(opd[0], t2); |
| break; |
| case 214: /* "stnt" */ |
| store(getIReg(ra), getIReg(rb)); |
| break; |
| case 215: /* "stnt1" */ |
| store(getIReg(ra), narrowTo(Ity_I8, getIReg(rb))); |
| break; |
| case 216: /* "stnt1_add" */ |
| t2 = newTemp(Ity_I64); |
| store(getIReg(opd[0]), narrowTo(Ity_I8, getIReg(opd[1]))); |
| assign(t2, binop(Iop_Add64, getIReg(opd[0]), mkU64(opd[2]))); |
| MARK_REG_WB(opd[0], t2); |
| break; |
| case 217: /* "stnt2" */ |
| store(getIReg(ra), narrowTo(Ity_I16, getIReg(rb))); |
| break; |
| case 218: /* "stnt2_add" */ |
| t2 = newTemp(Ity_I64); |
| store(getIReg(opd[0]), narrowTo(Ity_I16, getIReg(opd[1]))); |
| assign(t2, binop(Iop_Add64, getIReg(opd[0]), mkU64(opd[2]))); |
| MARK_REG_WB(opd[0], t2); |
| break; |
| case 219: /* "stnt4" */ |
| store(getIReg(ra), narrowTo(Ity_I32, getIReg(rb))); |
| break; |
| case 220: /* "stnt4_add" */ |
| t2 = newTemp(Ity_I64); |
| store(getIReg(opd[0]), narrowTo(Ity_I32, getIReg(opd[1]))); |
| assign(t2, binop(Iop_Add64, getIReg(opd[0]), mkU64(opd[2]))); |
| MARK_REG_WB(opd[0], t2); |
| break; |
| case 221: /* "stnt_add" */ |
| t2 = newTemp(Ity_I64); |
| store(getIReg(opd[0]), getIReg(opd[1])); |
| assign(t2, binop(Iop_Add64, getIReg(opd[0]), mkU64(opd[2]))); |
| MARK_REG_WB(opd[0], t2); |
| break; |
| case 222: /* "sub" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Sub64, getIReg(ra), |
| getIReg(rb))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 223: /* "subx" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, unop(Iop_32Sto64, |
| binop(Iop_Sub32, |
| narrowTo(Ity_I32, getIReg(ra)), |
| narrowTo(Ity_I32, getIReg(rb))))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 224: /* "subxsc" */ |
| use_dirty_helper = 1; |
| break; |
| case 225: /* "swint0" */ |
| vex_printf( "\n *** swint0 ***\n"); |
| vassert(0); |
| break; |
| case 226: /* "swint1" */ |
| next = mkU64(guest_PC_curr_instr + 8); |
| jumpkind = Ijk_Sys_syscall; |
| break; |
| case 227: /* "swint2" */ |
| vex_printf( "\n *** swint2 ***\n"); |
| vassert(0); |
| break; |
| case 228: /* "swint3" */ |
| vex_printf( "\n *** swint3 ***\n"); |
| vassert(0); |
| break; |
| case 229: |
| /* Fall-through */ |
| case 230: |
| /* Fall-through */ |
| case 231: |
| /* Fall-through */ |
| case 232: |
| /* Fall-through */ |
| case 233: |
| use_dirty_helper = 1; |
| break; |
| case 234: |
| opd[3] = V1EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| case 235: |
| /* Fall-through */ |
| case 236: |
| /* Fall-through */ |
| case 237: |
| use_dirty_helper = 1; |
| break; |
| case 238: /* "v1cmpeq" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_CmpEQ8x8, getIReg(ra), |
| getIReg(rb))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 239: /* "v1cmpeqi" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_CmpEQ8x8, getIReg(ra), |
| mkU64(imm))); |
| |
| MARK_REG_WB(rd, t2); |
| break; |
| case 240: |
| /* Fall-through */ |
| case 241: |
| /* Fall-through */ |
| case 242: |
| use_dirty_helper = 1; |
| break; |
| case 243: |
| opd[3] = V1EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| /* Fall-through */ |
| case 244: |
| use_dirty_helper = 1; |
| break; |
| case 245: |
| opd[3] = V1EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| case 246: /* "v1cmpne" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_CmpEQ8x8, |
| binop(Iop_CmpEQ8x8, getIReg(ra), |
| getIReg(rb)), |
| getIReg(63))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 247: |
| /* Fall-through */ |
| case 248: |
| /* Fall-through */ |
| case 249: |
| /* Fall-through */ |
| case 250: |
| /* Fall-through */ |
| case 251: |
| /* Fall-through */ |
| case 252: |
| /* Fall-through */ |
| case 253: |
| /* Fall-through */ |
| case 254: |
| /* Fall-through */ |
| case 255: |
| /* Fall-through */ |
| case 256: |
| /* Fall-through */ |
| case 257: |
| /* Fall-through */ |
| case 258: |
| /* Fall-through */ |
| case 259: |
| use_dirty_helper = 1; |
| break; |
| case 260: |
| opd[3] = V1EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| case 261: |
| use_dirty_helper = 1; |
| break; |
| case 262: |
| opd[3] = V1EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| case 263: |
| /* Fall-through */ |
| case 264: |
| /* Fall-through */ |
| case 265: |
| /* Fall-through */ |
| case 266: |
| /* Fall-through */ |
| case 267: |
| /* Fall-through */ |
| case 268: |
| /* Fall-through */ |
| case 269: |
| /* Fall-through */ |
| case 270: |
| use_dirty_helper = 1; |
| break; |
| case 271: |
| opd[3] = V1EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| case 272: |
| use_dirty_helper = 1; |
| break; |
| case 273: |
| opd[3] = V1EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| case 274: |
| use_dirty_helper = 1; |
| break; |
| case 275: /* "v1shrui" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Shr8x8, |
| getIReg(ra), |
| mkU64(imm))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 276: |
| /* Fall-through */ |
| case 277: |
| /* Fall-through */ |
| case 278: |
| use_dirty_helper = 1; |
| break; |
| case 279: |
| opd[3] = V2EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| case 280: |
| /* Fall-through */ |
| case 281: |
| /* Fall-through */ |
| case 282: |
| /* Fall-through */ |
| case 283: |
| use_dirty_helper = 1; |
| break; |
| case 284: |
| opd[3] = V2EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| case 285: |
| /* Fall-through */ |
| case 286: |
| /* Fall-through */ |
| case 287: |
| use_dirty_helper = 1; |
| break; |
| case 288: |
| opd[3] = V2EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| case 289: |
| use_dirty_helper = 1; |
| break; |
| case 290: |
| opd[3] = V2EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| case 291: |
| /* Fall-through */ |
| case 292: |
| /* Fall-through */ |
| case 293: |
| /* Fall-through */ |
| case 294: |
| /* Fall-through */ |
| case 295: |
| /* Fall-through */ |
| case 296: |
| use_dirty_helper = 1; |
| break; |
| case 297: |
| opd[3] = V2EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| case 298: |
| use_dirty_helper = 1; |
| break; |
| case 299: |
| opd[3] = V2EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| case 300: |
| /* Fall-through */ |
| case 301: |
| /* Fall-through */ |
| case 302: |
| /* Fall-through */ |
| case 303: |
| /* Fall-through */ |
| case 304: |
| /* Fall-through */ |
| case 305: |
| /* Fall-through */ |
| case 306: |
| /* Fall-through */ |
| case 307: |
| /* Fall-through */ |
| case 308: |
| /* Fall-through */ |
| case 309: |
| /* Fall-through */ |
| case 310: |
| /* Fall-through */ |
| case 311: |
| /* Fall-through */ |
| case 312: |
| use_dirty_helper = 1; |
| break; |
| case 313: |
| opd[3] = V2EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| case 314: |
| /* Fall-through */ |
| case 315: |
| use_dirty_helper = 1; |
| break; |
| case 316: |
| opd[3] = V2EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| case 317: |
| use_dirty_helper = 1; |
| break; |
| case 318: |
| opd[3] = V2EXP(opd[3]); |
| use_dirty_helper = 1; |
| break; |
| case 319: |
| /* Fall-through */ |
| case 320: |
| /* Fall-through */ |
| case 321: |
| /* Fall-through */ |
| case 322: |
| /* Fall-through */ |
| case 323: |
| use_dirty_helper = 1; |
| break; |
| case 324: /* "v4int_l" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Or64, |
| binop(Iop_Shl64, |
| getIReg(ra), |
| mkU8(32)), |
| binop(Iop_And64, |
| getIReg(rb), |
| mkU64(0xFFFFFFFF)))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 325: |
| /* Fall-through */ |
| case 326: |
| /* Fall-through */ |
| case 327: |
| /* Fall-through */ |
| case 328: |
| /* Fall-through */ |
| case 329: |
| /* Fall-through */ |
| case 330: |
| /* Fall-through */ |
| case 331: |
| use_dirty_helper = 1; |
| break; |
| case 332: /* "wh64" */ /* Ignore store hint */ |
| break; |
| case 333: /* "xor" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Xor64, |
| getIReg(ra), |
| getIReg(rb))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 334: /* "xori" */ |
| t2 = newTemp(Ity_I64); |
| assign(t2, binop(Iop_Xor64, |
| getIReg(ra), |
| mkU64(imm))); |
| MARK_REG_WB(rd, t2); |
| break; |
| case 335: /* "(null)" */ /* ignore */ |
| break; |
| default: |
| |
| decode_failure: |
| vex_printf("error: %d\n", (Int)opcode); |
| |
| /* All decode failures end up here. */ |
| vex_printf("vex tilegx->IR: unhandled instruction: " |
| "%s 0x%llx 0x%llx 0x%llx 0x%llx\n", |
| decoded[n].opcode->name, |
| opd[0], opd[1], opd[2], opd[3]); |
| |
| /* Tell the dispatcher that this insn cannot be decoded, and so has |
| not been executed, and (is currently) the next to be executed. */ |
| stmt(IRStmt_Put(offsetof(VexGuestTILEGXState, guest_pc), |
| mkU64(guest_PC_curr_instr))); |
| dres.whatNext = Dis_StopHere; |
| dres.len = 0; |
| return dres; |
| } |
| |
| /* Hook the dirty helper for rare instruxtions. */ |
| if (use_dirty_helper) |
| { |
| Int i = 0; |
| Int wbc = 0; |
| IRExpr *opc_oprand[5]; |
| |
| opc_oprand[0] = mkU64(opcode); |
| |
| /* Get the operand registers or immediate. */ |
| for (i = 0 ; i < 4; i++) |
| { |
| opc_oprand[i + 1] = NULL; |
| |
| if (opd_dst_map & (1ULL << i)) |
| { |
| tb[wbc] = newTemp(Ity_I64); |
| wbc++; |
| opc_oprand[i + 1] = getIReg(opd[i]); |
| } |
| else if (opd_imm_map & (1ULL << i)) |
| opc_oprand[i + 1] = mkU64(opd[i]); |
| else if (opd_src_map & (1ULL << i)) |
| opc_oprand[i + 1] = getIReg(opd[i]); |
| else |
| opc_oprand[i + 1] = mkU64(0xfeee); |
| } |
| |
| IRExpr **args = mkIRExprVec_5(opc_oprand[0], opc_oprand[1], |
| opc_oprand[2], opc_oprand[3], |
| opc_oprand[4]); |
| IRDirty *genIR = NULL; |
| |
| switch (wbc) { |
| case 0: |
| { |
| genIR = unsafeIRDirty_0_N (0/*regparms*/, |
| "tilegx_dirtyhelper_gen", |
| &tilegx_dirtyhelper_gen, |
| args); |
| } |
| break; |
| case 1: |
| { |
| genIR = unsafeIRDirty_1_N (tb[0], |
| 0/*regparms*/, |
| "tilegx_dirtyhelper_gen", |
| &tilegx_dirtyhelper_gen, |
| args); |
| } |
| break; |
| default: |
| vex_printf("opc = %d\n", (Int)opcode); |
| vassert(0); |
| } |
| |
| stmt(IRStmt_Dirty(genIR)); |
| |
| wbc = 0; |
| for (i = 0 ; i < 4; i++) |
| { |
| if(opd_dst_map & (1 << i)) |
| { |
| /* Queue the writeback destination registers. */ |
| MARK_REG_WB(opd[i], tb[wbc]); |
| wbc++; |
| } |
| } |
| } |
| } |
| |
| /* Write back registers for a bundle. Note have to get all source registers |
| for all instructions in a bundle before write the destinations b/c this is |
| an VLIW processor. */ |
| for (n = 0; n < rd_wb_index; n++) |
| putIReg(rd_wb_reg[n], mkexpr(rd_wb_temp[n])); |
| |
| /* Add branch IR if apply finally, only upto one branch per bundle. */ |
| if (bstmt) { |
| stmt(bstmt); |
| dres.whatNext = Dis_StopHere; |
| |
| dres.jk_StopHere = jumpkind; |
| stmt(IRStmt_Put(offsetof(VexGuestTILEGXState, guest_pc), |
| mkU64(guest_PC_curr_instr + 8))); |
| } else if (next) { |
| if (steering_pc != -1ULL) { |
| if (resteerOkFn(callback_opaque, steering_pc)) { |
| dres.whatNext = Dis_ResteerU; |
| dres.continueAt = steering_pc; |
| stmt(IRStmt_Put(offsetof(VexGuestTILEGXState, guest_pc), |
| mkU64(steering_pc))); |
| } else { |
| dres.whatNext = Dis_StopHere; |
| dres.jk_StopHere = jumpkind; |
| stmt(IRStmt_Put(offsetof(VexGuestTILEGXState, guest_pc), |
| mkU64(steering_pc))); |
| } |
| } else { |
| dres.whatNext = Dis_StopHere; |
| dres.jk_StopHere = jumpkind; |
| stmt(IRStmt_Put(offsetof(VexGuestTILEGXState, guest_pc), next)); |
| } |
| } else { |
| /* As dafault dres.whatNext = Dis_Continue. */ |
| stmt(IRStmt_Put(offsetof(VexGuestTILEGXState, guest_pc), |
| mkU64(guest_PC_curr_instr + 8))); |
| } |
| |
| irsb->jumpkind = Ijk_Boring; |
| irsb->next = NULL; |
| dres.len = 8; |
| |
| decode_success: |
| |
| return dres; |
| } |
| |
| /*------------------------------------------------------------*/ |
| /*--- Top-level fn ---*/ |
| /*------------------------------------------------------------*/ |
| |
| /* Disassemble a single instruction into IR. The instruction |
| is located in host memory at &guest_code[delta]. */ |
| |
| DisResult |
| disInstr_TILEGX ( IRSB* irsb_IN, |
| Bool (*resteerOkFn) (void *, Addr), |
| Bool resteerCisOk, |
| void* callback_opaque, |
| const UChar* guest_code_IN, |
| Long delta, |
| Addr guest_IP, |
| VexArch guest_arch, |
| const VexArchInfo* archinfo, |
| const VexAbiInfo* abiinfo, |
| VexEndness host_endness_IN, |
| Bool sigill_diag_IN ) |
| { |
| DisResult dres; |
| |
| /* Set globals (see top of this file) */ |
| vassert(guest_arch == VexArchTILEGX); |
| |
| guest_code = (UChar*)(Addr)guest_code_IN; |
| irsb = irsb_IN; |
| host_endness = host_endness_IN; |
| guest_PC_curr_instr = (Addr64) guest_IP; |
| guest_PC_bbstart = (Addr64) toUInt(guest_IP - delta); |
| |
| dres = disInstr_TILEGX_WRK(resteerOkFn, resteerCisOk, |
| callback_opaque, |
| delta, archinfo, abiinfo, sigill_diag_IN); |
| |
| return dres; |
| } |
| |
| /*--------------------------------------------------------------------*/ |
| /*--- end guest_tilegx_toIR.c ---*/ |
| /*--------------------------------------------------------------------*/ |