Merge in a port for mips32-linux, by Petar Jovanovic and Dejan Jevtic,
mips-valgrind@rt-rk.com, Bug 270777.
VEX: new files for mips32.
git-svn-id: svn://svn.valgrind.org/vex/trunk@2376 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest_mips_defs.h b/priv/guest_mips_defs.h
new file mode 100644
index 0000000..afb4f90
--- /dev/null
+++ b/priv/guest_mips_defs.h
@@ -0,0 +1,114 @@
+
+/*---------------------------------------------------------------*/
+/*--- begin guest_mips_defs.h ---*/
+/*---------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2010-2012 RT-RK
+ mips-valgrind@rt-rk.com
+
+ 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.
+*/
+
+/* Only to be used within the guest-mips directory. */
+
+#ifndef __VEX_GUEST_MIPS_DEFS_H
+#define __VEX_GUEST_MIPS_DEFS_H
+
+/*---------------------------------------------------------*/
+/*--- mips to IR conversion ---*/
+/*---------------------------------------------------------*/
+
+/* Convert one MIPS insn to IR. See the type DisOneInstrFn in
+ bb_to_IR.h. */
+extern DisResult disInstr_MIPS ( IRSB* irbb,
+ Bool (*resteerOkFn) (void *, Addr64),
+ Bool resteerCisOk,
+ void* callback_opaque,
+ UChar* guest_code,
+ Long delta,
+ Addr64 guest_IP,
+ VexArch guest_arch,
+ VexArchInfo* archinfo,
+ VexAbiInfo* abiinfo,
+ Bool host_bigendian );
+
+/* Used by the optimiser to specialise calls to helpers. */
+extern IRExpr *guest_mips32_spechelper(HChar * function_name, IRExpr ** args,
+ IRStmt ** precedingStmts,
+ Int n_precedingStmts);
+
+/* Describes to the optimser which part of the guest state require
+ precise memory exceptions. This is logically part of the guest
+ state description. */
+extern Bool guest_mips32_state_requires_precise_mem_exns(Int, Int);
+
+extern VexGuestLayout mips32Guest_layout;
+
+/*---------------------------------------------------------*/
+/*--- mips guest helpers ---*/
+/*---------------------------------------------------------*/
+
+extern UInt mips32_dirtyhelper_mfc0(UInt rd, UInt sel);
+
+extern void mips32_dirtyhelper_sync(UInt sync);
+
+/*---------------------------------------------------------*/
+/*--- Condition code stuff ---*/
+/*---------------------------------------------------------*/
+
+/* Defines conditions which we can ask for (MIPS MIPS 2e page A3-6) */
+
+typedef enum {
+ MIPSCondEQ = 0, /* equal : Z=1 */
+ MIPSCondNE = 1, /* not equal : Z=0 */
+
+ MIPSCondHS = 2, /* >=u (higher or same) : C=1 */
+ MIPSCondLO = 3, /* <u (lower) : C=0 */
+
+ MIPSCondMI = 4, /* minus (negative) : N=1 */
+ MIPSCondPL = 5, /* plus (zero or +ve) : N=0 */
+
+ MIPSCondVS = 6, /* overflow : V=1 */
+ MIPSCondVC = 7, /* no overflow : V=0 */
+
+ MIPSCondHI = 8, /* >u (higher) : C=1 && Z=0 */
+ MIPSCondLS = 9, /* <=u (lower or same) : C=0 || Z=1 */
+
+ MIPSCondGE = 10, /* >=s (signed greater or equal) : N=V */
+ MIPSCondLT = 11, /* <s (signed less than) : N!=V */
+
+ MIPSCondGT = 12, /* >s (signed greater) : Z=0 && N=V */
+ MIPSCondLE = 13, /* <=s (signed less or equal) : Z=1 || N!=V */
+
+ MIPSCondAL = 14, /* always (unconditional) : 1 */
+ MIPSCondNV = 15 /* never (unconditional): : 0 */
+ /* NB: MIPS have deprecated the use of the NV condition code.
+ You are now supposed to use MOV R0,R0 as a noop rather than
+ MOVNV R0,R0 as was previously recommended. Future processors
+ may have the NV condition code reused to do other things. */
+} MIPSCondcode;
+
+#endif /* __VEX_GUEST_MIPS_DEFS_H */
+
+/*---------------------------------------------------------------*/
+/*--- end guest_mips_defs.h ---*/
+/*---------------------------------------------------------------*/
diff --git a/priv/guest_mips_helpers.c b/priv/guest_mips_helpers.c
new file mode 100644
index 0000000..d992b9c
--- /dev/null
+++ b/priv/guest_mips_helpers.c
@@ -0,0 +1,573 @@
+
+/*---------------------------------------------------------------*/
+/*--- begin guest_mips_helpers.c ---*/
+/*---------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2010-2012 RT-RK
+ mips-valgrind@rt-rk.com
+
+ 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.
+*/
+
+#include "libvex_basictypes.h"
+#include "libvex_emwarn.h"
+#include "libvex_guest_mips32.h"
+#include "libvex_ir.h"
+#include "libvex.h"
+
+#include "main_util.h"
+#include "guest_generic_bb_to_IR.h"
+#include "guest_mips_defs.h"
+
+/* This file contains helper functions for mips guest code. Calls to
+ these functions are generated by the back end.
+*/
+
+#define ALWAYSDEFD32(field) \
+ { offsetof(VexGuestMIPS32State, field), \
+ (sizeof ((VexGuestMIPS32State*)0)->field) }
+
+IRExpr *guest_mips32_spechelper(HChar * function_name, IRExpr ** args,
+ IRStmt ** precedingStmts, Int n_precedingStmts)
+{
+ return NULL;
+}
+
+/* VISIBLE TO LIBVEX CLIENT */
+void LibVEX_GuestMIPS32_initialise( /*OUT*/ VexGuestMIPS32State * vex_state)
+{
+ vex_state->guest_r0 = 0; /* Hardwired to 0 */
+ vex_state->guest_r1 = 0; /* Assembler temporary */
+ vex_state->guest_r2 = 0; /* Values for function returns ... */
+ vex_state->guest_r3 = 0; /* ...and expression evaluation */
+ vex_state->guest_r4 = 0; /* Function arguments */
+ vex_state->guest_r5 = 0;
+ vex_state->guest_r6 = 0;
+ vex_state->guest_r7 = 0;
+ vex_state->guest_r8 = 0; /* Temporaries */
+ vex_state->guest_r9 = 0;
+ vex_state->guest_r10 = 0;
+ vex_state->guest_r11 = 0;
+ vex_state->guest_r12 = 0;
+ vex_state->guest_r13 = 0;
+ vex_state->guest_r14 = 0;
+ vex_state->guest_r15 = 0;
+ vex_state->guest_r16 = 0; /* Saved temporaries */
+ vex_state->guest_r17 = 0;
+ vex_state->guest_r18 = 0;
+ vex_state->guest_r19 = 0;
+ vex_state->guest_r20 = 0;
+ vex_state->guest_r21 = 0;
+ vex_state->guest_r22 = 0;
+ vex_state->guest_r23 = 0;
+ vex_state->guest_r24 = 0; /* Temporaries */
+ vex_state->guest_r25 = 0;
+ vex_state->guest_r26 = 0; /* Reserved for OS kernel */
+ vex_state->guest_r27 = 0;
+ vex_state->guest_r28 = 0; /* Global pointer */
+ vex_state->guest_r29 = 0; /* Stack pointer */
+ vex_state->guest_r30 = 0; /* Frame pointer */
+ vex_state->guest_r31 = 0; /* Return address */
+ vex_state->guest_PC = 0; /* Program counter */
+ vex_state->guest_HI = 0; /* Multiply and divide register higher result */
+ vex_state->guest_LO = 0; /* Multiply and divide register lower result */
+
+ /* FPU Registers */
+ vex_state->guest_f0 = 0x7ff80000; /* Floting point general purpose registers */
+ vex_state->guest_f1 = 0x7ff80000;
+ vex_state->guest_f2 = 0x7ff80000;
+ vex_state->guest_f3 = 0x7ff80000;
+ vex_state->guest_f4 = 0x7ff80000;
+ vex_state->guest_f5 = 0x7ff80000;
+ vex_state->guest_f6 = 0x7ff80000;
+ vex_state->guest_f7 = 0x7ff80000;
+ vex_state->guest_f8 = 0x7ff80000;
+ vex_state->guest_f9 = 0x7ff80000;
+ vex_state->guest_f10 = 0x7ff80000;
+ vex_state->guest_f11 = 0x7ff80000;
+ vex_state->guest_f12 = 0x7ff80000;
+ vex_state->guest_f13 = 0x7ff80000;
+ vex_state->guest_f14 = 0x7ff80000;
+ vex_state->guest_f15 = 0x7ff80000;
+ vex_state->guest_f16 = 0x7ff80000;
+ vex_state->guest_f17 = 0x7ff80000;
+ vex_state->guest_f18 = 0x7ff80000;
+ vex_state->guest_f19 = 0x7ff80000;
+ vex_state->guest_f20 = 0x7ff80000;
+ vex_state->guest_f21 = 0x7ff80000;
+ vex_state->guest_f22 = 0x7ff80000;
+ vex_state->guest_f23 = 0x7ff80000;
+ vex_state->guest_f24 = 0x7ff80000;
+ vex_state->guest_f25 = 0x7ff80000;
+ vex_state->guest_f26 = 0x7ff80000;
+ vex_state->guest_f27 = 0x7ff80000;
+ vex_state->guest_f28 = 0x7ff80000;
+ vex_state->guest_f29 = 0x7ff80000;
+ vex_state->guest_f30 = 0x7ff80000;
+ vex_state->guest_f31 = 0x7ff80000;
+
+ vex_state->guest_FIR = 0; /* FP implementation and revision register */
+ vex_state->guest_FCCR = 0; /* FP condition codes register */
+ vex_state->guest_FEXR = 0; /* FP exceptions register */
+ vex_state->guest_FENR = 0; /* FP enables register */
+ vex_state->guest_FCSR = 0; /* FP control/status register */
+ vex_state->guest_ULR = 0; /* TLS */
+
+ /* Various pseudo-regs mandated by Vex or Valgrind. */
+ /* Emulation warnings */
+ vex_state->guest_EMWARN = 0;
+
+ /* For clflush: record start and length of area to invalidate */
+ vex_state->guest_TISTART = 0;
+ vex_state->guest_TILEN = 0;
+ vex_state->host_EvC_COUNTER = 0;
+ vex_state->host_EvC_FAILADDR = 0;
+
+ /* Used to record the unredirected guest address at the start of
+ a translation whose start has been redirected. By reading
+ this pseudo-register shortly afterwards, the translation can
+ find out what the corresponding no-redirection address was.
+ Note, this is only set for wrap-style redirects, not for
+ replace-style ones. */
+ vex_state->guest_NRADDR = 0;
+
+ vex_state->guest_COND = 0;
+}
+
+/*-----------------------------------------------------------*/
+/*--- Describing the mips guest state, for the benefit ---*/
+/*--- of iropt and instrumenters. ---*/
+/*-----------------------------------------------------------*/
+
+/* Figure out if any part of the guest state contained in minoff
+ .. maxoff requires precise memory exceptions. If in doubt return
+ True (but this is generates significantly slower code).
+
+ We enforce precise exns for guest SP, PC.
+*/
+Bool guest_mips32_state_requires_precise_mem_exns(Int minoff, Int maxoff)
+{
+ Int sp_min = offsetof(VexGuestMIPS32State, guest_r29);
+ Int sp_max = sp_min + 4 - 1;
+ Int pc_min = offsetof(VexGuestMIPS32State, guest_PC);
+ Int pc_max = pc_min + 4 - 1;
+
+ if (maxoff < sp_min || minoff > sp_max) {
+ /* no overlap with sp */
+ } else {
+ return True;
+ }
+
+ if (maxoff < pc_min || minoff > pc_max) {
+ /* no overlap with pc */
+ } else {
+ return True;
+ }
+
+ /* We appear to need precise updates of R11 in order to get proper
+ stacktraces from non-optimised code. */
+ Int fp_min = offsetof(VexGuestMIPS32State, guest_r30);
+ Int fp_max = fp_min + 4 - 1;
+
+ if (maxoff < fp_min || minoff > fp_max) {
+ /* no overlap with fp */
+ } else {
+ return True;
+ }
+
+ return False;
+}
+
+VexGuestLayout mips32Guest_layout = {
+ /* Total size of the guest state, in bytes. */
+ .total_sizeB = sizeof(VexGuestMIPS32State),
+ /* Describe the stack pointer. */
+ .offset_SP = offsetof(VexGuestMIPS32State, guest_r29),
+ .sizeof_SP = 4,
+ /* Describe the frame pointer. */
+ .offset_FP = offsetof(VexGuestMIPS32State, guest_r30),
+ .sizeof_FP = 4,
+ /* Describe the instruction pointer. */
+ .offset_IP = offsetof(VexGuestMIPS32State, guest_PC),
+ .sizeof_IP = 4,
+ /* Describe any sections to be regarded by Memcheck as
+ 'always-defined'. */
+ .n_alwaysDefd = 8,
+ /* ? :( */
+ .alwaysDefd = {
+ /* 0 */ ALWAYSDEFD32(guest_r0),
+ /* 1 */ ALWAYSDEFD32(guest_r1),
+ /* 2 */ ALWAYSDEFD32(guest_EMWARN),
+ /* 3 */ ALWAYSDEFD32(guest_TISTART),
+ /* 4 */ ALWAYSDEFD32(guest_TILEN),
+ /* 5 */ ALWAYSDEFD32(guest_r29),
+ /* 6 */ ALWAYSDEFD32(guest_r31),
+ /* 7 */ ALWAYSDEFD32(guest_ULR)
+ }
+};
+
+#define ASM_VOLATILE_CASE(rd, sel) \
+ case rd: asm volatile ("mfc0 %0, $" #rd ", "#sel"\n\t" :"=r" (x) ); break;
+
+UInt mips32_dirtyhelper_mfc0(UInt rd, UInt sel)
+{
+ UInt x = 0;
+#if defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev >= 2))
+ switch (sel) {
+ case 0:
+ //__asm__("mfc0 %0, $1, 0" :"=r" (x));
+ switch (rd) {
+ ASM_VOLATILE_CASE(0, 0);
+ ASM_VOLATILE_CASE(1, 0);
+ ASM_VOLATILE_CASE(2, 0);
+ ASM_VOLATILE_CASE(3, 0);
+ ASM_VOLATILE_CASE(4, 0);
+ ASM_VOLATILE_CASE(5, 0);
+ ASM_VOLATILE_CASE(6, 0);
+ ASM_VOLATILE_CASE(7, 0);
+ ASM_VOLATILE_CASE(8, 0);
+ ASM_VOLATILE_CASE(9, 0);
+ ASM_VOLATILE_CASE(10, 0);
+ ASM_VOLATILE_CASE(11, 0);
+ ASM_VOLATILE_CASE(12, 0);
+ ASM_VOLATILE_CASE(13, 0);
+ ASM_VOLATILE_CASE(14, 0);
+ ASM_VOLATILE_CASE(15, 0);
+ ASM_VOLATILE_CASE(16, 0);
+ ASM_VOLATILE_CASE(17, 0);
+ ASM_VOLATILE_CASE(18, 0);
+ ASM_VOLATILE_CASE(19, 0);
+ ASM_VOLATILE_CASE(20, 0);
+ ASM_VOLATILE_CASE(21, 0);
+ ASM_VOLATILE_CASE(22, 0);
+ ASM_VOLATILE_CASE(23, 0);
+ ASM_VOLATILE_CASE(24, 0);
+ ASM_VOLATILE_CASE(25, 0);
+ ASM_VOLATILE_CASE(26, 0);
+ ASM_VOLATILE_CASE(27, 0);
+ ASM_VOLATILE_CASE(28, 0);
+ ASM_VOLATILE_CASE(29, 0);
+ ASM_VOLATILE_CASE(30, 0);
+ ASM_VOLATILE_CASE(31, 0);
+ default:
+ break;
+ }
+ break;
+ case 1:
+ //__asm__("mfc0 %0, $1, 0" :"=r" (x));
+ switch (rd) {
+ ASM_VOLATILE_CASE(0, 1);
+ ASM_VOLATILE_CASE(1, 1);
+ ASM_VOLATILE_CASE(2, 1);
+ ASM_VOLATILE_CASE(3, 1);
+ ASM_VOLATILE_CASE(4, 1);
+ ASM_VOLATILE_CASE(5, 1);
+ ASM_VOLATILE_CASE(6, 1);
+ ASM_VOLATILE_CASE(7, 1);
+ ASM_VOLATILE_CASE(8, 1);
+ ASM_VOLATILE_CASE(9, 1);
+ ASM_VOLATILE_CASE(10, 1);
+ ASM_VOLATILE_CASE(11, 1);
+ ASM_VOLATILE_CASE(12, 1);
+ ASM_VOLATILE_CASE(13, 1);
+ ASM_VOLATILE_CASE(14, 1);
+ ASM_VOLATILE_CASE(15, 1);
+ ASM_VOLATILE_CASE(16, 1);
+ ASM_VOLATILE_CASE(17, 1);
+ ASM_VOLATILE_CASE(18, 1);
+ ASM_VOLATILE_CASE(19, 1);
+ ASM_VOLATILE_CASE(20, 1);
+ ASM_VOLATILE_CASE(21, 1);
+ ASM_VOLATILE_CASE(22, 1);
+ ASM_VOLATILE_CASE(23, 1);
+ ASM_VOLATILE_CASE(24, 1);
+ ASM_VOLATILE_CASE(25, 1);
+ ASM_VOLATILE_CASE(26, 1);
+ ASM_VOLATILE_CASE(27, 1);
+ ASM_VOLATILE_CASE(28, 1);
+ ASM_VOLATILE_CASE(29, 1);
+ ASM_VOLATILE_CASE(30, 1);
+ ASM_VOLATILE_CASE(31, 1);
+ default:
+ break;
+ }
+ break;
+ case 2:
+ //__asm__("mfc0 %0, $1, 0" :"=r" (x));
+ switch (rd) {
+ ASM_VOLATILE_CASE(0, 2);
+ ASM_VOLATILE_CASE(1, 2);
+ ASM_VOLATILE_CASE(2, 2);
+ ASM_VOLATILE_CASE(3, 1);
+ ASM_VOLATILE_CASE(4, 2);
+ ASM_VOLATILE_CASE(5, 2);
+ ASM_VOLATILE_CASE(6, 2);
+ ASM_VOLATILE_CASE(7, 2);
+ ASM_VOLATILE_CASE(8, 2);
+ ASM_VOLATILE_CASE(9, 2);
+ ASM_VOLATILE_CASE(10, 2);
+ ASM_VOLATILE_CASE(11, 2);
+ ASM_VOLATILE_CASE(12, 2);
+ ASM_VOLATILE_CASE(13, 2);
+ ASM_VOLATILE_CASE(14, 2);
+ ASM_VOLATILE_CASE(15, 2);
+ ASM_VOLATILE_CASE(16, 2);
+ ASM_VOLATILE_CASE(17, 2);
+ ASM_VOLATILE_CASE(18, 2);
+ ASM_VOLATILE_CASE(19, 2);
+ ASM_VOLATILE_CASE(20, 2);
+ ASM_VOLATILE_CASE(21, 2);
+ ASM_VOLATILE_CASE(22, 2);
+ ASM_VOLATILE_CASE(23, 2);
+ ASM_VOLATILE_CASE(24, 2);
+ ASM_VOLATILE_CASE(25, 2);
+ ASM_VOLATILE_CASE(26, 2);
+ ASM_VOLATILE_CASE(27, 2);
+ ASM_VOLATILE_CASE(28, 2);
+ ASM_VOLATILE_CASE(29, 2);
+ ASM_VOLATILE_CASE(30, 2);
+ ASM_VOLATILE_CASE(31, 2);
+ default:
+ break;
+ }
+ break;
+ case 3:
+ //__asm__("mfc0 %0, $1, 0" :"=r" (x));
+ switch (rd) {
+ ASM_VOLATILE_CASE(0, 3);
+ ASM_VOLATILE_CASE(1, 3);
+ ASM_VOLATILE_CASE(2, 3);
+ ASM_VOLATILE_CASE(3, 3);
+ ASM_VOLATILE_CASE(4, 3);
+ ASM_VOLATILE_CASE(5, 3);
+ ASM_VOLATILE_CASE(6, 3);
+ ASM_VOLATILE_CASE(7, 3);
+ ASM_VOLATILE_CASE(8, 3);
+ ASM_VOLATILE_CASE(9, 3);
+ ASM_VOLATILE_CASE(10, 3);
+ ASM_VOLATILE_CASE(11, 3);
+ ASM_VOLATILE_CASE(12, 3);
+ ASM_VOLATILE_CASE(13, 3);
+ ASM_VOLATILE_CASE(14, 3);
+ ASM_VOLATILE_CASE(15, 3);
+ ASM_VOLATILE_CASE(16, 3);
+ ASM_VOLATILE_CASE(17, 3);
+ ASM_VOLATILE_CASE(18, 3);
+ ASM_VOLATILE_CASE(19, 3);
+ ASM_VOLATILE_CASE(20, 3);
+ ASM_VOLATILE_CASE(21, 3);
+ ASM_VOLATILE_CASE(22, 3);
+ ASM_VOLATILE_CASE(23, 3);
+ ASM_VOLATILE_CASE(24, 3);
+ ASM_VOLATILE_CASE(25, 3);
+ ASM_VOLATILE_CASE(26, 3);
+ ASM_VOLATILE_CASE(27, 3);
+ ASM_VOLATILE_CASE(28, 3);
+ ASM_VOLATILE_CASE(29, 3);
+ ASM_VOLATILE_CASE(30, 3);
+ ASM_VOLATILE_CASE(31, 3);
+ default:
+ break;
+ }
+ break;
+ case 4:
+ //__asm__("mfc0 %0, $1, 0" :"=r" (x));
+ switch (rd) {
+ ASM_VOLATILE_CASE(0, 4);
+ ASM_VOLATILE_CASE(1, 4);
+ ASM_VOLATILE_CASE(2, 4);
+ ASM_VOLATILE_CASE(3, 4);
+ ASM_VOLATILE_CASE(4, 4);
+ ASM_VOLATILE_CASE(5, 4);
+ ASM_VOLATILE_CASE(6, 4);
+ ASM_VOLATILE_CASE(7, 4);
+ ASM_VOLATILE_CASE(8, 4);
+ ASM_VOLATILE_CASE(9, 4);
+ ASM_VOLATILE_CASE(10, 4);
+ ASM_VOLATILE_CASE(11, 4);
+ ASM_VOLATILE_CASE(12, 4);
+ ASM_VOLATILE_CASE(13, 4);
+ ASM_VOLATILE_CASE(14, 4);
+ ASM_VOLATILE_CASE(15, 4);
+ ASM_VOLATILE_CASE(16, 4);
+ ASM_VOLATILE_CASE(17, 4);
+ ASM_VOLATILE_CASE(18, 4);
+ ASM_VOLATILE_CASE(19, 4);
+ ASM_VOLATILE_CASE(20, 4);
+ ASM_VOLATILE_CASE(21, 4);
+ ASM_VOLATILE_CASE(22, 4);
+ ASM_VOLATILE_CASE(23, 4);
+ ASM_VOLATILE_CASE(24, 4);
+ ASM_VOLATILE_CASE(25, 4);
+ ASM_VOLATILE_CASE(26, 4);
+ ASM_VOLATILE_CASE(27, 4);
+ ASM_VOLATILE_CASE(28, 4);
+ ASM_VOLATILE_CASE(29, 4);
+ ASM_VOLATILE_CASE(30, 4);
+ ASM_VOLATILE_CASE(31, 4);
+ default:
+ break;
+ }
+ break;
+ case 5:
+ //__asm__("mfc0 %0, $1, 0" :"=r" (x));
+ switch (rd) {
+ ASM_VOLATILE_CASE(0, 5);
+ ASM_VOLATILE_CASE(1, 5);
+ ASM_VOLATILE_CASE(2, 5);
+ ASM_VOLATILE_CASE(3, 5);
+ ASM_VOLATILE_CASE(4, 5);
+ ASM_VOLATILE_CASE(5, 5);
+ ASM_VOLATILE_CASE(6, 5);
+ ASM_VOLATILE_CASE(7, 5);
+ ASM_VOLATILE_CASE(8, 5);
+ ASM_VOLATILE_CASE(9, 5);
+ ASM_VOLATILE_CASE(10, 5);
+ ASM_VOLATILE_CASE(11, 5);
+ ASM_VOLATILE_CASE(12, 5);
+ ASM_VOLATILE_CASE(13, 5);
+ ASM_VOLATILE_CASE(14, 5);
+ ASM_VOLATILE_CASE(15, 5);
+ ASM_VOLATILE_CASE(16, 5);
+ ASM_VOLATILE_CASE(17, 5);
+ ASM_VOLATILE_CASE(18, 5);
+ ASM_VOLATILE_CASE(19, 5);
+ ASM_VOLATILE_CASE(20, 5);
+ ASM_VOLATILE_CASE(21, 5);
+ ASM_VOLATILE_CASE(22, 5);
+ ASM_VOLATILE_CASE(23, 5);
+ ASM_VOLATILE_CASE(24, 5);
+ ASM_VOLATILE_CASE(25, 5);
+ ASM_VOLATILE_CASE(26, 5);
+ ASM_VOLATILE_CASE(27, 5);
+ ASM_VOLATILE_CASE(28, 5);
+ ASM_VOLATILE_CASE(29, 5);
+ ASM_VOLATILE_CASE(30, 5);
+ ASM_VOLATILE_CASE(31, 5);
+ default:
+ break;
+ }
+ break;
+ case 6:
+ //__asm__("mfc0 %0, $1, 0" :"=r" (x));
+ switch (rd) {
+ ASM_VOLATILE_CASE(0, 6);
+ ASM_VOLATILE_CASE(1, 6);
+ ASM_VOLATILE_CASE(2, 6);
+ ASM_VOLATILE_CASE(3, 6);
+ ASM_VOLATILE_CASE(4, 6);
+ ASM_VOLATILE_CASE(5, 6);
+ ASM_VOLATILE_CASE(6, 6);
+ ASM_VOLATILE_CASE(7, 6);
+ ASM_VOLATILE_CASE(8, 6);
+ ASM_VOLATILE_CASE(9, 6);
+ ASM_VOLATILE_CASE(10, 6);
+ ASM_VOLATILE_CASE(11, 6);
+ ASM_VOLATILE_CASE(12, 6);
+ ASM_VOLATILE_CASE(13, 6);
+ ASM_VOLATILE_CASE(14, 6);
+ ASM_VOLATILE_CASE(15, 6);
+ ASM_VOLATILE_CASE(16, 6);
+ ASM_VOLATILE_CASE(17, 6);
+ ASM_VOLATILE_CASE(18, 6);
+ ASM_VOLATILE_CASE(19, 6);
+ ASM_VOLATILE_CASE(20, 6);
+ ASM_VOLATILE_CASE(21, 6);
+ ASM_VOLATILE_CASE(22, 6);
+ ASM_VOLATILE_CASE(23, 6);
+ ASM_VOLATILE_CASE(24, 6);
+ ASM_VOLATILE_CASE(25, 6);
+ ASM_VOLATILE_CASE(26, 6);
+ ASM_VOLATILE_CASE(27, 6);
+ ASM_VOLATILE_CASE(28, 6);
+ ASM_VOLATILE_CASE(29, 6);
+ ASM_VOLATILE_CASE(30, 6);
+ ASM_VOLATILE_CASE(31, 6);
+ default:
+ break;
+ }
+ break;
+ case 7:
+ //__asm__("mfc0 %0, $1, 0" :"=r" (x));
+ switch (rd) {
+ ASM_VOLATILE_CASE(0, 7);
+ ASM_VOLATILE_CASE(1, 7);
+ ASM_VOLATILE_CASE(2, 7);
+ ASM_VOLATILE_CASE(3, 7);
+ ASM_VOLATILE_CASE(4, 7);
+ ASM_VOLATILE_CASE(5, 7);
+ ASM_VOLATILE_CASE(6, 7);
+ ASM_VOLATILE_CASE(7, 7);
+ ASM_VOLATILE_CASE(8, 7);
+ ASM_VOLATILE_CASE(9, 7);
+ ASM_VOLATILE_CASE(10, 7);
+ ASM_VOLATILE_CASE(11, 7);
+ ASM_VOLATILE_CASE(12, 7);
+ ASM_VOLATILE_CASE(13, 7);
+ ASM_VOLATILE_CASE(14, 7);
+ ASM_VOLATILE_CASE(15, 7);
+ ASM_VOLATILE_CASE(16, 7);
+ ASM_VOLATILE_CASE(17, 7);
+ ASM_VOLATILE_CASE(18, 7);
+ ASM_VOLATILE_CASE(19, 7);
+ ASM_VOLATILE_CASE(20, 7);
+ ASM_VOLATILE_CASE(21, 7);
+ ASM_VOLATILE_CASE(22, 7);
+ ASM_VOLATILE_CASE(23, 7);
+ ASM_VOLATILE_CASE(24, 7);
+ ASM_VOLATILE_CASE(25, 7);
+ ASM_VOLATILE_CASE(26, 7);
+ ASM_VOLATILE_CASE(27, 7);
+ ASM_VOLATILE_CASE(28, 7);
+ ASM_VOLATILE_CASE(29, 7);
+ ASM_VOLATILE_CASE(30, 7);
+ ASM_VOLATILE_CASE(31, 7);
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+#endif
+ return x;
+}
+
+#undef ASM_VOLATILE_CASE
+
+#define ASM_VOLATILE_CASE(rd, sel) \
+ case rd: asm volatile ("dmfc0 %0, $" #rd ", "#sel"\n\t" :"=r" (x) ); break;
+
+#define ASM_VOLATILE_SYNC(stype) \
+ asm volatile ("sync \n\t");
+
+void mips32_dirtyhelper_sync(UInt stype)
+{
+#if defined(__mips__) && ((defined(__mips_isa_rev) && __mips_isa_rev >= 2))
+ ASM_VOLATILE_SYNC(0);
+#endif
+}
+
+/*---------------------------------------------------------------*/
+/*--- end guest_mips_helpers.c ---*/
+/*---------------------------------------------------------------*/
diff --git a/priv/guest_mips_toIR.c b/priv/guest_mips_toIR.c
new file mode 100644
index 0000000..80e6d3f
--- /dev/null
+++ b/priv/guest_mips_toIR.c
@@ -0,0 +1,3518 @@
+
+/*--------------------------------------------------------------------*/
+/*--- begin guest_mips_toIR.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2010-2012 RT-RK
+ mips-valgrind@rt-rk.com
+
+ 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.
+*/
+
+/* Translates MIPS code to IR. */
+
+#include "libvex_basictypes.h"
+#include "libvex_ir.h"
+#include "libvex.h"
+#include "libvex_guest_mips32.h"
+
+#include "main_util.h"
+#include "main_globals.h"
+#include "guest_generic_bb_to_IR.h"
+#include "guest_mips_defs.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 Bool host_is_bigendian;
+
+/* Pointer to the guest code area. */
+static UChar *guest_code;
+
+/* The guest address corresponding to guest_code[0]. */
+static Addr32 guest_PC_bbstart;
+
+/* CONST: The guest address for the instruction currently being
+ translated. */
+static Addr32 guest_PC_curr_instr;
+
+/* MOD: The IRSB* into which we're generating code. */
+static IRSB *irsb;
+
+/* Is our guest binary 32 or 64bit? Set at each call to
+ disInstr_MIPS below. */
+static Bool mode64 = False;
+
+/*------------------------------------------------------------*/
+/*--- Debugging output ---*/
+/*------------------------------------------------------------*/
+
+#define DIP(format, args...) \
+ if (vex_traceflags & VEX_TRACE_FE) \
+ vex_printf(format, ## args)
+
+/*------------------------------------------------------------*/
+/*--- Helper bits and pieces for deconstructing the ---*/
+/*--- mips insn stream. ---*/
+/*------------------------------------------------------------*/
+
+/* ---------------- Integer registers ---------------- */
+
+static UInt integerGuestRegOffset(UInt iregNo)
+{
+ /* Do we care about endianness here? We do if sub-parts of integer
+ registers are accessed, but I don't think that ever happens on
+ MIPS. */
+ UInt ret;
+ switch (iregNo) {
+ case 0:
+ ret = offsetof(VexGuestMIPS32State, guest_r0); break;
+ case 1:
+ ret = offsetof(VexGuestMIPS32State, guest_r1); break;
+ case 2:
+ ret = offsetof(VexGuestMIPS32State, guest_r2); break;
+ case 3:
+ ret = offsetof(VexGuestMIPS32State, guest_r3); break;
+ case 4:
+ ret = offsetof(VexGuestMIPS32State, guest_r4); break;
+ case 5:
+ ret = offsetof(VexGuestMIPS32State, guest_r5); break;
+ case 6:
+ ret = offsetof(VexGuestMIPS32State, guest_r6); break;
+ case 7:
+ ret = offsetof(VexGuestMIPS32State, guest_r7); break;
+ case 8:
+ ret = offsetof(VexGuestMIPS32State, guest_r8); break;
+ case 9:
+ ret = offsetof(VexGuestMIPS32State, guest_r9); break;
+ case 10:
+ ret = offsetof(VexGuestMIPS32State, guest_r10); break;
+ case 11:
+ ret = offsetof(VexGuestMIPS32State, guest_r11); break;
+ case 12:
+ ret = offsetof(VexGuestMIPS32State, guest_r12); break;
+ case 13:
+ ret = offsetof(VexGuestMIPS32State, guest_r13); break;
+ case 14:
+ ret = offsetof(VexGuestMIPS32State, guest_r14); break;
+ case 15:
+ ret = offsetof(VexGuestMIPS32State, guest_r15); break;
+ case 16:
+ ret = offsetof(VexGuestMIPS32State, guest_r16); break;
+ case 17:
+ ret = offsetof(VexGuestMIPS32State, guest_r17); break;
+ case 18:
+ ret = offsetof(VexGuestMIPS32State, guest_r18); break;
+ case 19:
+ ret = offsetof(VexGuestMIPS32State, guest_r19); break;
+ case 20:
+ ret = offsetof(VexGuestMIPS32State, guest_r20); break;
+ case 21:
+ ret = offsetof(VexGuestMIPS32State, guest_r21); break;
+ case 22:
+ ret = offsetof(VexGuestMIPS32State, guest_r22); break;
+ case 23:
+ ret = offsetof(VexGuestMIPS32State, guest_r23); break;
+ case 24:
+ ret = offsetof(VexGuestMIPS32State, guest_r24); break;
+ case 25:
+ ret = offsetof(VexGuestMIPS32State, guest_r25); break;
+ case 26:
+ ret = offsetof(VexGuestMIPS32State, guest_r26); break;
+ case 27:
+ ret = offsetof(VexGuestMIPS32State, guest_r27); break;
+ case 28:
+ ret = offsetof(VexGuestMIPS32State, guest_r28); break;
+ case 29:
+ ret = offsetof(VexGuestMIPS32State, guest_r29); break;
+ case 30:
+ ret = offsetof(VexGuestMIPS32State, guest_r30); break;
+ case 31:
+ ret = offsetof(VexGuestMIPS32State, guest_r31); break;
+ default:
+ vassert(0);
+ break;
+ }
+ return ret;
+}
+
+#define OFFB_PC offsetof(VexGuestMIPS32State, guest_PC)
+
+/* ---------------- Floating point registers ---------------- */
+
+static UInt floatGuestRegOffset(UInt fregNo)
+{
+ vassert(fregNo < 32);
+ UInt ret;
+ switch (fregNo) {
+ case 0:
+ ret = offsetof(VexGuestMIPS32State, guest_f0); break;
+ case 1:
+ ret = offsetof(VexGuestMIPS32State, guest_f1); break;
+ case 2:
+ ret = offsetof(VexGuestMIPS32State, guest_f2); break;
+ case 3:
+ ret = offsetof(VexGuestMIPS32State, guest_f3); break;
+ case 4:
+ ret = offsetof(VexGuestMIPS32State, guest_f4); break;
+ case 5:
+ ret = offsetof(VexGuestMIPS32State, guest_f5); break;
+ case 6:
+ ret = offsetof(VexGuestMIPS32State, guest_f6); break;
+ case 7:
+ ret = offsetof(VexGuestMIPS32State, guest_f7); break;
+ case 8:
+ ret = offsetof(VexGuestMIPS32State, guest_f8); break;
+ case 9:
+ ret = offsetof(VexGuestMIPS32State, guest_f9); break;
+ case 10:
+ ret = offsetof(VexGuestMIPS32State, guest_f10); break;
+ case 11:
+ ret = offsetof(VexGuestMIPS32State, guest_f11); break;
+ case 12:
+ ret = offsetof(VexGuestMIPS32State, guest_f12); break;
+ case 13:
+ ret = offsetof(VexGuestMIPS32State, guest_f13); break;
+ case 14:
+ ret = offsetof(VexGuestMIPS32State, guest_f14); break;
+ case 15:
+ ret = offsetof(VexGuestMIPS32State, guest_f15); break;
+ case 16:
+ ret = offsetof(VexGuestMIPS32State, guest_f16); break;
+ case 17:
+ ret = offsetof(VexGuestMIPS32State, guest_f17); break;
+ case 18:
+ ret = offsetof(VexGuestMIPS32State, guest_f18); break;
+ case 19:
+ ret = offsetof(VexGuestMIPS32State, guest_f19); break;
+ case 20:
+ ret = offsetof(VexGuestMIPS32State, guest_f20); break;
+ case 21:
+ ret = offsetof(VexGuestMIPS32State, guest_f21); break;
+ case 22:
+ ret = offsetof(VexGuestMIPS32State, guest_f22); break;
+ case 23:
+ ret = offsetof(VexGuestMIPS32State, guest_f23); break;
+ case 24:
+ ret = offsetof(VexGuestMIPS32State, guest_f24); break;
+ case 25:
+ ret = offsetof(VexGuestMIPS32State, guest_f25); break;
+ case 26:
+ ret = offsetof(VexGuestMIPS32State, guest_f26); break;
+ case 27:
+ ret = offsetof(VexGuestMIPS32State, guest_f27); break;
+ case 28:
+ ret = offsetof(VexGuestMIPS32State, guest_f28); break;
+ case 29:
+ ret = offsetof(VexGuestMIPS32State, guest_f29); break;
+ case 30:
+ ret = offsetof(VexGuestMIPS32State, guest_f30); break;
+ case 31:
+ ret = offsetof(VexGuestMIPS32State, guest_f31); break;
+ default:
+ vassert(0);
+ break;
+ }
+ return ret;
+}
+
+/* Do a endian load of a 32-bit word, regardless of the
+ endianness of the underlying host. */
+static inline UInt getUInt(UChar * p)
+{
+ UInt w = 0;
+#if defined (_MIPSEL)
+ w = (w << 8) | p[3];
+ w = (w << 8) | p[2];
+ w = (w << 8) | p[1];
+ w = (w << 8) | p[0];
+#elif defined (_MIPSEB)
+ w = (w << 8) | p[0];
+ w = (w << 8) | p[1];
+ w = (w << 8) | p[2];
+ w = (w << 8) | p[3];
+#endif
+ return w;
+}
+
+#define BITS2(_b1,_b0) \
+ (((_b1) << 1) | (_b0))
+
+#define BITS3(_b2,_b1,_b0) \
+ (((_b2) << 2) | ((_b1) << 1) | (_b0))
+
+#define BITS4(_b3,_b2,_b1,_b0) \
+ (((_b3) << 3) | ((_b2) << 2) | ((_b1) << 1) | (_b0))
+
+#define BITS5(_b4,_b3,_b2,_b1,_b0) \
+ (((_b4) << 4) | BITS4((_b3),(_b2),(_b1),(_b0)))
+
+#define BITS6(_b5,_b4,_b3,_b2,_b1,_b0) \
+ ((BITS2((_b5),(_b4)) << 4) \
+ | BITS4((_b3),(_b2),(_b1),(_b0)))
+
+#define BITS8(_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0) \
+ ((BITS4((_b7),(_b6),(_b5),(_b4)) << 4) \
+ | BITS4((_b3),(_b2),(_b1),(_b0)))
+
+#define LOAD_STORE_PATTERN \
+ t1 = newTemp(Ity_I32); \
+ assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm)))); \
+
+#define LWX_SWX_PATTERN \
+ t2 = newTemp(Ity_I32); \
+ assign(t2, binop(Iop_And32, mkexpr(t1), mkU32(0xFFFFFFFC))); \
+ t4 = newTemp(Ity_I32); \
+ assign(t4, binop(Iop_And32, mkexpr(t1), mkU32(0x00000003)))
+
+#define SXXV_PATTERN(op) \
+ putIReg(rd, binop(op, \
+ getIReg(rt), \
+ unop(Iop_32to8, \
+ binop(Iop_And32, \
+ getIReg(rs), \
+ mkU32(0x0000001F) \
+ ) \
+ ) \
+ ) \
+ )
+
+#define SXX_PATTERN(op) \
+ putIReg(rd, binop(op, getIReg(rt), mkU8(sa)));
+
+#define ALU_PATTERN(op) \
+ putIReg(rd, binop(op, getIReg(rs), getIReg(rt)));
+
+#define ALUI_PATTERN(op) \
+ putIReg(rt, binop(op, getIReg(rs), mkU32(imm)));
+
+#define ALUI_PATTERN64(op) \
+ putIReg(rt, binop(op, getIReg(rs), mkU64(imm)));
+
+#define FP_CONDITIONAL_CODE \
+ t3 = newTemp(Ity_I32); \
+ assign(t3, binop(Iop_And32, IRExpr_Mux0X( unop(Iop_1Uto8, \
+ binop(Iop_CmpEQ32, mkU32(cc), mkU32(0))), \
+ binop(Iop_Shr32, getFCSR(), mkU8(24+cc)), \
+ binop(Iop_Shr32, getFCSR(), mkU8(23))), mkU32(0x1)));
+
+/*------------------------------------------------------------*/
+/*--- Field helpers ---*/
+/*------------------------------------------------------------*/
+
+static UInt get_opcode(UInt mipsins)
+{
+ return (0xFC000000 & mipsins) >> 26;
+}
+
+static UInt get_rs(UInt mipsins)
+{
+ return (0x03E00000 & mipsins) >> 21;
+}
+
+static UInt get_rt(UInt mipsins)
+{
+ return (0x001F0000 & mipsins) >> 16;
+}
+
+static UInt get_imm(UInt mipsins)
+{
+ return (0x0000FFFF & mipsins);
+}
+
+static UInt get_instr_index(UInt mipsins)
+{
+ return (0x03FFFFFF & mipsins);
+}
+
+static UInt get_rd(UInt mipsins)
+{
+ return (0x0000F800 & mipsins) >> 11;
+}
+
+static UInt get_sa(UInt mipsins)
+{
+ return (0x000007C0 & mipsins) >> 6;
+}
+
+static UInt get_function(UInt mipsins)
+{
+ return (0x0000003F & mipsins);
+}
+
+static UInt get_ft(UInt mipsins)
+{
+ return (0x001F0000 & mipsins) >> 16;
+}
+
+static UInt get_fs(UInt mipsins)
+{
+ return (0x0000F800 & mipsins) >> 11;
+}
+
+static UInt get_fd(UInt mipsins)
+{
+ return (0x000007C0 & mipsins) >> 6;
+}
+
+static UInt get_mov_cc(UInt mipsins)
+{
+ return (0x001C0000 & mipsins) >> 18;
+}
+
+static UInt get_bc1_cc(UInt mipsins)
+{
+ return (0x001C0000 & mipsins) >> 18;
+}
+
+static UInt get_fpc_cc(UInt mipsins)
+{
+ return (0x00000700 & mipsins) >> 8;
+}
+
+static UInt get_tf(UInt mipsins)
+{
+ return (0x00010000 & mipsins) >> 16;
+}
+
+static UInt get_nd(UInt mipsins)
+{
+ return (0x00020000 & mipsins) >> 17;
+}
+
+static UInt get_fmt(UInt mipsins)
+{
+ return (0x03E00000 & mipsins) >> 21;
+}
+
+static UInt get_FC(UInt mipsins)
+{
+ return (0x000000F0 & mipsins) >> 4;
+}
+
+static UInt get_cond(UInt mipsins)
+{
+ return (0x0000000F & mipsins);
+}
+
+/* for break & syscall */
+static UInt get_code(UInt mipsins)
+{
+ return (0xFFC0 & mipsins) >> 6;
+}
+
+static UInt get_lsb(UInt mipsins)
+{
+ return (0x7C0 & mipsins) >> 6;
+}
+
+static UInt get_msb(UInt mipsins)
+{
+ return (0x0000F800 & mipsins) >> 11;
+}
+
+static UInt get_rot(UInt mipsins)
+{
+ return (0x00200000 & mipsins) >> 21;
+}
+
+static UInt get_rotv(UInt mipsins)
+{
+ return (0x00000040 & mipsins) >> 6;
+}
+
+static UInt get_sel(UInt mipsins)
+{
+ return (0x00000007 & mipsins);
+}
+
+static Bool branch_or_jump(UChar * addr)
+{
+ UInt fmt;
+ UInt cins = getUInt(addr);
+
+ UInt opcode = get_opcode(cins);
+ UInt rt = get_rt(cins);
+ UInt function = get_function(cins);
+
+ /* bgtz, blez, bne, beq, jal */
+ if (opcode == 0x07 || opcode == 0x06 || opcode == 0x05 || opcode == 0x04
+ || opcode == 0x03 || opcode == 0x02) {
+ return True;
+ }
+
+ /* bgez */
+ if (opcode == 0x01 && rt == 0x01) {
+ return True;
+ }
+
+ /* bgezal */
+ if (opcode == 0x01 && rt == 0x11) {
+ return True;
+ }
+
+ /* bltzal */
+ if (opcode == 0x01 && rt == 0x10) {
+ return True;
+ }
+
+ /* bltz */
+ if (opcode == 0x01 && rt == 0x00) {
+ return True;
+ }
+
+ /* jalr */
+ if (opcode == 0x00 && function == 0x09) {
+ return True;
+ }
+
+ /* jr */
+ if (opcode == 0x00 && function == 0x08) {
+ return True;
+ }
+
+ if (opcode == 0x11) {
+ /*bc1f & bc1t */
+ fmt = get_fmt(cins);
+ if (fmt == 0x08) {
+ return True;
+ }
+ }
+
+ return False;
+}
+
+static Bool is_Branch_or_Jump_and_Link(UChar * addr)
+{
+ UInt cins = getUInt(addr);
+
+ UInt opcode = get_opcode(cins);
+ UInt rt = get_rt(cins);
+ UInt function = get_function(cins);
+
+ /* jal */
+ if (opcode == 0x02) {
+ return True;
+ }
+
+ /* bgezal */
+ if (opcode == 0x01 && rt == 0x11) {
+ return True;
+ }
+
+ /* bltzal */
+ if (opcode == 0x01 && rt == 0x10) {
+ return True;
+ }
+
+ /* jalr */
+ if (opcode == 0x00 && function == 0x09) {
+ return True;
+ }
+
+ return False;
+}
+
+static Bool branch_or_link_likely(UChar * addr)
+{
+ UInt cins = getUInt(addr);
+ UInt opcode = get_opcode(cins);
+ UInt rt = get_rt(cins);
+
+ /* bgtzl, blezl, bnel, beql */
+ if (opcode == 0x17 || opcode == 0x16 || opcode == 0x15 || opcode == 0x14)
+ return True;
+
+ /* bgezl */
+ if (opcode == 0x01 && rt == 0x03)
+ return True;
+
+ /* bgezall */
+ if (opcode == 0x01 && rt == 0x13)
+ return True;
+
+ /* bltzall */
+ if (opcode == 0x01 && rt == 0x12)
+ return True;
+
+ /* bltzl */
+ if (opcode == 0x01 && rt == 0x02)
+ return True;
+
+ return False;
+}
+
+/*------------------------------------------------------------*/
+/*--- Helper bits and pieces for creating IR fragments. ---*/
+/*------------------------------------------------------------*/
+
+static IRExpr *mkU8(UInt i)
+{
+ vassert(i < 256);
+ 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 *triop(IROp op, IRExpr * a1, IRExpr * a2, IRExpr * a3)
+{
+ return IRExpr_Triop(op, a1, a2, a3);
+}
+
+static IRExpr *load(IRType ty, IRExpr * addr)
+{
+ IRExpr *load1 = NULL;
+#if defined (_MIPSEL)
+ load1 = IRExpr_Load(Iend_LE, ty, addr);
+#elif defined (_MIPSEB)
+ load1 = IRExpr_Load(Iend_BE, ty, addr);
+#endif
+ return load1;
+}
+
+/* Add a statement to the list held by "irsb". */
+static void stmt(IRStmt * st)
+{
+ addStmtToIRSB(irsb, st);
+}
+
+static void assign(IRTemp dst, IRExpr * e)
+{
+ stmt(IRStmt_WrTmp(dst, e));
+}
+
+static void store(IRExpr * addr, IRExpr * data)
+{
+#if defined (_MIPSEL)
+ stmt(IRStmt_Store(Iend_LE, addr, data));
+#elif defined (_MIPSEB)
+ stmt(IRStmt_Store(Iend_BE, addr, data));
+#endif
+}
+
+/* Generate a new temporary of the given type. */
+static IRTemp newTemp(IRType ty)
+{
+ vassert(isPlausibleIRType(ty));
+ return newIRTemp(irsb->tyenv, ty);
+}
+
+/* Generate an expression for SRC rotated right by ROT. */
+static IRExpr *genROR32(IRExpr * src, Int rot)
+{
+ vassert(rot >= 0 && rot < 32);
+ if (rot == 0)
+ return src;
+ return binop(Iop_Or32, binop(Iop_Shl32, src, mkU8(32 - rot)),
+ binop(Iop_Shr32, src, mkU8(rot)));
+}
+
+static IRExpr *genRORV32(IRExpr * src, IRExpr * rs)
+{
+ IRTemp t0 = newTemp(Ity_I8);
+ IRTemp t1 = newTemp(Ity_I8);
+
+ assign(t0, unop(Iop_32to8, binop(Iop_And32, rs, mkU32(0x0000001F))));
+ assign(t1, binop(Iop_Sub8, mkU8(32), mkexpr(t0)));
+ return binop(Iop_Or32, binop(Iop_Shl32, src, mkexpr(t1)),
+ binop(Iop_Shr32, src, mkexpr(t0)));
+}
+
+static UInt extend_s_16to32(UInt x)
+{
+ return (UInt) ((((Int) x) << 16) >> 16);
+}
+
+static UInt extend_s_18to32(UInt x)
+{
+ return (UInt) ((((Int) x) << 14) >> 14);
+}
+
+static void jmp_lit( /*MOD*/DisResult* dres,
+ IRJumpKind kind, Addr32 d32 )
+{
+ vassert(dres->whatNext == Dis_Continue);
+ vassert(dres->len == 0);
+ vassert(dres->continueAt == 0);
+ vassert(dres->jk_StopHere == Ijk_INVALID);
+ dres->whatNext = Dis_StopHere;
+ dres->jk_StopHere = kind;
+ stmt( IRStmt_Put( OFFB_PC, mkU32(d32) ) );
+}
+
+/* Fetch a byte from the guest insn stream. */
+static UChar getIByte(Int delta)
+{
+ return guest_code[delta];
+}
+
+static IRExpr *getIReg(UInt iregNo)
+{
+ IRType ty = mode64 ? Ity_I64 : Ity_I32;
+ vassert(iregNo < 32);
+ return IRExpr_Get(integerGuestRegOffset(iregNo), ty);
+}
+
+static IRExpr *getHI(void)
+{
+ return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_HI), Ity_I32);
+}
+
+static IRExpr *getLO(void)
+{
+ return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_LO), Ity_I32);
+}
+
+static IRExpr *getFCSR(void)
+{
+ return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_FCSR), Ity_I32);
+}
+
+static void putFCSR(IRExpr * e)
+{
+ stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_FCSR), e));
+}
+
+static IRExpr *getULR(void)
+{
+ return IRExpr_Get(offsetof(VexGuestMIPS32State, guest_ULR), Ity_I32);
+}
+
+static void putIReg(UInt archreg, IRExpr * e)
+{
+ IRType ty = mode64 ? Ity_I64 : Ity_I32;
+ vassert(archreg < 32);
+ vassert(typeOfIRExpr(irsb->tyenv, e) == ty);
+ if (archreg != 0)
+ stmt(IRStmt_Put(integerGuestRegOffset(archreg), e));
+}
+
+static void putLO(IRExpr * e)
+{
+ stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_LO), e));
+}
+
+static void putHI(IRExpr * e)
+{
+ stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_HI), e));
+}
+
+static void putPC(IRExpr * e)
+{
+ stmt(IRStmt_Put(OFFB_PC, e));
+}
+
+static IRExpr *mkWidenFrom32(IRType ty, IRExpr * src, Bool sined)
+{
+ vassert(ty == Ity_I32 || ty == Ity_I64);
+ if (ty == Ity_I32)
+ return src;
+ return (sined) ? unop(Iop_32Sto64, src) : unop(Iop_32Uto64, src);
+}
+
+/* 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) {
+ vassert(mode64);
+ return unop(Iop_64to8, e);
+ }
+ if (src_ty == Ity_I64 && dst_ty == Ity_I16) {
+ vassert(mode64);
+ return unop(Iop_64to16, 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(mips)");
+ return 0;
+}
+
+static IRExpr *mkNarrowTo32(IRType ty, IRExpr * src)
+{
+ vassert(ty == Ity_I32 || ty == Ity_I64);
+ return ty == Ity_I64 ? unop(Iop_64to32, src) : src;
+}
+
+static IRExpr *getLoFromF64(IRType ty, IRExpr * src)
+{
+ vassert(ty == Ity_F32 || ty == Ity_F64);
+ if (ty == Ity_F64) {
+ IRTemp t0, t1;
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I32);
+ assign(t0, unop(Iop_ReinterpF64asI64, src));
+ assign(t1, unop(Iop_64to32, mkexpr(t0)));
+ return unop(Iop_ReinterpI32asF32, mkexpr(t1));
+ } else
+ return src;
+}
+
+static IRExpr *mkWidenFromF32(IRType ty, IRExpr * src)
+{
+ vassert(ty == Ity_F32 || ty == Ity_F64);
+ return ty == Ity_F64 ? unop(Iop_F32toF64, src) : src;
+}
+
+static IRExpr *dis_branch_likely(IRExpr * guard, UInt imm)
+{
+ ULong branch_offset;
+ IRTemp t0;
+
+ /* PC = PC + (SignExtend(signed_immed_24) << 2)
+ An 18-bit signed offset (the 16-bit offset field shifted left 2 bits)
+ is added to the address of the instruction following
+ the branch (not the branch itself), in the branch delay slot, to form
+ a PC-relative effective target address. */
+ branch_offset = extend_s_18to32(imm << 2);
+
+ t0 = newTemp(Ity_I1);
+ assign(t0, guard);
+
+ stmt(IRStmt_Exit(mkexpr(t0), Ijk_Boring,
+ IRConst_U32(guest_PC_curr_instr + 8), OFFB_PC));
+
+ irsb->jumpkind = Ijk_Boring;
+
+ return mkU32(guest_PC_curr_instr + 4 + branch_offset);
+}
+
+static void dis_branch(Bool link, IRExpr * guard, UInt imm, IRStmt ** set)
+{
+ ULong branch_offset;
+ IRTemp t0;
+
+ if (link) { // LR (GPR31) = addr of the 2nd instr after branch instr
+ putIReg(31, mkU32(guest_PC_curr_instr + 8));
+ }
+
+ /* PC = PC + (SignExtend(signed_immed_24) << 2)
+ An 18-bit signed offset (the 16-bit offset field shifted left 2 bits)
+ is added to the address of the instruction following
+ the branch (not the branch itself), in the branch delay slot, to form
+ a PC-relative effective target address. */
+
+ branch_offset = extend_s_18to32(imm << 2);
+
+ t0 = newTemp(Ity_I1);
+ assign(t0, guard);
+ *set = IRStmt_Exit(mkexpr(t0), link ? Ijk_Call : Ijk_Boring,
+ IRConst_U32(guest_PC_curr_instr + 4 + (UInt) branch_offset),
+ OFFB_PC);
+}
+
+static IRExpr *getFReg(UInt dregNo)
+{
+ vassert(dregNo < 32);
+ IRType ty = mode64 ? Ity_F64 : Ity_F32;
+ return IRExpr_Get(floatGuestRegOffset(dregNo), ty);
+}
+
+static IRExpr *getDReg(UInt dregNo)
+{
+ vassert(dregNo < 32);
+ IRTemp t0 = newTemp(Ity_F32);
+ IRTemp t1 = newTemp(Ity_F32);
+ IRTemp t2 = newTemp(Ity_F64);
+ IRTemp t3 = newTemp(Ity_I32);
+ IRTemp t4 = newTemp(Ity_I32);
+ IRTemp t5 = newTemp(Ity_I64);
+
+ assign(t0, getFReg(dregNo));
+ assign(t1, getFReg(dregNo + 1));
+
+ assign(t3, unop(Iop_ReinterpF32asI32, mkexpr(t0)));
+ assign(t4, unop(Iop_ReinterpF32asI32, mkexpr(t1)));
+ assign(t5, binop(Iop_32HLto64, mkexpr(t4), mkexpr(t3)));
+ assign(t2, unop(Iop_ReinterpI64asF64, mkexpr(t5)));
+
+ return mkexpr(t2);
+}
+
+static void putFReg(UInt dregNo, IRExpr * e)
+{
+ vassert(dregNo < 32);
+ IRType ty = mode64 ? Ity_F64 : Ity_F32;
+ vassert(typeOfIRExpr(irsb->tyenv, e) == ty);
+ stmt(IRStmt_Put(floatGuestRegOffset(dregNo), e));
+}
+
+static void putDReg(UInt dregNo, IRExpr * e)
+{
+ vassert(dregNo < 32);
+ vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F64);
+ IRTemp t1 = newTemp(Ity_F64);
+ IRTemp t4 = newTemp(Ity_I32);
+ IRTemp t5 = newTemp(Ity_I32);
+ IRTemp t6 = newTemp(Ity_I64);
+ assign(t1, e);
+ assign(t6, unop(Iop_ReinterpF64asI64, mkexpr(t1)));
+ assign(t4, unop(Iop_64HIto32, mkexpr(t6))); // hi
+ assign(t5, unop(Iop_64to32, mkexpr(t6))); //lo
+ putFReg(dregNo, unop(Iop_ReinterpI32asF32, mkexpr(t5)));
+ putFReg(dregNo + 1, unop(Iop_ReinterpI32asF32, mkexpr(t4)));
+}
+
+static void setFPUCondCode(IRExpr * e, UInt cc)
+{
+ if (cc == 0) {
+ DIP("setFpu: %d\n", cc);
+ putFCSR(binop(Iop_And32, getFCSR(), mkU32(0xFF7FFFFF)));
+ putFCSR(binop(Iop_Or32, getFCSR(), binop(Iop_Shl32, e, mkU8(23))));
+ } else {
+ DIP("setFpu1: %d\n", cc);
+ putFCSR(binop(Iop_And32, getFCSR(), unop(Iop_Not32,
+ binop(Iop_Shl32, mkU32(0x01000000), mkU8(cc)))));
+ putFCSR(binop(Iop_Or32, getFCSR(), binop(Iop_Shl32, e, mkU8(24 + cc))));
+ }
+}
+
+static IRExpr */* :: Ity_I32 */get_IR_roundingmode(void)
+{
+/*
+ rounding mode | MIPS | IR
+ ------------------------
+ to nearest | 00 | 00
+ to zero | 01 | 11
+ to +infinity | 10 | 10
+ to -infinity | 11 | 01
+*/
+ IRTemp rm_MIPS = newTemp(Ity_I32);
+ /* Last two bits in FCSR are rounding mode. */
+
+ assign(rm_MIPS, binop(Iop_And32, IRExpr_Get(offsetof(VexGuestMIPS32State,
+ guest_FCSR), Ity_I32), mkU32(3)));
+
+ // rm_IR = XOR( rm_MIPS32, (rm_MIPS32 << 1) & 2)
+
+ return binop(Iop_Xor32, mkexpr(rm_MIPS), binop(Iop_And32,
+ binop(Iop_Shl32, mkexpr(rm_MIPS), mkU8(1)), mkU32(2)));
+}
+
+/*********************************************************/
+/*--- Floating Point Compare ---*/
+/*********************************************************/
+static Bool dis_instr_CCondFmt(UInt cins)
+{
+ IRTemp t0, t1, t2, t3;
+ IRTemp ccIR = newTemp(Ity_I32);
+ IRTemp ccMIPS = newTemp(Ity_I32);
+ UInt FC = get_FC(cins);
+ UInt fmt = get_fmt(cins);
+ UInt fs = get_fs(cins);
+ UInt ft = get_ft(cins);
+ UInt cond = get_cond(cins);
+
+ if (FC == 0x3) { // C.cond.fmt
+ UInt fpc_cc = get_fpc_cc(cins);
+ switch (fmt) {
+ case 0x10: { //C.cond.S
+ DIP("C.cond.S %d f%d, f%d\n", fpc_cc, fs, ft);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+
+ assign(ccIR, binop(Iop_CmpF64, unop(Iop_F32toF64, getFReg(fs)),
+ unop(Iop_F32toF64, getFReg(ft))));
+ /* Map compare result from IR to MIPS */
+ /*
+ FP cmp result | MIPS | IR
+ --------------------------
+ UN | 0x1 | 0x45
+ EQ | 0x2 | 0x40
+ GT | 0x4 | 0x00
+ LT | 0x8 | 0x01
+ */
+
+ // ccMIPS = Shl(1, (~(ccIR>>5) & 2)
+ // | ((ccIR ^ (ccIR>>6)) & 1)
+ assign(ccMIPS, binop(Iop_Shl32, mkU32(1), unop(Iop_32to8,
+ binop(Iop_Or32, binop(Iop_And32, unop(Iop_Not32,
+ binop(Iop_Shr32, mkexpr(ccIR), mkU8(5))), mkU32(2)),
+ binop(Iop_And32, binop(Iop_Xor32, mkexpr(ccIR),
+ binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))),
+ mkU32(1))))));
+ assign(t0, binop(Iop_And32, mkexpr(ccMIPS), mkU32(0x1))); // UN
+ assign(t1, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
+ mkU8(0x1)), mkU32(0x1))); // EQ
+ assign(t2, binop(Iop_And32, unop(Iop_Not32, binop(Iop_Shr32,
+ mkexpr(ccMIPS), mkU8(0x2))), mkU32(0x1))); // NGT
+ assign(t3, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
+ mkU8(0x3)), mkU32(0x1))); // LT
+
+ switch (cond) {
+ case 0x0:
+ setFPUCondCode(mkU32(0), fpc_cc);
+ break;
+ case 0x1:
+ DIP("unorderd: %d\n", fpc_cc);
+ setFPUCondCode(mkexpr(t0), fpc_cc);
+ break;
+ case 0x2:
+ setFPUCondCode(mkexpr(t1), fpc_cc);
+ break;
+ case 0x3:
+ setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
+ fpc_cc);
+ break;
+ case 0x4:
+ setFPUCondCode(mkexpr(t3), fpc_cc);
+ break;
+ case 0x5:
+ setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
+ fpc_cc);
+ break;
+ case 0x6:
+ setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
+ fpc_cc);
+ break;
+ case 0x7:
+ setFPUCondCode(mkexpr(t2), fpc_cc);
+ break;
+ case 0x8:
+ setFPUCondCode(mkU32(0), fpc_cc);
+ break;
+ case 0x9:
+ setFPUCondCode(mkexpr(t0), fpc_cc);
+ break;
+ case 0xA:
+ setFPUCondCode(mkexpr(t1), fpc_cc);
+ break;
+ case 0xB:
+ setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
+ fpc_cc);
+ break;
+ case 0xC:
+ setFPUCondCode(mkexpr(t3), fpc_cc);
+ break;
+ case 0xD:
+ setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
+ fpc_cc);
+ break;
+ case 0xE:
+ setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
+ fpc_cc);
+ break;
+ case 0xF:
+ setFPUCondCode(mkexpr(t2), fpc_cc);
+ break;
+
+ default:
+ return False;
+ }
+ }
+ break;
+
+ case 0x11: //C.cond.D
+ DIP("C.%d.D %d f%d, f%d\n", cond, fpc_cc, fs, ft);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ assign(ccIR, binop(Iop_CmpF64, getDReg(fs), getDReg(ft)));
+ /* Map compare result from IR to MIPS */
+ /*
+ FP cmp result | MIPS | IR
+ --------------------------
+ UN | 0x1 | 0x45
+ EQ | 0x2 | 0x40
+ GT | 0x4 | 0x00
+ LT | 0x8 | 0x01
+ */
+
+ // ccMIPS = Shl(1, (~(ccIR>>5) & 2)
+ // | ((ccIR ^ (ccIR>>6)) & 1)
+ assign(ccMIPS, binop(Iop_Shl32, mkU32(1), unop(Iop_32to8,
+ binop(Iop_Or32, binop(Iop_And32, unop(Iop_Not32,
+ binop(Iop_Shr32, mkexpr(ccIR), mkU8(5))), mkU32(2)),
+ binop(Iop_And32, binop(Iop_Xor32, mkexpr(ccIR),
+ binop(Iop_Shr32, mkexpr(ccIR), mkU8(6))),
+ mkU32(1))))));
+
+ assign(t0, binop(Iop_And32, mkexpr(ccMIPS), mkU32(0x1))); // UN
+ assign(t1, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
+ mkU8(0x1)), mkU32(0x1))); // EQ
+ assign(t2, binop(Iop_And32, unop(Iop_Not32, binop(Iop_Shr32,
+ mkexpr(ccMIPS), mkU8(0x2))), mkU32(0x1))); // NGT
+ assign(t3, binop(Iop_And32, binop(Iop_Shr32, mkexpr(ccMIPS),
+ mkU8(0x3)), mkU32(0x1))); // LT
+
+ switch (cond) {
+ case 0x0:
+ setFPUCondCode(mkU32(0), fpc_cc);
+ break;
+ case 0x1:
+ DIP("unorderd: %d\n", fpc_cc);
+ setFPUCondCode(mkexpr(t0), fpc_cc);
+ break;
+ case 0x2:
+ setFPUCondCode(mkexpr(t1), fpc_cc);
+ break;
+ case 0x3:
+ setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
+ fpc_cc);
+ break;
+ case 0x4:
+ setFPUCondCode(mkexpr(t3), fpc_cc);
+ break;
+ case 0x5:
+ setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
+ fpc_cc);
+ break;
+ case 0x6:
+ setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
+ fpc_cc);
+ break;
+ case 0x7:
+ setFPUCondCode(mkexpr(t2), fpc_cc);
+ break;
+ case 0x8:
+ setFPUCondCode(mkU32(0), fpc_cc);
+ break;
+ case 0x9:
+ setFPUCondCode(mkexpr(t0), fpc_cc);
+ break;
+ case 0xA:
+ setFPUCondCode(mkexpr(t1), fpc_cc);
+ break;
+ case 0xB:
+ setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
+ fpc_cc);
+ break;
+ case 0xC:
+ setFPUCondCode(mkexpr(t3), fpc_cc);
+ break;
+ case 0xD:
+ setFPUCondCode(binop(Iop_Or32, mkexpr(t0), mkexpr(t3)),
+ fpc_cc);
+ break;
+ case 0xE:
+ setFPUCondCode(binop(Iop_Or32, mkexpr(t3), mkexpr(t1)),
+ fpc_cc);
+ break;
+ case 0xF:
+ setFPUCondCode(mkexpr(t2), fpc_cc);
+ break;
+ default:
+ return False;
+ }
+ break;
+
+ default:
+ return False;
+ }
+ } else {
+ return False;
+ }
+
+ return True;
+}
+
+/*------------------------------------------------------------*/
+/*--- Disassemble a single instruction ---*/
+/*------------------------------------------------------------*/
+
+/* Disassemble a single instruction into IR. The instruction 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_MIPS_WRK ( Bool(*resteerOkFn) (/*opaque */void *,
+ Addr64),
+ Bool resteerCisOk,
+ void* callback_opaque,
+ Long delta64,
+ VexArchInfo* archinfo,
+ VexAbiInfo* abiinfo )
+{
+ IRTemp t0, t1, t2, t3, t4, t5, t6, t7, t8;
+ UInt opcode, cins, rs, rt, rd, sa, ft, fs, fd, fmt, tf, nd, function,
+ trap_code, imm, instr_index, p, msb, lsb, size, rot, sel;
+
+ DisResult dres;
+
+ static IRExpr *lastn = NULL; /* last jump addr */
+ static IRStmt *bstmt = NULL; /* branch (Exit) stmt */
+
+ /* The running delta */
+ Int delta = (Int) delta64;
+
+ /* Holds eip at the start of the insn, so that we can print
+ consistent error messages for unimplemented insns. */
+ Int delta_start = delta;
+
+ /* Are we in a delay slot ? */
+ Bool delay_slot_branch, likely_delay_slot, delay_slot_jump;
+
+ /* Set result defaults. */
+ dres.whatNext = Dis_Continue;
+ dres.len = 0;
+ dres.continueAt = 0;
+ dres.jk_StopHere = Ijk_INVALID;
+
+ delay_slot_branch = likely_delay_slot = delay_slot_jump = False;
+
+ UChar *code = (UChar *) (guest_code + delta);
+ cins = getUInt(code);
+
+ if (delta != 0) {
+ if (branch_or_jump(guest_code + delta - 4)) {
+ if (lastn == NULL && bstmt == NULL) {
+ DIP("Info: jump to delay slot insn...\n");
+ } else {
+ dres.whatNext = Dis_StopHere;
+
+ DIP("lastn = %p bstmt = %p\n", lastn, bstmt);
+ if (lastn != NULL) {
+ DIP("delay slot jump\n");
+ if (vex_traceflags & VEX_TRACE_FE)
+ ppIRExpr(lastn);
+ delay_slot_jump = True;
+ } else if (bstmt != NULL) {
+ DIP("\ndelay slot branch\n");
+ delay_slot_branch = True;
+ }
+ DIP("delay slot\n");
+ }
+ }
+
+ if (branch_or_link_likely(guest_code + delta - 4)) {
+ likely_delay_slot = True;
+ }
+ }
+
+ /* Spot "Special" instructions (see comment at top of file). */
+ {
+ /* Spot the 16-byte preamble:
+ ****mips32****
+ "srl $0, $0, 13
+ "srl $0, $0, 29
+ "srl $0, $0, 3
+ "srl $0, $0, 19 */
+ UInt word1 = 0x00000342;
+ UInt word2 = 0x00000742;
+ UInt word3 = 0x000000C2;
+ UInt word4 = 0x000004C2;
+ if (getUInt(code + 0) == word1 && getUInt(code + 4) == word2 &&
+ getUInt(code + 8) == word3 && getUInt(code + 12) == word4) {
+ /* Got a "Special" instruction preamble. Which one is it? */
+ if (getUInt(code + 16) == 0x01ad6825 /* or t5, t5, t5 */ ) {
+ /* v0 = client_request ( t9 ) */
+ DIP("v0 = client_request ( t9 )\n");
+ putPC(mkU32(guest_PC_curr_instr + 20));
+ dres.jk_StopHere = Ijk_ClientReq;
+ dres.whatNext = Dis_StopHere;
+
+ goto decode_success;
+ } else if (getUInt(code + 16) == 0x01ce7025 /* or t6,t6,t6 */ ) {
+ /* t9 = guest_NRADDR */
+ DIP("t9 = guest_NRADDR\n");
+ dres.len = 20;
+ delta += 20;
+ putIReg(11, IRExpr_Get(offsetof(VexGuestMIPS32State, guest_NRADDR),
+ Ity_I32));
+ goto decode_success;
+ } else if (getUInt(code + 16) == 0x01ef7825/* or t7,t7,t7 */ ) {
+ /* branch-and-link-to-noredir t9 */
+ DIP("branch-and-link-to-noredir t9\n");
+ putIReg(31, mkU32(guest_PC_curr_instr + 20));
+ putPC(getIReg(25));
+ dres.jk_StopHere = Ijk_NoRedir;
+ dres.whatNext = Dis_StopHere;
+ goto decode_success;
+ }
+
+ /* We don't know what it is. Set opc1/opc2 so decode_failure
+ can print the insn following the Special-insn preamble. */
+ delta += 16;
+ goto decode_failure;
+ /*NOTREACHED*/}
+ }
+
+ opcode = get_opcode(cins);
+ imm = get_imm(cins);
+ rs = get_rs(cins);
+ rt = get_rt(cins);
+ rd = get_rd(cins);
+ sa = get_sa(cins);
+ fs = get_fs(cins);
+ fd = get_fd(cins);
+ ft = get_ft(cins);
+ tf = get_tf(cins);
+ nd = get_nd(cins);
+ sel = get_sel(cins);
+ fmt = get_fmt(cins);
+ instr_index = get_instr_index(cins);
+ trap_code = get_code(cins);
+ function = get_function(cins);
+ IRType ty = mode64 ? Ity_I64 : Ity_I32;
+ IRType tyF = mode64 ? Ity_F64 : Ity_F32;
+
+ DIP("[cins = 0x%08x] ", cins);
+
+ switch (opcode) {
+
+ case 0x03: /* JAL */
+ DIP("jal");
+ putIReg(31, mkU32(guest_PC_curr_instr + 8));
+ t0 = newTemp(ty);
+ assign(t0, mkU32((guest_PC_curr_instr & 0xF0000000) |
+ (instr_index << 2)));
+ lastn = mkexpr(t0);
+ break;
+ case 0x02: /* J */
+ DIP("j");
+ t0 = newTemp(ty);
+ assign(t0, mkU32((guest_PC_curr_instr & 0xF0000000) |
+ (instr_index << 2)));
+ lastn = mkexpr(t0);
+ break;
+
+ case 0x11: /* COP1 */
+ {
+ UInt bc1_cc = get_bc1_cc(cins);
+ if (0x08 == fmt) {
+ switch (fmt) {
+ case 0x08: //BC
+ {
+ DIP("tf: %d, nd: %d\n", tf, nd);
+ //FcConditionalCode(bc1_cc)
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I1);
+
+ assign(t1, unop(Iop_1Sto32, binop(Iop_CmpEQ32, mkU32(0),
+ mkU32(bc1_cc))));
+ assign(t2, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t1)),
+ binop(Iop_And32, binop(Iop_Shr32, getFCSR(),
+ mkU8(24 + bc1_cc)), mkU32(0x1)), binop(Iop_And32,
+ binop(Iop_Shr32, getFCSR(), mkU8(23)),
+ mkU32(0x1))));
+
+ if (tf == 1 && nd == 0) {
+ //branch on true
+ DIP("bc1t \n");
+ assign(t3, binop(Iop_CmpEQ32, mkU32(1), mkexpr(t2)));
+ dis_branch(False, mkexpr(t3), imm, &bstmt);
+ break;
+ } else if (tf == 0 && nd == 0) {
+ //branch on false
+ DIP("bc1f \n");
+ assign(t3, binop(Iop_CmpEQ32, mkU32(0), mkexpr(t2)));
+ dis_branch(False, mkexpr(t3), imm, &bstmt);
+ break;
+ } else if (nd == 1 && tf == 0) {
+ DIP("bc1fl \n");
+ lastn = dis_branch_likely(binop(Iop_CmpNE32, mkexpr(t2),
+ mode64 ? mkU64(0x0) : mkU32(0x0)), imm);
+ break;
+ } else if (nd == 1 && tf == 1) {
+ DIP("bc1tl \n");
+ lastn = dis_branch_likely(binop(Iop_CmpEQ32, mkexpr(t2),
+ mkU32(0x0)), imm);
+ break;
+ } else
+ goto decode_failure;
+ }
+
+ default:
+ goto decode_failure;
+ }
+ } else {
+ switch (function) {
+
+ case 0x4: //SQRT.fmt
+ {
+ switch (fmt) {
+ case 0x10: //S
+ {
+ IRExpr *rm = get_IR_roundingmode();
+ putFReg(fd, mkWidenFromF32(tyF, binop(Iop_SqrtF32, rm,
+ getLoFromF64(tyF, getFReg(fs)))));
+ }
+ break;
+ case 0x11: //D
+ {
+ IRExpr *rm = get_IR_roundingmode();
+ putDReg(fd, binop(Iop_SqrtF64, rm, getDReg(fs)));
+ }
+ break;
+ }
+ }
+ break;
+ case 0x5: //abs.fmt
+ switch (fmt) {
+ case 0x10: //S
+ DIP("abs.s f%d, f%d\n", fd, fs);
+ putFReg(fd, mkWidenFromF32(tyF, unop(Iop_AbsF32,
+ getLoFromF64(tyF, getFReg(fs)))));
+ break;
+ case 0x11: //D
+ DIP("abs.d f%d, f%d\n", fd, fs);
+ putDReg(fd, unop(Iop_AbsF64, getDReg(fs)));
+ break;
+ default:
+ goto decode_failure;
+ }
+ break; //case 0x5
+
+ case 0x02: // MUL.fmt
+ switch (fmt) {
+ case 0x11: // D
+ {
+ DIP("mul.d f%d, f%d, f%d", fd, fs, ft);
+ IRExpr *rm = get_IR_roundingmode();
+ putDReg(fd, triop(Iop_MulF64, rm, getDReg(fs),
+ getDReg(ft)));
+ break;
+ }
+ case 0x10: // S
+ {
+ DIP("mul.s f%d, f%d, f%d", fd, fs, ft);
+ IRExpr *rm = get_IR_roundingmode();
+ putFReg(fd, mkWidenFromF32(tyF, triop(Iop_MulF32, rm,
+ getLoFromF64(tyF, getFReg(fs)),
+ getLoFromF64(tyF, getFReg(ft)))));
+ break;
+ }
+ default:
+ goto decode_failure;
+ }
+ break; // MUL.fmt
+
+ case 0x03: // DIV.fmt
+ switch (fmt) {
+ case 0x11: // D
+ {
+ DIP("div.d f%d, f%d, f%d", fd, fs, ft);
+ IRExpr *rm = get_IR_roundingmode();
+ putDReg(fd, triop(Iop_DivF64, rm, getDReg(fs),
+ getDReg(ft)));
+ break;
+ }
+ case 0x10: // S
+ {
+ DIP("div.s f%d, f%d, f%d", fd, fs, ft);
+ IRExpr *rm = get_IR_roundingmode();
+ putFReg(fd, mkWidenFromF32(tyF, triop(Iop_DivF32, rm,
+ getLoFromF64(tyF, getFReg(fs)),
+ getLoFromF64(tyF, getFReg(ft)))));
+ break;
+ }
+ default:
+ goto decode_failure;
+ }
+ break; // DIV.fmt
+
+ case 0x01: // SUB.fmt
+ switch (fmt) {
+ case 0x11: // D
+ {
+ DIP("sub.d f%d, f%d, f%d", fd, fs, ft);
+ IRExpr *rm = get_IR_roundingmode();
+ putDReg(fd, triop(Iop_SubF64, rm, getDReg(fs), getDReg(ft)));
+ break;
+ }
+ case 0x10: // S
+ {
+ DIP("sub.s f%d, f%d, f%d", fd, fs, ft);
+ IRExpr *rm = get_IR_roundingmode();
+ putFReg(fd, mkWidenFromF32(tyF, triop(Iop_SubF32, rm,
+ getLoFromF64(tyF, getFReg(fs)),
+ getLoFromF64(tyF, getFReg(ft)))));
+ break;
+ }
+ default:
+ goto decode_failure;
+ }
+ break; // SUB.fmt
+
+ case 0x06: // MOV.fmt
+ switch (fmt) {
+ case 0x11: // D
+ /* TODO: Check this for 64 bit FPU registers. */
+ DIP("mov.d f%d, f%d", fd, fs);
+ putFReg(fd, getFReg(fs));
+ putFReg(fd + 1, getFReg(fs + 1));
+ break;
+ case 0x10: // S
+ DIP("mov.s f%d, f%d", fd, fs);
+ putFReg(fd, getFReg(fs));
+ break;
+ default:
+ goto decode_failure;
+ }
+ break; // MOV.fmt
+
+ case 0x7: //neg.fmt
+ switch (fmt) {
+ case 0x10: //S
+ DIP("neg.s f%d, f%d", fd, fs);
+ putFReg(fd, mkWidenFromF32(tyF, unop(Iop_NegF32,
+ getLoFromF64(tyF, getFReg(fs)))));
+ break;
+ case 0x11: //D
+ DIP("neg.d f%d, f%d", fd, fs);
+ putDReg(fd, unop(Iop_NegF64, getDReg(fs)));
+ break;
+ default:
+ goto decode_failure;
+ }
+ break; //case 0x7
+
+ case 0x15: //RECIP.fmt
+ switch (fmt) {
+ case 0x10:
+ { //S
+ DIP("recip.s f%d, f%d\n", fd, fs);
+ IRExpr *rm = get_IR_roundingmode();
+ putFReg(fd, mkWidenFromF32(tyF, triop(Iop_DivF32,
+ rm, unop(Iop_ReinterpI32asF32,
+ mkU32(0x3F800000)), getLoFromF64(tyF,
+ getFReg(fs)))));
+ break;
+ }
+ case 0x11:
+ { //D
+ DIP("recip.d f%d, f%d\n", fd, fs);
+ IRExpr *rm = get_IR_roundingmode();
+ putDReg(fd, triop(Iop_DivF64, rm,
+ unop(Iop_ReinterpI64asF64,
+ mkU64(0x3FF0000000000000ULL)), getDReg(fs)));
+ break;
+ }
+ default:
+ goto decode_failure;
+
+ }
+ break; //case 0x15
+
+ case 0x13: //MOVN.fmt
+ switch (fmt) {
+ case 0x10: // S
+ DIP("movn.s f%d, f%d, r%d", fd, fs, rt);
+
+ t1 = newTemp(Ity_F64);
+ t2 = newTemp(Ity_F64);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_F64);
+
+ assign(t1, unop(Iop_F32toF64, getFReg(fs)));
+ assign(t2, unop(Iop_F32toF64, getFReg(fd)));
+ assign(t3, unop(Iop_1Sto32, binop(Iop_CmpNE32, mkU32(0),
+ getIReg(rt))));
+
+ assign(t4, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t3)),
+ mkexpr(t1), mkexpr(t2)));
+
+ putFReg(fd, binop(Iop_F64toF32, get_IR_roundingmode(),
+ mkexpr(t4)));
+ break;
+ case 0x11: // D
+ DIP("movn.d f%d, f%d, r%d", fd, fs, rt);
+
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_F64);
+
+ assign(t3, unop(Iop_1Sto32, binop(Iop_CmpNE32, mkU32(0),
+ getIReg(rt))));
+ putDReg(fd, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t3)),
+ getDReg(fs), getDReg(fd)));
+ break;
+ default:
+ goto decode_failure;
+ }
+ break; // MOVN.fmt
+
+ case 0x12: //MOVZ.fmt
+ switch (fmt) {
+ case 0x10: // S
+ DIP("movz.s f%d, f%d, r%d", fd, fs, rt);
+
+ t1 = newTemp(Ity_F64);
+ t2 = newTemp(Ity_F64);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_F64);
+
+ assign(t1, unop(Iop_F32toF64, getFReg(fs)));
+ assign(t2, unop(Iop_F32toF64, getFReg(fd)));
+ assign(t3, unop(Iop_1Sto32, binop(Iop_CmpEQ32, mkU32(0),
+ getIReg(rt))));
+ assign(t4, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t3)),
+ mkexpr(t1), mkexpr(t2)));
+
+ putFReg(fd, binop(Iop_F64toF32, get_IR_roundingmode(),
+ mkexpr(t4)));
+
+ break;
+ case 0x11: // D
+ DIP("movz.d f%d, f%d, r%d", fd, fs, rt);
+
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_F64);
+
+ assign(t3, unop(Iop_1Sto32, binop(Iop_CmpEQ32, mkU32(0),
+ getIReg(rt))));
+ putDReg(fd, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t3)),
+ getDReg(fs), getDReg(fd)));
+ break;
+ default:
+ goto decode_failure;
+ }
+ break; // MOVZ.fmt
+
+ case 0x11: // MOVT.fmt
+ if (tf == 1) {
+ UInt mov_cc = get_mov_cc(cins);
+ switch (fmt) // MOVCF = 010001
+ {
+ case 0x11: // D
+ DIP("movt.d f%d, f%d, %d", fd, fs, mov_cc);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_F64);
+
+ assign(t1, unop(Iop_1Sto32, binop(Iop_CmpEQ32, mkU32(0),
+ mkU32(mov_cc))));
+ assign(t2, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t1)),
+ binop(Iop_And32, binop(Iop_Shr32, getFCSR(),
+ mkU8(24 + mov_cc)), mkU32(0x1)),
+ binop(Iop_And32, binop(Iop_Shr32, getFCSR(),
+ mkU8(23)), mkU32(0x1))));
+
+ assign(t3, unop(Iop_1Sto32, binop(Iop_CmpEQ32, mkU32(1),
+ mkexpr(t2))));
+ assign(t4, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t3)),
+ getDReg(fs), getDReg(fd)));
+ putDReg(fd, mkexpr(t4));
+ break;
+ case 0x10: // S
+ DIP("movt.s f%d, f%d, %d", fd, fs, mov_cc);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_F64);
+ t5 = newTemp(Ity_F64);
+ t6 = newTemp(Ity_F64);
+ t7 = newTemp(Ity_I64);
+
+ assign(t5, unop(Iop_F32toF64, getFReg(fs)));
+ assign(t6, unop(Iop_F32toF64, getFReg(fd)));
+
+ assign(t1, unop(Iop_1Sto32, binop(Iop_CmpEQ32, mkU32(0),
+ mkU32(mov_cc))));
+ assign(t2, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t1)),
+ binop(Iop_And32, binop(Iop_Shr32,
+ getFCSR(), mkU8(24 + mov_cc)),
+ mkU32(0x1)), binop(Iop_And32,
+ binop(Iop_Shr32, getFCSR(),
+ mkU8(23)), mkU32(0x1))));
+
+ assign(t3, unop(Iop_1Sto32, binop(Iop_CmpEQ32, mkU32(1),
+ mkexpr(t2))));
+ assign(t4, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t3)),
+ mkexpr(t5), mkexpr(t6)));
+
+ putFReg(fd, binop(Iop_F64toF32, get_IR_roundingmode(),
+ mkexpr(t4)));
+ break;
+ default:
+ goto decode_failure;
+ }
+ } else if (tf == 0) //movf.fmt
+ {
+ UInt mov_cc = get_mov_cc(cins);
+ switch (fmt) // MOVCF = 010001
+ {
+ case 0x11: // D
+ DIP("movf.d f%d, f%d, %d", fd, fs, mov_cc);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_F64);
+
+ assign(t1, unop(Iop_1Sto32, binop(Iop_CmpEQ32,
+ mkU32(0), mkU32(mov_cc))));
+ assign(t2, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t1)),
+ binop(Iop_And32, binop(Iop_Shr32, getFCSR(),
+ mkU8(24 + mov_cc)), mkU32(0x1)),
+ binop(Iop_And32, binop(Iop_Shr32, getFCSR(),
+ mkU8(23)), mkU32(0x1))));
+
+ assign(t3, unop(Iop_1Sto32, binop(Iop_CmpEQ32, mkU32(1),
+ mkexpr(t2))));
+ assign(t4, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t3)),
+ getDReg(fd), getDReg(fs)));
+ putDReg(fd, mkexpr(t4));
+ break;
+ case 0x10: // S
+ DIP("movf.s f%d, f%d, %d", fd, fs, mov_cc);
+ {
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_F64);
+ t5 = newTemp(Ity_F64);
+ t6 = newTemp(Ity_F64);
+
+ assign(t5, unop(Iop_F32toF64, getFReg(fs)));
+ assign(t6, unop(Iop_F32toF64, getFReg(fd)));
+
+ assign(t1, unop(Iop_1Sto32, binop(Iop_CmpEQ32, mkU32(0),
+ mkU32(mov_cc))));
+ assign(t2, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t1)),
+ binop(Iop_And32, binop(Iop_Shr32, getFCSR(),
+ mkU8(24 + mov_cc)), mkU32(0x1)),
+ binop(Iop_And32, binop(Iop_Shr32, getFCSR(),
+ mkU8(23)), mkU32(0x1))));
+
+ assign(t3, unop(Iop_1Sto32, binop(Iop_CmpEQ32, mkU32(1),
+ mkexpr(t2))));
+ assign(t4, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t3)),
+ mkexpr(t6), mkexpr(t5)));
+ putFReg(fd, binop(Iop_F64toF32, get_IR_roundingmode(),
+ mkexpr(t4)));
+ }
+ break;
+ default:
+ goto decode_failure;
+ }
+ }
+
+ break; // MOVT.fmt
+
+ case 0x0: //add.fmt
+ switch (fmt) {
+ case 0x10: //S
+ {
+ DIP("add.s f%d, f%d, f%d\n", fd, fs, ft);
+ IRExpr *rm = get_IR_roundingmode();
+ putFReg(fd, mkWidenFromF32(tyF, triop(Iop_AddF32, rm,
+ getLoFromF64(tyF, getFReg(fs)),
+ getLoFromF64(tyF, getFReg(ft)))));
+ break;
+ }
+ case 0x11: //D
+ {
+ DIP("add.d f%d, f%d, f%d\n", fd, fs, ft);
+ IRExpr *rm = get_IR_roundingmode();
+ putDReg(fd, triop(Iop_AddF64, rm, getDReg(fs),
+ getDReg(ft)));
+ break;
+ }
+
+ case 0x4: //MTC1 (Move Word to Floating Point)
+ DIP("mtc1 r%d, f%d", rt, fs);
+ putFReg(fs, unop(Iop_ReinterpI32asF32, getIReg(rt)));
+ break;
+
+ case 0x0: //MFC1
+ DIP("mfc1 r%d, f%d", rt, fs);
+ putIReg(rt, unop(Iop_ReinterpF32asI32, getFReg(fs)));
+ break;
+
+ case 0x6: //CTC1
+ DIP("ctc1 r%d, f%d", rt, fs);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+ assign(t0, mkNarrowTo32(ty, getIReg(rt)));
+ if (fs == 25) { //FCCR
+ assign(t1, binop(Iop_Shl32, binop(Iop_And32, mkexpr(t0),
+ mkU32(0x000000FE)), mkU8(24)));
+ assign(t2, binop(Iop_And32, mkexpr(t0),
+ mkU32(0x01000000)));
+ assign(t3, binop(Iop_Shl32, binop(Iop_And32, mkexpr(t0),
+ mkU32(0x00000001)), mkU8(23)));
+ assign(t4, binop(Iop_And32, mkexpr(t0),
+ mkU32(0x007FFFFF)));
+ putFCSR(binop(Iop_Or32, binop(Iop_Or32, mkexpr(t1),
+ mkexpr(t2)), binop(Iop_Or32, mkexpr(t3),
+ mkexpr(t4))));
+ } else if (fs == 26) { //FEXR
+ assign(t1, binop(Iop_And32, getFCSR(), mkU32(0xFFFC0000)));
+ assign(t2, binop(Iop_And32, mkexpr(t0),
+ mkU32(0x0003F000)));
+ assign(t3, binop(Iop_And32, getFCSR(), mkU32(0x00000F80)));
+ assign(t4, binop(Iop_And32, mkexpr(t0),
+ mkU32(0x0000007C)));
+ assign(t5, binop(Iop_And32, getFCSR(), mkU32(0x00000003)));
+ putFCSR(binop(Iop_Or32, binop(Iop_Or32, binop(Iop_Or32,
+ mkexpr(t1), mkexpr(t2)), binop(Iop_Or32,
+ mkexpr(t3), mkexpr(t4))), mkexpr(t5)));
+ } else if (fs == 28) {
+ assign(t1, binop(Iop_And32, getFCSR(), mkU32(0xFE000000)));
+ assign(t2, binop(Iop_Shl32, binop(Iop_And32, mkexpr(t0),
+ mkU32(0x00000002)), mkU8(22)));
+ assign(t3, binop(Iop_And32, getFCSR(), mkU32(0x00FFF000)));
+ assign(t4, binop(Iop_And32, mkexpr(t0),
+ mkU32(0x00000F80)));
+ assign(t5, binop(Iop_And32, getFCSR(), mkU32(0x0000007C)));
+ assign(t6, binop(Iop_And32, mkexpr(t0),
+ mkU32(0x00000003)));
+ putFCSR(binop(Iop_Or32, binop(Iop_Or32, binop(Iop_Or32,
+ mkexpr(t1), mkexpr(t2)), binop(Iop_Or32,
+ mkexpr(t3), mkexpr(t4))), binop(Iop_Or32,
+ mkexpr(t5), mkexpr(t6))));
+ } else if (fs == 31) {
+ putFCSR(mkexpr(t0));
+ }
+ break;
+ case 0x2: //CFC1
+ DIP("cfc1 r%d, f%d", rt, fs);
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+ assign(t0, getFCSR());
+ if (fs == 0) {
+ putIReg(rt, mkWidenFrom32(ty,
+ IRExpr_Get(offsetof(VexGuestMIPS32State,
+ guest_FIR),
+ Ity_I32),
+ False));
+ } else if (fs == 25) {
+ assign(t1, mkU32(0x000000FF));
+ assign(t2, binop(Iop_Shr32, binop(Iop_And32, mkexpr(t0),
+ mkU32(0xFE000000)), mkU8(25)));
+ assign(t3, binop(Iop_Shr32, binop(Iop_And32, mkexpr(t0),
+ mkU32(0x00800000)), mkU8(23)));
+ putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32,
+ binop(Iop_Or32, mkexpr(t1), mkexpr(t2)),
+ mkexpr(t3)), False));
+ } else if (fs == 26) {
+ assign(t1, mkU32(0xFFFFF07C));
+ assign(t2, binop(Iop_And32, mkexpr(t0),
+ mkU32(0x0003F000)));
+ assign(t3, binop(Iop_And32, mkexpr(t0),
+ mkU32(0x0000007C)));
+ putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32,
+ binop(Iop_Or32, mkexpr(t1), mkexpr(t2)),
+ mkexpr(t3)), False));
+ } else if (fs == 28) {
+ assign(t1, mkU32(0x00000F87));
+ assign(t2, binop(Iop_And32, mkexpr(t0),
+ mkU32(0x00000F83)));
+ assign(t3, binop(Iop_Shr32, binop(Iop_And32, mkexpr(t0),
+ mkU32(0x01000000)), mkU8(22)));
+ putIReg(rt, mkWidenFrom32(ty, binop(Iop_Or32,
+ binop(Iop_Or32, mkexpr(t1), mkexpr(t2)),
+ mkexpr(t3)), False));
+ } else if (fs == 31) {
+ putIReg(rt, mkWidenFrom32(ty, getFCSR(), False));
+ }
+ break;
+ default:
+ goto decode_failure;
+ }
+ break; //case 0x0: //add.fmt
+
+ case 0x21: //CVT.D
+ switch (fmt) {
+ case 0x10: //S
+ DIP("cvt.d.s f%d, f%d", fd, fs);
+ putDReg(fd, unop(Iop_F32toF64, getFReg(fs)));
+ break;
+
+ case 0x14:
+ { //W
+ DIP("cvt.d.w %d, %d\n", fd, fs);
+ t0 = newTemp(Ity_I32);
+ assign(t0, unop(Iop_ReinterpF32asI32, getFReg(fs)));
+ putDReg(fd, unop(Iop_I32StoF64, mkexpr(t0)));
+ }
+ break;
+
+ default:
+ goto decode_failure;
+ }
+ break; //CVT.D
+
+ case 0x20: //cvt.s
+ switch (fmt) {
+ case 0x14: //W
+ DIP("cvt.s.w %d, %d\n", fd, fs);
+ t0 = newTemp(Ity_I32);
+ assign(t0, unop(Iop_ReinterpF32asI32, getFReg(fs)));
+ putFReg(fd, binop(Iop_I32StoF32, get_IR_roundingmode(),
+ mkexpr(t0)));
+ break;
+
+ case 0x11: //D
+ DIP("cvt.s.d %d, %d\n", fd, fs);
+ putFReg(fd, binop(Iop_F64toF32, get_IR_roundingmode(),
+ getDReg(fs)));
+ break;
+
+ default:
+ goto decode_failure;
+ }
+ break; //cvt.s
+
+ case 0x24: //cvt.w
+ switch (fmt) {
+ case 0x10: //S
+ DIP("cvt.w.s %d, %d\n", fd, fs);
+ putFReg(fd, binop(Iop_RoundF32toInt, get_IR_roundingmode(),
+ getFReg(fs)));
+ break;
+
+ case 0x11:
+ { //D
+ DIP("cvt.w.d %d, %d\n", fd, fs);
+ t0 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_F64toI32S, get_IR_roundingmode(),
+ getDReg(fs)));
+
+ putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
+ }
+ break;
+
+ default:
+ goto decode_failure;
+
+ }
+ break;
+
+ case 0x09: //TRUNC.L
+ switch (fmt) {
+ case 0x10: //S
+ DIP("trunc.l.s %d, %d\n", fd, fs);
+ goto decode_failure;
+
+ case 0x11: //D
+ DIP("trunc.l.d %d, %d\n", fd, fs);
+ goto decode_failure;
+
+ default:
+ goto decode_failure;
+
+ }
+ break; //trunc.l
+
+ case 0x0C: //ROUND.W.fmt
+ switch (fmt) {
+ case 0x10: //S
+ DIP("round.w.s f%d, f%d\n", fd, fs);
+ putFReg(fd, binop(Iop_RoundF32toInt, mkU32(0x0),
+ getFReg(fs)));
+ break;
+
+ case 0x11: //D
+ DIP("round.w.d f%d, f%d\n", fd, fs);
+ t0 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_F64toI32S, mkU32(0x0), getDReg(fs)));
+
+ putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
+ break;
+
+ default:
+ goto decode_failure;
+
+ }
+ break; //ROUND.W.fmt
+
+ case 0x0F: //FLOOR.W.fmt
+ switch (fmt) {
+ case 0x10: //S
+ DIP("floor.w.s f%d, f%d\n", fd, fs);
+ putFReg(fd, binop(Iop_RoundF32toInt, mkU32(0x1),
+ getFReg(fs)));
+ break;
+
+ case 0x11: //D
+ DIP("floor.w.d f%d, f%d\n", fd, fs);
+ t0 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_F64toI32S, mkU32(0x1), getDReg(fs)));
+
+ putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
+ break;
+
+ default:
+ goto decode_failure;
+
+ }
+ break; //FLOOR.W.fmt
+
+ case 0x0D: //TRUNC.W
+ switch (fmt) {
+ case 0x10: //S
+ DIP("trunc.w.s %d, %d\n", fd, fs);
+ putFReg(fd, binop(Iop_RoundF32toInt, mkU32(0x3),
+ getFReg(fs)));
+ break;
+
+ case 0x11: //D
+ DIP("trunc.w.d %d, %d\n", fd, fs);
+ t0 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_F64toI32S, mkU32(0x3), getDReg(fs)));
+
+ putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
+ break;
+
+ default:
+ goto decode_failure;
+
+ }
+ break;
+ case 0x0E: //CEIL.W.fmt
+ switch (fmt) {
+ case 0x10: //S
+ DIP("ceil.w.s %d, %d\n", fd, fs);
+ putFReg(fd, binop(Iop_RoundF32toInt, mkU32(0x2),
+ getFReg(fs)));
+ break;
+
+ case 0x11: //D
+ DIP("ceil.w.d %d, %d\n", fd, fs);
+ t0 = newTemp(Ity_I32);
+
+ assign(t0, binop(Iop_F64toI32S, mkU32(0x2), getDReg(fs)));
+
+ putFReg(fd, unop(Iop_ReinterpI32asF32, mkexpr(t0)));
+ break;
+
+ default:
+ goto decode_failure;
+
+ }
+ break;
+ case 0x0A: //CEIL.L.fmt
+ switch (fmt) {
+ case 0x10: //S
+ DIP("ceil.l.s %d, %d\n", fd, fs);
+ goto decode_failure;
+
+ case 0x11: //D
+ DIP("ceil.l.d %d, %d\n", fd, fs);
+
+ goto decode_failure;
+
+ default:
+ goto decode_failure;
+
+ }
+ break;
+
+ case 0x16: //RSQRT.fmt
+ switch (fmt) {
+ case 0x10:
+ { //S
+ DIP("rsqrt.s %d, %d\n", fd, fs);
+ IRExpr *rm = get_IR_roundingmode();
+ putFReg(fd, mkWidenFromF32(tyF, triop(Iop_DivF32, rm,
+ unop(Iop_ReinterpI32asF32, mkU32(0x3F800000)),
+ binop(Iop_SqrtF32, rm, getLoFromF64(tyF,
+ getFReg(fs))))));
+ break;
+ }
+ case 0x11:
+ { //D
+ DIP("rsqrt.d %d, %d\n", fd, fs);
+ IRExpr *rm = get_IR_roundingmode();
+ putDReg(fd, triop(Iop_DivF64, rm,
+ unop(Iop_ReinterpI64asF64,
+ mkU64(0x3FF0000000000000ULL)),
+ binop(Iop_SqrtF64, rm, getDReg(fs))));
+ break;
+ }
+ default:
+ goto decode_failure;
+
+ }
+ break;
+
+ default:
+ if (dis_instr_CCondFmt(cins))
+ break;
+ goto decode_failure;
+
+ }
+
+ }
+ }
+ break; /*COP1 */
+ case 0x10: /* COP0 */
+ if (rs == 0) { /* MFC0 */
+ DIP("mfc0 r%d, r%d, %d", rt, rd, sel);
+
+ IRTemp val = newTemp(Ity_I32);
+ IRExpr** args = mkIRExprVec_2 (mkU32(rd), mkU32(sel));
+ IRDirty *d = unsafeIRDirty_1_N(val,
+ 0,
+ "mips32_dirtyhelper_mfc0",
+ &mips32_dirtyhelper_mfc0,
+ args);
+
+ stmt(IRStmt_Dirty(d));
+ putIReg(rt, mkexpr(val));
+ } else
+ goto decode_failure;
+ break;
+ case 0x31: /* LWC1 */
+ /* Load Word to Floating Point - LWC1 (MIPS32) */
+ LOAD_STORE_PATTERN;
+ putFReg(ft, load(Ity_F32, mkexpr(t1)));
+
+ DIP("lwc1 f%d, %d(r%d)", ft, imm, rs);
+ break;
+
+ case 0x39: /* SWC1 */
+ LOAD_STORE_PATTERN;
+ store(mkexpr(t1), getFReg(ft));
+ DIP("swc1 f%d, %d(r%d)", ft, imm, rs);
+ break;
+
+ case 0x33: /* PREF */
+ DIP("pref)");
+ break;
+
+ case 0x35:
+ /* Load Doubleword to Floating Point - LDC1 (MIPS32) */
+ LOAD_STORE_PATTERN;
+
+ t2 = newTemp(Ity_I32);
+ assign(t2, binop(Iop_Add32, getIReg(rs),
+ mkU32(extend_s_16to32(imm + 4))));
+
+#if defined (_MIPSEL)
+ putFReg(ft, load(Ity_F32, mkexpr(t1)));
+ putFReg(ft + 1, load(Ity_F32, mkexpr(t2)));
+#elif defined (_MIPSEB)
+ putFReg(ft + 1, load(Ity_F32, mkexpr(t1)));
+ putFReg(ft, load(Ity_F32, mkexpr(t2)));
+#endif
+ DIP("ldc1 f%d, %d(%d) \n", rt, imm, rs);
+ break;
+
+ case 0x3D:
+ /* Store Doubleword from Floating Point - SDC1 */
+ LOAD_STORE_PATTERN;
+
+ t2 = newTemp(Ity_I32);
+ assign(t2, binop(Iop_Add32, getIReg(rs),
+ mkU32(extend_s_16to32(imm + 4))));
+
+#if defined (_MIPSEL)
+ store(mkexpr(t1), getFReg(ft));
+ store(mkexpr(t2), getFReg(ft + 1));
+#elif defined (_MIPSEB)
+ store(mkexpr(t1), getFReg(ft + 1));
+ store(mkexpr(t2), getFReg(ft));
+#endif
+ DIP("sdc1 f%d, %d(%d)", ft, imm, rs);
+ break;
+
+ case 0x23: /* LW */
+ DIP("lw r%d, %d(r%d)", rt, imm, rs);
+ LOAD_STORE_PATTERN;
+ putIReg(rt, mkWidenFrom32(ty, load(Ity_I32, mkexpr(t1)), True));
+ break;
+
+ case 0x20: /* LB */
+ DIP("lb");
+ LOAD_STORE_PATTERN;
+ putIReg(rt, unop(Iop_8Sto32, load(Ity_I8, mkexpr(t1))));
+ break;
+
+ case 0x24: /* LBU */
+ DIP("lbu");
+ LOAD_STORE_PATTERN;
+ putIReg(rt, unop(Iop_8Uto32, load(Ity_I8, mkexpr(t1))));
+ break;
+
+ case 0x21: /* LH */
+ DIP("lh");
+ LOAD_STORE_PATTERN;
+ putIReg(rt, unop(Iop_16Sto32, load(Ity_I16, mkexpr(t1))));
+ break;
+
+ case 0x25: /* LHU */
+ DIP("lhu");
+ LOAD_STORE_PATTERN;
+ putIReg(rt, unop(Iop_16Uto32, load(Ity_I16, mkexpr(t1))));
+ break;
+
+ case 0x0F: /* LUI */
+ p = (imm << 16);
+ DIP("lui rt: %d, imm: %d, imm << 16: %d", rt, imm, p);
+ if ((vex_traceflags & VEX_TRACE_FE) && !mode64)
+ ppIRExpr(mkU32(p));
+ putIReg(rt, mkU32(p));
+ break;
+
+ case 0x13: /* COP1X */
+ switch (function) {
+ case 0x0: { /* LWXC1 */
+ /* Load Word Indexed to Floating Point - LWXC1 (MIPS32r2) */
+ DIP("lwxc1 f%d, r%d(r%d) \n", fd, rt, rs);
+ t0 = newTemp(Ity_I32);
+ assign(t0, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
+ putFReg(fd, load(Ity_F32, mkexpr(t0)));
+ break;
+ }
+
+ case 0x1: { /* LDXC1 */
+ /* Load Doubleword Indexed to Floating Point - LDXC1 (MIPS32r2) */
+ t0 = newTemp(Ity_I32);
+ assign(t0, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
+
+ t1 = newTemp(Ity_I32);
+ assign(t1, binop(Iop_Add32, mkexpr(t0), mkU32(4)));
+
+#if defined (_MIPSEL)
+ putFReg(fd, load(Ity_F32, mkexpr(t0)));
+ putFReg(fd + 1, load(Ity_F32, mkexpr(t1)));
+#elif defined (_MIPSEB)
+ putFReg(fd + 1, load(Ity_F32, mkexpr(t0)));
+ putFReg(fd, load(Ity_F32, mkexpr(t1)));
+#endif
+ DIP("ldxc1 f%d, r%d(r%d) \n", fd, rt, rs);
+ break;
+ }
+
+ case 0x5: // Load Doubleword Indexed Unaligned
+ // to Floating Point - LUXC1; MIPS32r2
+ DIP("luxc1 f%d, r%d(r%d) \n", fd, rt, rs);
+ t0 = newTemp(Ity_I64);
+ t1 = newTemp(Ity_I64);
+ assign(t0, binop(Iop_Add64, getIReg(rs), getIReg(rt)));
+ assign(t1, binop(Iop_And64, mkexpr(t0), mkU64(0xfffffffffffffff8ULL)));
+ putFReg(fd, load(Ity_F64, mkexpr(t1)));
+ break;
+
+ case 0x8: { /* SWXC1 */
+ /* Store Word Indexed from Floating Point - SWXC1 */
+ t0 = newTemp(Ity_I32);
+ assign(t0, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
+
+ store(mkexpr(t0), getFReg(fs));
+
+ DIP("swxc1 f%d, r%d(r%d)", ft, rt, rs);
+ break;
+ }
+ case 0x9: { /* SDXC1 */
+ /* Store Doubleword Indexed from Floating Point - SDXC1 */
+ t0 = newTemp(Ity_I32);
+ assign(t0, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
+
+ t1 = newTemp(Ity_I32);
+ assign(t1, binop(Iop_Add32, mkexpr(t0), mkU32(4)));
+
+#if defined (_MIPSEL)
+ store(mkexpr(t0), getFReg(fs));
+ store(mkexpr(t1), getFReg(fs + 1));
+#elif defined (_MIPSEB)
+ store(mkexpr(t0), getFReg(fs + 1));
+ store(mkexpr(t1), getFReg(fs));
+#endif
+
+ DIP("sdc1 f%d, %d(%d)", ft, imm, rs);
+ break;
+ }
+ case 0x0F: {
+ DIP("prefx");
+ break;
+ }
+ case 0x20: { /* MADD.S */
+ DIP("madd.s f%d, f%d, f%d, f%d", fmt, ft, fs, fd);
+ IRExpr *rm = get_IR_roundingmode();
+ t1 = newTemp(Ity_F32);
+ assign(t1, triop(Iop_MulF32, rm, getLoFromF64(tyF, getFReg(fs)),
+ getLoFromF64(tyF, getFReg(ft))));
+
+ putFReg(fd, mkWidenFromF32(tyF, triop(Iop_AddF32, rm, mkexpr(t1),
+ getLoFromF64(tyF, getFReg(fmt)))));
+ break; /* MADD.S */
+ }
+ case 0x21: { /* MADD.D */
+ DIP("madd.d f%d, f%d, f%d, f%d", fmt, ft, fs, fd);
+ IRExpr *rm = get_IR_roundingmode();
+ t1 = newTemp(Ity_F64);
+ assign(t1, triop(Iop_MulF64, rm, getDReg(fs), getDReg(ft)));
+
+ putDReg(fd, triop(Iop_AddF64, rm, mkexpr(t1), getDReg(fmt)));
+ break; /* MADD.D */
+ }
+ case 0x28: { /* MSUB.S */
+ DIP("msub.s f%d, f%d, f%d, f%d", fmt, ft, fs, fd);
+ IRExpr *rm = get_IR_roundingmode();
+ t1 = newTemp(Ity_F32);
+ assign(t1, triop(Iop_MulF32, rm, getLoFromF64(tyF, getFReg(fs)),
+ getLoFromF64(tyF, getFReg(ft))));
+
+ putFReg(fd, mkWidenFromF32(tyF, triop(Iop_SubF32, rm,
+ mkexpr(t1), getLoFromF64(tyF, getFReg(fmt)))));
+ break; /* MSUB.S */
+ }
+ case 0x29: { /* MSUB.D */
+ DIP("msub.d f%d, f%d, f%d, f%d", fmt, ft, fs, fd);
+ IRExpr *rm = get_IR_roundingmode();
+ t1 = newTemp(Ity_F64);
+ assign(t1, triop(Iop_MulF64, rm, getDReg(fs), getDReg(ft)));
+
+ putDReg(fd, triop(Iop_SubF64, rm, mkexpr(t1), getDReg(fmt)));
+ break; /* MSUB.D */
+ }
+ case 0x30: { /* NMADD.S */
+ DIP("nmadd.s f%d, f%d, f%d, f%d", fmt, ft, fs, fd);
+ IRExpr *rm = get_IR_roundingmode();
+ t1 = newTemp(Ity_F32);
+ t2 = newTemp(Ity_F32);
+ assign(t1, triop(Iop_MulF32, rm, getLoFromF64(tyF, getFReg(fs)),
+ getLoFromF64(tyF, getFReg(ft))));
+
+ assign(t2, triop(Iop_AddF32, rm, mkexpr(t1),
+ getLoFromF64(tyF, getFReg(fmt))));
+
+ putFReg(fd, mkWidenFromF32(tyF, unop(Iop_NegF32, mkexpr(t2))));
+ break; /* NMADD.S */
+ }
+ case 0x31: { /* NMADD.D */
+ DIP("nmadd.d f%d, f%d, f%d, f%d", fmt, ft, fs, fd);
+ IRExpr *rm = get_IR_roundingmode();
+ t1 = newTemp(Ity_F64);
+ t2 = newTemp(Ity_F64);
+ assign(t1, triop(Iop_MulF64, rm, getDReg(fs), getDReg(ft)));
+
+ assign(t2, triop(Iop_AddF64, rm, mkexpr(t1), getDReg(fmt)));
+ putDReg(fd, unop(Iop_NegF64, mkexpr(t2)));
+ break; /* NMADD.D */
+ }
+ case 0x38: { /* NMSUBB.S */
+ DIP("nmsub.s f%d, f%d, f%d, f%d", fmt, ft, fs, fd);
+ IRExpr *rm = get_IR_roundingmode();
+ t1 = newTemp(Ity_F32);
+ t2 = newTemp(Ity_F32);
+ assign(t1, triop(Iop_MulF32, rm, getLoFromF64(tyF, getFReg(fs)),
+ getLoFromF64(tyF, getFReg(ft))));
+
+ assign(t2, triop(Iop_SubF32, rm, mkexpr(t1), getLoFromF64(tyF,
+ getFReg(fmt))));
+
+ putFReg(fd, mkWidenFromF32(tyF, unop(Iop_NegF32, mkexpr(t2))));
+ break; /* NMSUBB.S */
+ }
+ case 0x39: { /* NMSUBB.D */
+ DIP("nmsub.d f%d, f%d, f%d, f%d", fmt, ft, fs, fd);
+ IRExpr *rm = get_IR_roundingmode();
+ t1 = newTemp(Ity_F64);
+ t2 = newTemp(Ity_F64);
+ assign(t1, triop(Iop_MulF64, rm, getDReg(fs), getDReg(ft)));
+
+ assign(t2, triop(Iop_SubF64, rm, mkexpr(t1), getDReg(fmt)));
+ putDReg(fd, unop(Iop_NegF64, mkexpr(t2)));
+ break; /* NMSUBB.D */
+ }
+
+ default:
+ goto decode_failure;
+ }
+ break;
+
+ case 0x22: /* LWL */
+
+ DIP("lwl");
+ {
+ /* t1 = addr */
+ t1 = newTemp(Ity_I32);
+#if defined (_MIPSEL)
+ assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
+#elif defined (_MIPSEB)
+ assign(t1, binop(Iop_Xor32, mkU32(0x3), binop(Iop_Add32, getIReg(rs),
+ mkU32(extend_s_16to32(imm)))));
+#endif
+
+ /* t2 = word addr */
+ /* t4 = addr mod 4 */
+ LWX_SWX_PATTERN;
+
+ /* t3 = word content - shifted */
+ t3 = newTemp(Ity_I32);
+ assign(t3, binop(Iop_Shl32, load(Ity_I32, mkexpr(t2)), narrowTo(Ity_I8,
+ binop(Iop_Shl32, binop(Iop_Sub32, mkU32(0x03), mkexpr(t4)),
+ mkU8(3)))));
+
+ /* rt content - adjusted */
+ t5 = newTemp(Ity_I32);
+ assign(t5, binop(Iop_And32, getIReg(rt), binop(Iop_Shr32,
+ mkU32(0xFFFFFFFF), narrowTo(Ity_I8, binop(Iop_Shl32,
+ binop(Iop_Add32, mkexpr(t4), mkU32(0x1)), mkU8(0x3))))));
+
+ putIReg(rt, binop(Iop_Or32, mkexpr(t5), mkexpr(t3)));
+ }
+ break;
+
+ case 0x26: /* LWR */
+
+ DIP("lwr");
+ {
+ /* t1 = addr */
+ t1 = newTemp(Ity_I32);
+#if defined (_MIPSEL)
+ assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
+#elif defined (_MIPSEB)
+ assign(t1, binop(Iop_Xor32, mkU32(0x3), binop(Iop_Add32, getIReg(rs),
+ mkU32(extend_s_16to32(imm)))));
+#endif
+
+ /* t2 = word addr */
+ /* t4 = addr mod 4 */
+ LWX_SWX_PATTERN;
+
+ /* t3 = word content - shifted */
+ t3 = newTemp(Ity_I32);
+ assign(t3, binop(Iop_Shr32, load(Ity_I32, mkexpr(t2)),
+ narrowTo(Ity_I8, binop(Iop_Shl32, mkexpr(t4),
+ mkU8(3)))));
+
+ /* rt content - adjusted */
+ t5 = newTemp(Ity_I32);
+ assign(t5, binop(Iop_And32, getIReg(rt), unop(Iop_Not32,
+ binop(Iop_Shr32, mkU32(0xFFFFFFFF), narrowTo(Ity_I8,
+ binop(Iop_Shl32, mkexpr(t4), mkU8(0x3)))))));
+
+ putIReg(rt, binop(Iop_Or32, mkexpr(t5), mkexpr(t3)));
+ }
+ break;
+
+ case 0x2B: /* SW */
+ DIP("sw r%d, %d(r%d)", rt, imm, rs);
+ LOAD_STORE_PATTERN;
+ store(mkexpr(t1), mkNarrowTo32(ty, getIReg(rt)));
+ break;
+
+ case 0x28: /* SB */
+ DIP("sb");
+ LOAD_STORE_PATTERN;
+ store(mkexpr(t1), narrowTo(Ity_I8, getIReg(rt)));
+ break;
+
+ case 0x29: /* SH */
+ DIP("sh\n");
+ LOAD_STORE_PATTERN;
+ store(mkexpr(t1), narrowTo(Ity_I16, getIReg(rt)));
+ break;
+
+ case 0x2A: /* SWL */
+
+ DIP("swl\n");
+ {
+ /* t1 = addr */
+ t1 = newTemp(Ity_I32);
+#if defined (_MIPSEL)
+ assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
+#elif defined (_MIPSEB)
+ assign(t1, binop(Iop_Xor32, mkU32(0x3), binop(Iop_Add32, getIReg(rs),
+ mkU32(extend_s_16to32(imm)))));
+#endif
+
+ /* t2 = word addr */
+ /* t4 = addr mod 4 */
+ LWX_SWX_PATTERN;
+
+ /* t3 = rt content - shifted */
+ t3 = newTemp(Ity_I32);
+ assign(t3, binop(Iop_Shr32, getIReg(rt), narrowTo(Ity_I8,
+ binop(Iop_Shl32, binop(Iop_Sub32, mkU32(0x03), mkexpr(t4)),
+ mkU8(3)))));
+
+ /* word content - adjusted */
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+ t7 = newTemp(Ity_I32);
+ t8 = newTemp(Ity_I32);
+
+ // neg(shr(0xFFFFFFFF, mul(sub(3,n), 8)))
+ assign(t5, binop(Iop_Mul32, binop(Iop_Sub32, mkU32(0x3), mkexpr(t4)),
+ mkU32(0x8)));
+
+ assign(t6, binop(Iop_Shr32, mkU32(0xFFFFFFFF), narrowTo(Ity_I8,
+ mkexpr(t5))));
+ assign(t7, binop(Iop_Xor32, mkU32(0xFFFFFFFF), mkexpr(t6)));
+ assign(t8, binop(Iop_And32, load(Ity_I32, mkexpr(t2)), mkexpr(t7)));
+ store(mkexpr(t2), binop(Iop_Or32, mkexpr(t8), mkexpr(t3)));
+ }
+ break;
+
+ case 0x2E: /* SWR */
+
+ DIP("swr");
+ {
+ /* t1 = addr */
+ t1 = newTemp(Ity_I32);
+#if defined (_MIPSEL)
+ assign(t1, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
+#elif defined (_MIPSEB)
+ assign(t1, binop(Iop_Xor32, mkU32(0x3), binop(Iop_Add32, getIReg(rs),
+ mkU32(extend_s_16to32(imm)))));
+#endif
+
+ /* t2 = word addr */
+ /* t4 = addr mod 4 */
+ LWX_SWX_PATTERN;
+
+ /* t3 = rt content - shifted */
+ t3 = newTemp(Ity_I32);
+ assign(t3, binop(Iop_Shl32, getIReg(rt), narrowTo(Ity_I8,
+ binop(Iop_Shl32, mkexpr(t4), mkU8(3)))));
+
+ /* word content - adjusted */
+ t5 = newTemp(Ity_I32);
+ assign(t5, binop(Iop_And32, load(Ity_I32, mkexpr(t2)), unop(Iop_Not32,
+ binop(Iop_Shl32, mkU32(0xFFFFFFFF), narrowTo(Ity_I8,
+ binop(Iop_Shl32, mkexpr(t4), mkU8(0x3)))))));
+
+ store(mkexpr(t2), binop(Iop_Xor32, mkexpr(t5), mkexpr(t3)));
+ }
+ break;
+
+ case 0x1C: /*Special2 */
+ switch (function) {
+ case 0x02: { /* MUL */
+ DIP("mul");
+ putIReg(rd, binop(Iop_Mul32, getIReg(rs), getIReg(rt)));
+ break;
+ }
+
+ case 0x00: { /* MADD */
+ DIP("madd");
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I64);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+
+ assign(t1, getHI());
+ assign(t2, getLO());
+
+ assign(t3, binop(Iop_MullS32, getIReg(rs), getIReg(rt)));
+
+ assign(t4, binop(Iop_Add32, mkexpr(t2), unop(Iop_64to32,
+ mkexpr(t3))));
+
+ assign(t5, unop(Iop_1Uto32, binop(Iop_CmpLT32U, mkexpr(t4),
+ unop(Iop_64to32, mkexpr(t3)))));
+ assign(t6, binop(Iop_Add32, mkexpr(t5), mkexpr(t1)));
+
+ putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32, mkexpr(t3))));
+ putLO(mkexpr(t4));
+ break;
+ }
+
+ case 0x01: { /* MADDU */
+ DIP("maddu");
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I64);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+
+ assign(t1, getHI());
+ assign(t2, getLO());
+
+ assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt)));
+
+ assign(t4, binop(Iop_Add32, mkexpr(t2), unop(Iop_64to32,
+ mkexpr(t3))));
+ assign(t5, unop(Iop_1Uto32, binop(Iop_CmpLT32U, mkexpr(t4),
+ unop(Iop_64to32, mkexpr(t3)))));
+ assign(t6, binop(Iop_Add32, mkexpr(t5), mkexpr(t1)));
+
+ putHI(binop(Iop_Add32, mkexpr(t6), unop(Iop_64HIto32, mkexpr(t3))));
+ putLO(mkexpr(t4));
+ break;
+ }
+
+ case 0x04: { /* MSUB */
+ DIP("msub");
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I64);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+
+ assign(t1, getHI());
+ assign(t2, getLO());
+
+ assign(t3, binop(Iop_MullS32, getIReg(rs), getIReg(rt)));
+ assign(t4, unop(Iop_64to32, mkexpr(t3))); //new lo
+
+ //if lo<lo(mul) hi = hi - 1
+ assign(t5, unop(Iop_1Sto32, binop(Iop_CmpLT32U, mkexpr(t2),
+ mkexpr(t4))));
+
+ assign(t6, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t5)), mkexpr(t1),
+ binop(Iop_Sub32, mkexpr(t1), mkU32(0x1))));
+
+ putHI(binop(Iop_Sub32, mkexpr(t6), unop(Iop_64HIto32, mkexpr(t3))));
+ putLO(binop(Iop_Sub32, mkexpr(t2), mkexpr(t4)));
+ break;
+ }
+
+ case 0x05: { /* MSUBU */
+ DIP("msubu");
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I64);
+ t4 = newTemp(Ity_I32);
+ t5 = newTemp(Ity_I32);
+ t6 = newTemp(Ity_I32);
+
+ assign(t1, getHI());
+ assign(t2, getLO());
+
+ assign(t3, binop(Iop_MullU32, getIReg(rs), getIReg(rt)));
+ assign(t4, unop(Iop_64to32, mkexpr(t3))); //new lo
+
+ //if lo<lo(mul) hi = hi - 1
+ assign(t5, unop(Iop_1Sto32, binop(Iop_CmpLT32U, mkexpr(t2),
+ mkexpr(t4))));
+
+ assign(t6, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t5)),
+ mkexpr(t1), binop(Iop_Sub32, mkexpr(t1), mkU32(0x1))));
+
+ putHI(binop(Iop_Sub32, mkexpr(t6), unop(Iop_64HIto32, mkexpr(t3))));
+ putLO(binop(Iop_Sub32, mkexpr(t2), mkexpr(t4)));
+ break;
+ }
+
+ case 0x20: { /* CLZ */
+ DIP("clz r%d, r%d", rd, rs);
+ t1 = newTemp(Ity_I32);
+ assign(t1, unop(Iop_1Sto32, binop(Iop_CmpEQ32, getIReg(rs),
+ mkU32(0))));
+ putIReg(rd, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t1)),
+ unop(Iop_Clz32, getIReg(rs)), mkU32(0x00000020)));
+ break;
+ }
+
+ case 0x21: { /* CLO */
+ DIP("clo r%d, r%d", rd, rs);
+ t1 = newTemp(Ity_I32);
+ assign(t1, unop(Iop_1Sto32, binop(Iop_CmpEQ32, getIReg(rs),
+ mkU32(0xffffffff))));
+ putIReg(rd, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t1)),
+ unop(Iop_Clz32, unop(Iop_Not32, getIReg(rs))),
+ mkU32(0x00000020)));
+ break;
+ }
+
+ default:
+ goto decode_failure;
+ }
+ break;
+
+ case 0x1F: /*Special3 */
+ switch (function) {
+ case 0x3B:
+ /*RDHWR*/ {
+ DIP("rdhwr r%d, r%d", rt, rd);
+ if (rd == 29) {
+ putIReg(rt, getULR());
+ } else
+ goto decode_failure;
+ break;
+ }
+ case 0x04:
+ /*INS*/ msb = get_msb(cins);
+ lsb = get_lsb(cins);
+
+ size = msb - lsb + 1;
+
+ vassert(lsb + size <= 32);
+ vassert(lsb + size > 0);
+
+ DIP("ins size:%d msb:%d lsb:%d", size, msb, lsb);
+ /*put size bits from rs at the pos in temporary */
+ t0 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ /*shift left for 32 - size to clear leading bits and get zeros
+ at the end */
+ assign(t0, binop(Iop_Shl32, getIReg(rs), mkU8(32 - size)));
+ /*now set it at pos */
+ t1 = newTemp(Ity_I32);
+ assign(t1, binop(Iop_Shr32, mkexpr(t0), mkU8(32 - size - lsb)));
+
+ if (lsb > 0) {
+ t2 = newTemp(Ity_I32);
+ /*clear everything but lower pos bits from rt */
+ assign(t2, binop(Iop_Shl32, getIReg(rt), mkU8(32 - lsb)));
+ assign(t3, binop(Iop_Shr32, mkexpr(t2), mkU8(32 - lsb)));
+ }
+
+ if (msb < 31) {
+ t4 = newTemp(Ity_I32);
+ /*clear everything but upper msb + 1 bits from rt */
+ assign(t4, binop(Iop_Shr32, getIReg(rt), mkU8(msb + 1)));
+ t5 = newTemp(Ity_I32);
+ assign(t5, binop(Iop_Shl32, mkexpr(t4), mkU8(msb + 1)));
+
+ /*now combine these registers */
+ if (lsb > 0) {
+ t6 = newTemp(Ity_I32);
+ assign(t6, binop(Iop_Or32, mkexpr(t5), mkexpr(t1)));
+ putIReg(rt, binop(Iop_Or32, mkexpr(t6), mkexpr(t3)));
+ } else {
+ putIReg(rt, binop(Iop_Or32, mkexpr(t1), mkexpr(t5)));
+ }
+ }
+
+ else {
+ putIReg(rt, binop(Iop_Or32, mkexpr(t1), mkexpr(t3)));
+
+ }
+ break;
+
+ case 0x00:
+ /*EXT*/ msb = get_msb(cins);
+ lsb = get_lsb(cins);
+ size = msb + 1;
+ DIP("ext size:%d msb:%d lsb:%d", size, msb, lsb);
+ vassert(lsb + size <= 32);
+ vassert(lsb + size > 0);
+ /*put size bits from rs at the top of in temporary */
+ if (lsb + size < 32) {
+ t0 = newTemp(Ity_I32);
+ assign(t0, binop(Iop_Shl32, getIReg(rs), mkU8(32 - lsb - size)));
+ putIReg(rt, binop(Iop_Shr32, mkexpr(t0), mkU8(32 - size)));
+ } else {
+ putIReg(rt, binop(Iop_Shr32, getIReg(rs), mkU8(32 - size)));
+
+ }
+ break;
+
+ case 0x20:
+ /*BSHFL*/ switch (sa) {
+
+ case 0x10:
+ /*SEB*/ DIP("seb");
+ putIReg(rd, unop(Iop_8Sto32, unop(Iop_32to8, getIReg(rt))));
+ break;
+
+ case 0x18:
+ /*SEH*/ DIP("seh");
+ putIReg(rd, unop(Iop_16Sto32, unop(Iop_32to16, getIReg(rt))));
+ break;
+
+ case 0x02:
+ /*WSBH*/ DIP("wsbh");
+ t0 = newTemp(Ity_I32);
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ assign(t0, binop(Iop_Shl32, binop(Iop_And32, getIReg(rt),
+ mkU32(0x00FF0000)), mkU8(0x8)));
+ assign(t1, binop(Iop_Shr32, binop(Iop_And32, getIReg(rt),
+ mkU32(0xFF000000)), mkU8(0x8)));
+ assign(t2, binop(Iop_Shl32, binop(Iop_And32, getIReg(rt),
+ mkU32(0x000000FF)), mkU8(0x8)));
+ assign(t3, binop(Iop_Shr32, binop(Iop_And32, getIReg(rt),
+ mkU32(0x0000FF00)), mkU8(0x8)));
+ putIReg(rd, binop(Iop_Or32, binop(Iop_Or32, mkexpr(t0),
+ mkexpr(t1)), binop(Iop_Or32, mkexpr(t2), mkexpr(t3))));
+ break;
+
+ default:
+ goto decode_failure;
+
+ }
+ break;
+ /*BSHFL*/ default:
+ goto decode_failure;
+
+ }
+ break; /*Special3 */
+
+ case 0x3B:
+ if (0x3B == function && (archinfo->hwcaps & VEX_PRID_COMP_BROADCOM)) {
+ /*RDHWR*/
+ DIP("rdhwr r%d, r%d", rt, rd);
+ if (rd == 29) {
+ putIReg(rt, getULR());
+ } else
+ goto decode_failure;
+ break;
+ } else {
+ goto decode_failure;
+ }
+
+ case 0x00: /*Special */
+
+ switch (function) {
+ case 0x1: {
+ UInt mov_cc = get_mov_cc(cins);
+ if (tf == 0) { /* MOVF */
+ DIP("movf r%d, r%d, %d", rd, rs, mov_cc);
+ {
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+
+ assign(t1, unop(Iop_1Sto32, binop(Iop_CmpEQ32, mkU32(0),
+ mkU32(mov_cc))));
+ assign(t2, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t1)),
+ binop(Iop_And32, binop(Iop_Shr32, getFCSR(),
+ mkU8(24 + mov_cc)), mkU32(0x1)), binop(Iop_And32,
+ binop(Iop_Shr32, getFCSR(), mkU8(23)),
+ mkU32(0x1))));
+
+ assign(t3, unop(Iop_1Sto32, binop(Iop_CmpEQ32, mkU32(0),
+ mkexpr(t2))));
+ assign(t4, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t3)),
+ getIReg(rd), getIReg(rs)));
+ putIReg(rd, mkexpr(t4));
+ }
+ } else if (tf == 1) { /* MOVT */
+ DIP("movt r%d, r%d, %d", rd, rs,
+ mov_cc);
+ {
+ t1 = newTemp(Ity_I32);
+ t2 = newTemp(Ity_I32);
+ t3 = newTemp(Ity_I32);
+ t4 = newTemp(Ity_I32);
+
+ assign(t1, unop(Iop_1Sto32, binop(Iop_CmpEQ32, mkU32(0),
+ mkU32(mov_cc))));
+ assign(t2, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t1)),
+ binop(Iop_And32, binop(Iop_Shr32, getFCSR(),
+ mkU8(24 + mov_cc)), mkU32(0x1)), binop(Iop_And32,
+ binop(Iop_Shr32, getFCSR(), mkU8(23)),
+ mkU32(0x1))));
+
+ assign(t3, unop(Iop_1Sto32, binop(Iop_CmpEQ32, mkU32(1),
+ mkexpr(t2))));
+ assign(t4, IRExpr_Mux0X(unop(Iop_32to8, mkexpr(t3)),
+ getIReg(rd), getIReg(rs)));
+ putIReg(rd, mkexpr(t4));
+ }
+ }
+ break;
+ }
+ case 0x0A: {
+ /* MOVZ */
+ DIP("movz");
+ t1 = newTemp(ty);
+ t2 = newTemp(ty);
+ {
+ assign(t1, unop(Iop_1Sto32, binop(Iop_CmpEQ32, getIReg(rt),
+ mkU32(0x0))));
+ assign(t2, unop(Iop_1Sto32, binop(Iop_CmpNE32, getIReg(rt),
+ mkU32(0x0))));
+ putIReg(rd, binop(Iop_Add32, binop(Iop_And32, getIReg(rs),
+ mkexpr(t1)), binop(Iop_And32, getIReg(rd),
+ mkexpr(t2))));
+ }
+ break;
+ }
+
+ case 0x0B: {
+ /* MOVN */
+ DIP("movn");
+ t1 = newTemp(ty);
+ t2 = newTemp(ty);
+ {
+ assign(t1, unop(Iop_1Sto32, binop(Iop_CmpEQ32, getIReg(rt),
+ mkU32(0x0))));
+ assign(t2, unop(Iop_1Sto32, binop(Iop_CmpNE32, getIReg(rt),
+ mkU32(0x0))));
+ putIReg(rd, binop(Iop_Add32, binop(Iop_And32, getIReg(rs),
+ mkexpr(t2)), binop(Iop_And32, getIReg(rd),
+ mkexpr(t1))));
+ }
+ break;
+ }
+
+ case 0x18: /* MULT */
+ DIP("mult");
+ t2 = newTemp(Ity_I64);
+
+ assign(t2, binop(Iop_MullS32, mkNarrowTo32(ty, getIReg(rs)),
+ mkNarrowTo32(ty, getIReg(rt))));
+
+ putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True));
+ putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True));
+ break;
+
+ case 0x19: /* MULTU */
+ DIP("multu");
+ t2 = newTemp(Ity_I64);
+
+ assign(t2, binop(Iop_MullU32, mkNarrowTo32(ty, getIReg(rs)),
+ mkNarrowTo32(ty, getIReg(rt))));
+
+ putHI(mkWidenFrom32(ty, unop(Iop_64HIto32, mkexpr(t2)), True));
+ putLO(mkWidenFrom32(ty, unop(Iop_64to32, mkexpr(t2)), True));
+ break;
+
+ case 0x20: /* ADD */
+ DIP("add");
+ {
+ t2 = newTemp(Ity_I32);
+
+ assign(t2, binop(Iop_Add32, getIReg(rs), getIReg(rt)));
+ putIReg(rd, mkexpr(t2));
+ }
+ break;
+
+ case 0x1A: /* DIV */
+ DIP("div");
+ {
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+
+ assign(t1, unop(Iop_32Sto64, getIReg(rs)));
+ assign(t2, binop(Iop_DivModS64to32, mkexpr(t1), getIReg(rt)));
+
+ putHI(unop(Iop_64HIto32, mkexpr(t2)));
+ putLO(unop(Iop_64to32, mkexpr(t2)));
+ }
+ break;
+
+ case 0x1B: /* DIVU */
+ DIP("divu");
+ {
+ t1 = newTemp(Ity_I64);
+ t2 = newTemp(Ity_I64);
+ assign(t1, unop(Iop_32Uto64, getIReg(rs)));
+ assign(t2, binop(Iop_DivModU64to32, mkexpr(t1), getIReg(rt)));
+ putHI(unop(Iop_64HIto32, mkexpr(t2)));
+ putLO(unop(Iop_64to32, mkexpr(t2)));
+ }
+ break;
+
+ case 0x10: /* MFHI */
+ DIP("mfhi");
+ putIReg(rd, getHI());
+ break;
+
+ case 0x11: /* MTHI */
+ DIP("mthi");
+ putHI(getIReg(rs));
+ break;
+
+ case 0x12: /* MFLO */
+ DIP("mflo");
+ putIReg(rd, getLO());
+ break;
+
+ case 0x13: /* MTLO */
+ DIP("mtlo");
+ putLO(getIReg(rs));
+ break;
+
+ case 0x21: /* ADDU */
+ DIP("addu");
+ ALU_PATTERN(Iop_Add32);
+ break;
+
+ case 0x22: /* SUB */
+ DIP("sub");
+ ALU_PATTERN(Iop_Sub32);
+ break;
+
+ case 0x23: /* SUBU */
+ DIP("subu");
+ ALU_PATTERN(Iop_Sub32);
+ break;
+
+ case 0x24: /* AND */
+ DIP("and");
+ ALU_PATTERN(Iop_And32);
+ break;
+
+ case 0x25: /* OR */
+ DIP("or r%d, r%d, r%d", rd, rs, rt);
+ ALU_PATTERN(Iop_Or32);
+ break;
+
+ case 0x26: /* XOR */
+ DIP("xor");
+ ALU_PATTERN(Iop_Xor32);
+ break;
+
+ case 0x27: /* NOR */
+ DIP("nor");
+ putIReg(rd, unop(Iop_Not32, binop(Iop_Or32, getIReg(rs),getIReg(rt))));
+ break;
+
+ case 0x08: /* JR */
+ DIP("jr r%d", rs);
+ t0 = newTemp(ty);
+ assign(t0, getIReg(rs));
+ lastn = mkexpr(t0);
+ break;
+
+ case 0x09: /* JALR */
+ DIP("jalr r%d r%d", rd, rs);
+ putIReg(rd, mkU32(guest_PC_curr_instr + 8));
+ t0 = newTemp(Ity_I32);
+ assign(t0, getIReg(rs));
+ lastn = mkexpr(t0);
+ break;
+
+ case 0x0C: /* SYSCALL */
+ DIP("syscall");
+ putPC(mkU32(guest_PC_curr_instr + 4));
+ dres.jk_StopHere = Ijk_Sys_syscall;
+ dres.whatNext = Dis_StopHere;
+ break;
+
+ case 0x2A: /* SLT */
+ DIP("slt");
+ putIReg(rd, unop(Iop_1Uto32, binop(Iop_CmpLT32S, getIReg(rs),
+ getIReg(rt))));
+ break;
+
+ case 0x2B: /* SLTU */
+ DIP("sltu");
+ putIReg(rd, unop(Iop_1Uto32, binop(Iop_CmpLT32U, getIReg(rs),
+ getIReg(rt))));
+ break;
+
+ case 0x00:
+ /* SLL */
+ DIP("sll");
+ SXX_PATTERN(Iop_Shl32);
+ break;
+
+ case 0x04: /* SLLV */
+ DIP("sllv");
+ SXXV_PATTERN(Iop_Shl32);
+ break;
+
+ case 0x03: /* SRA */
+ DIP("sra");
+ SXX_PATTERN(Iop_Sar32);
+ break;
+
+ case 0x07: /* SRAV */
+ DIP("srav");
+ SXXV_PATTERN(Iop_Sar32);
+ break;
+
+ case 0x02: { /* SRL */
+ rot = get_rot(cins);
+ if (rot) {
+ DIP("rotr");
+ putIReg(rd, mkWidenFrom32(ty, genROR32(mkNarrowTo32(ty,
+ getIReg(rt)), sa), False));
+ } else {
+ DIP("srl");
+ SXX_PATTERN(Iop_Shr32);
+ }
+ break;
+ }
+
+ case 0x06: {
+ rot = get_rotv(cins);
+ if (rot) {
+ DIP("rotrv");
+ putIReg(rd, mkWidenFrom32(ty, genRORV32(mkNarrowTo32(ty,
+ getIReg(rt)), mkNarrowTo32(ty, getIReg(rs))),False));
+ break;
+ } else {
+ /* SRLV */
+ DIP("srlv");
+ SXXV_PATTERN(Iop_Shr32);
+ break;
+ }
+ }
+
+ case 0x0D: /* BREAK */
+ DIP("Info: Breakpoint...code = %d", trap_code);
+ jmp_lit(&dres, Ijk_SigTRAP, (guest_PC_curr_instr + 4));
+ vassert(dres.whatNext == Dis_StopHere);
+ break;
+
+ case 0x30: { /* TGE */
+ /*tge */ DIP("tge r%d, r%d %d", rs, rt, trap_code);
+ stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rt), getIReg (rs)),
+ Ijk_SigTRAP,
+ IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+ break;
+ }
+ case 0x31: { /* TGEU */
+ /*tgeu */ DIP("tgeu r%d, r%d %d", rs, rt, trap_code);
+ stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rt), getIReg (rs)),
+ Ijk_SigTRAP,
+ IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+ break;
+ }
+ case 0x32: { /* TLT */
+ /*tlt */ DIP("tlt r%d, r%d %d", rs, rt, trap_code);
+ stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rs), getIReg (rt)),
+ Ijk_SigTRAP,
+ IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+ break;
+ }
+ case 0x33: { /* TLTU */
+ /*tltu */ DIP("tltu r%d, r%d %d", rs, rt, trap_code);
+ stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rs), getIReg (rt)),
+ Ijk_SigTRAP,
+ IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+ break;
+ }
+ case 0x34: { /* TEQ */
+ /*teq */ DIP("teq r%d, r%d %d", rs, rt, trap_code);
+ stmt (IRStmt_Exit(binop (Iop_CmpEQ32, getIReg (rs), getIReg (rt)),
+ Ijk_SigTRAP, IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+ break;
+ }
+ case 0x36: { /* TNE */
+ /*tne */ DIP("tne r%d, r%d %d", rs, rt, trap_code);
+ stmt (IRStmt_Exit (binop (Iop_CmpNE32, getIReg (rs), getIReg (rt)),
+ Ijk_SigTRAP,
+ IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+ break;
+ }
+ case 0x0F: {
+ /*SYNC*/ DIP("sync r%d, r%d, %d", rt, rd, sel);
+ lsb = get_lsb(cins);
+ IRDirty *d = unsafeIRDirty_0_N(0,
+ "mips32_dirtyhelper_sync",
+ &mips32_dirtyhelper_sync,
+ mkIRExprVec_1
+ (mkU32(lsb)));
+
+ d->needsBBP = False;
+ d->nFxState = 0;
+
+ stmt(IRStmt_Dirty(d));
+ break;
+ }
+
+ default:
+ goto decode_failure;
+ }
+ break;
+
+ case 0x01: /* Regimm */
+
+ switch (rt) {
+ case 0x01: /* BGEZ */
+ DIP("bgez");
+ dis_branch(False, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs),
+ mkU32(0x80000000)), mkU32(0x0)), imm, &bstmt);
+ break;
+
+ case 0x03: /* BGEZL */
+ DIP("bgezl");
+ lastn = dis_branch_likely(binop(Iop_CmpNE32, binop(Iop_And32,
+ getIReg(rs), mode64 ?
+ mkU64(0x8000000000000000ULL)
+ :mkU32(0x80000000)),
+ mkU32(0x0)), imm);
+ break;
+
+ case 0x00: /* BLTZ */
+ DIP("bltz");
+ dis_branch(False, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs),
+ mkU32(0x80000000)), mkU32(0x80000000)), imm, &bstmt);
+ break;
+
+ case 0x02: /* BLTZL */
+ DIP("bltzl");
+ lastn = dis_branch_likely(binop(Iop_CmpNE32, binop(Iop_And32,
+ getIReg(rs), mkU32(0x80000000)),
+ mkU32(0x80000000)), imm);
+ break;
+
+ case 0x10: /* BLTZAL */
+ DIP("bltzal");
+ dis_branch(True, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs),
+ mkU32(0x80000000)), mkU32(0x80000000)), imm, &bstmt);
+ break;
+
+ case 0x12: /* BLTZALL */
+ DIP("bltzall");
+ putIReg(31, mkU32(guest_PC_curr_instr + 8));
+ lastn = dis_branch_likely(binop(Iop_CmpNE32, binop(Iop_And32,
+ getIReg(rs), mkU32(0x80000000)),
+ mkU32(0x80000000)), imm);
+ break;
+
+ case 0x11: /* BGEZAL */
+ DIP("bgezal");
+ dis_branch(True, binop(Iop_CmpEQ32, binop(Iop_And32, getIReg(rs),
+ mkU32(0x80000000)), mkU32(0x0)), imm, &bstmt);
+ break;
+
+ case 0x13: /* BGEZALL */
+ DIP("bgezall");
+ putIReg(31, mkU32(guest_PC_curr_instr + 8));
+ lastn = dis_branch_likely(binop(Iop_CmpNE32, binop(Iop_And32,
+ getIReg(rs), mkU32(0x80000000)),
+ mkU32(0x0)), imm);
+ break;
+
+ case 0x08: { /* TGEI */
+ /*tgei */ DIP("tgei r%d, %d %d", rs, imm, trap_code);
+ stmt (IRStmt_Exit (binop (Iop_CmpLT32S, mkU32 (imm), getIReg (rs)),
+ Ijk_SigTRAP,
+ IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+ break;
+ }
+ case 0x09: { /* TGEIU */
+ /*tqeiu */ DIP("tgeiu r%d, %d %d", rs, imm, trap_code);
+ stmt (IRStmt_Exit (binop (Iop_CmpLT32U, mkU32 (imm), getIReg (rs)),
+ Ijk_SigTRAP,
+ IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+ break;
+ }
+ case 0x0A: { /* TLTI */
+ /*tlti */ DIP("tlti r%d, %d %d", rs, imm, trap_code);
+ stmt (IRStmt_Exit (binop (Iop_CmpLT32S, getIReg (rs), mkU32 (imm)),
+ Ijk_SigTRAP,
+ IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+ break;
+ }
+ case 0x0B: { /* TLTIU */
+ /*tltiu */ DIP("tltiu r%d, %d %d", rs, imm, trap_code);
+ stmt (IRStmt_Exit (binop (Iop_CmpLT32U, getIReg (rs), mkU32 (imm)),
+ Ijk_SigTRAP,
+ IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+ break;
+ }
+ case 0x0C: { /* TEQI */
+ /*teqi */ DIP("teqi r%d, %d %d", rs, imm, trap_code);
+ stmt (IRStmt_Exit (binop (Iop_CmpEQ32, getIReg (rs), mkU32 (imm)),
+ Ijk_SigTRAP,
+ IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+ break;
+ }
+ case 0x0E: { /* TNEI */
+ /*tnei */ DIP("tnei r%d, %d %d", rs, imm, trap_code);
+ stmt (IRStmt_Exit (binop (Iop_CmpNE32, getIReg (rs), mkU32 (imm)),
+ Ijk_SigTRAP,
+ IRConst_U32 (guest_PC_curr_instr + 4), OFFB_PC));
+ break;
+ }
+ case 0x1F:
+ /*SYNCI*/
+ //Just ignore it
+ break;
+
+ default:
+ goto decode_failure;
+ }
+ break;
+
+ case 0x04:
+ DIP("beq");
+ dis_branch(False, binop(Iop_CmpEQ32, getIReg(rs), getIReg(rt)),
+ imm, &bstmt);
+ break;
+
+ case 0x14:
+ DIP("beql");
+ lastn = dis_branch_likely(binop(Iop_CmpNE32, getIReg(rs), getIReg(rt)),
+ imm);
+ break;
+
+ case 0x05:
+ DIP("bne");
+ dis_branch(False, binop(Iop_CmpNE32, getIReg(rs), getIReg(rt)),
+ imm, &bstmt);
+ break;
+
+ case 0x15:
+ DIP("bnel");
+ lastn =
+ dis_branch_likely(binop(Iop_CmpEQ32, getIReg(rs), getIReg(rt)), imm);
+ break;
+
+ case 0x07: /* BGTZ */
+ DIP("bgtz");
+ dis_branch(False, unop(Iop_Not1, binop(Iop_CmpLE32S, getIReg(rs),
+ mkU32(0x00))), imm, &bstmt);
+ break;
+
+ case 0x17: /* BGTZL */
+ DIP("bgtzl");
+ lastn = dis_branch_likely(binop(Iop_CmpLE32S, getIReg(rs), mkU32(0x00)),
+ imm);
+ break;
+
+ case 0x06: /* BLEZ */
+ DIP("blez");
+ dis_branch(False,binop(Iop_CmpLE32S, getIReg(rs), mkU32(0x0)), imm,
+ &bstmt);
+ break;
+
+ case 0x16: /* BLEZL */
+ DIP("blezl");
+ lastn = dis_branch_likely(unop(Iop_Not1, (binop(Iop_CmpLE32S,
+ getIReg(rs), mkU32(0x0)))), imm);
+ break;
+
+ case 0x08: /* ADDI TODO: Check this */
+ DIP("addi r%d, r%d, %d", rt, rs, imm);
+ putIReg(rt, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
+ break;
+
+ case 0x09: /* ADDIU */
+ DIP("addiu r%d, r%d, %d", rt, rs, imm);
+ putIReg(rt, binop(Iop_Add32, getIReg(rs), mkU32(extend_s_16to32(imm))));
+ break;
+
+ case 0x0C: /* ANDI */
+ DIP("andi");
+ ALUI_PATTERN(Iop_And32);
+ break;
+
+ case 0x0E: /* XORI */
+ DIP("xori");
+ ALUI_PATTERN(Iop_Xor32);
+ break;
+
+ case 0x0D: /* ORI */
+ DIP("ori");
+ ALUI_PATTERN(Iop_Or32);
+ break;
+
+ case 0x0A: /* SLTI */
+ DIP("slti");
+ putIReg(rt, unop(Iop_1Uto32, binop(Iop_CmpLT32S, getIReg(rs),
+ mkU32(extend_s_16to32(imm)))));
+ break;
+
+ case 0x0B: /* SLTIU */
+ DIP("sltiu");
+ putIReg(rt, unop(Iop_1Uto32, binop(Iop_CmpLT32U, getIReg(rs),
+ mkU32(extend_s_16to32(imm)))));
+ break;
+
+ case 0x30: /* LL / LWC0 */
+ DIP("ll r%d, %d(r%d)", rt, imm, rs);
+ LOAD_STORE_PATTERN;
+
+ t2 = newTemp(Ity_I32);
+#if defined (_MIPSEL)
+ stmt(IRStmt_LLSC(Iend_LE, t2, mkexpr(t1), NULL /*this is a load */ ));
+#elif defined (_MIPSEB)
+ stmt(IRStmt_LLSC(Iend_BE, t2, mkexpr(t1), NULL /*this is a load */ ));
+#endif
+
+ putIReg(rt, mkexpr(t2));
+ break;
+
+ case 0x38: /* SC / SWC0 */
+ DIP("sc");
+ LOAD_STORE_PATTERN;
+
+ t2 = newTemp(Ity_I1);
+#if defined (_MIPSEL)
+ stmt(IRStmt_LLSC(Iend_LE, t2, mkexpr(t1), mkNarrowTo32(ty, getIReg(rt))));
+#elif defined (_MIPSEB)
+ stmt(IRStmt_LLSC(Iend_BE, t2, mkexpr(t1), mkNarrowTo32(ty, getIReg(rt))));
+#endif
+
+ putIReg(rt, unop(Iop_1Uto32, mkexpr(t2)));
+ break;
+
+ decode_failure:
+ /* All decode failures end up here. */
+ DIP("vex mips->IR: unhandled instruction bytes: "
+ "0x%x 0x%x 0x%x 0x%x\n",
+ (Int) getIByte(delta_start + 0),
+ (Int) getIByte(delta_start + 1),
+ (Int) getIByte(delta_start + 2),
+ (Int) getIByte(delta_start + 3));
+
+ /* Tell the dispatcher that this insn cannot be decoded, and so has
+ not been executed, and (is currently) the next to be executed.
+ EIP should be up-to-date since it made so at the start bnezof each
+ insn, but nevertheless be paranoid and update it again right
+ now. */
+ stmt(IRStmt_Put(offsetof(VexGuestMIPS32State, guest_PC),
+ mkU32(guest_PC_curr_instr)));
+ jmp_lit(&dres, Ijk_NoDecode, guest_PC_curr_instr);
+ dres.whatNext = Dis_StopHere;
+ dres.len = 0;
+ return dres;
+ } /* switch (opc) for the main (primary) opcode switch. */
+
+ /* All MIPS insn have 4 bytes */
+
+ if (delay_slot_branch) {
+ delay_slot_branch = False;
+ stmt(bstmt);
+ bstmt = NULL;
+ putPC(mkU32(guest_PC_curr_instr + 4));
+ dres.jk_StopHere = is_Branch_or_Jump_and_Link(guest_code + delta - 4) ?
+ Ijk_Call : Ijk_Boring;
+ }
+
+ if (likely_delay_slot) {
+ dres.jk_StopHere = Ijk_Boring;
+ dres.whatNext = Dis_StopHere;
+ putPC(lastn);
+ lastn = NULL;
+ }
+ if (delay_slot_jump) {
+ putPC(lastn);
+ lastn = NULL;
+ dres.jk_StopHere = is_Branch_or_Jump_and_Link(guest_code + delta - 4) ?
+ Ijk_Call : Ijk_Boring;
+ }
+
+ decode_success:
+ /* All decode successes end up here. */
+ switch (dres.whatNext) {
+ case Dis_Continue:
+ putPC(mkU32(guest_PC_curr_instr + 4));
+ break;
+ case Dis_ResteerU:
+ case Dis_ResteerC:
+ putPC(mkU32(dres.continueAt));
+ break;
+ case Dis_StopHere:
+ break;
+ default:
+ vassert(0);
+ break;
+ }
+
+ // On MIPS we need to check if the last instruction
+ // in block is branch or jump
+ if ((vex_control.guest_max_insns - 1) == (delta+4)/4)
+ if (branch_or_jump(guest_code + delta + 4)) {
+ dres.whatNext = Dis_StopHere;
+ dres.jk_StopHere = Ijk_Boring;
+ putPC(mkU32(guest_PC_curr_instr + 4));
+ }
+ dres.len = 4;
+
+ DIP("\n");
+
+ return dres;
+
+}
+
+/*------------------------------------------------------------*/
+/*--- Top-level fn ---*/
+/*------------------------------------------------------------*/
+
+/* Disassemble a single instruction into IR. The instruction
+ is located in host memory at &guest_code[delta]. */
+
+DisResult
+disInstr_MIPS(IRSB* irsb_IN,
+ Bool (*resteerOkFn) (void *, Addr64),
+ Bool resteerCisOk,
+ void* callback_opaque,
+ UChar* guest_code_IN,
+ Long delta,
+ Addr64 guest_IP,
+ VexArch guest_arch,
+ VexArchInfo* archinfo,
+ VexAbiInfo* abiinfo,
+ Bool host_bigendian_IN)
+{
+ DisResult dres;
+
+ /* Set globals (see top of this file) */
+ vassert(guest_arch == VexArchMIPS32);
+
+ mode64 = guest_arch != VexArchMIPS32;
+
+ guest_code = guest_code_IN;
+ irsb = irsb_IN;
+ host_is_bigendian = host_bigendian_IN;
+ guest_PC_curr_instr = (Addr32) guest_IP;
+ guest_PC_bbstart = (Addr32) toUInt(guest_IP - delta);
+
+ dres = disInstr_MIPS_WRK(resteerOkFn, resteerCisOk, callback_opaque,
+ delta, archinfo, abiinfo);
+
+ return dres;
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end guest_mips_toIR.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/priv/host_mips_defs.c b/priv/host_mips_defs.c
new file mode 100644
index 0000000..22082d5
--- /dev/null
+++ b/priv/host_mips_defs.c
@@ -0,0 +1,4048 @@
+
+/*---------------------------------------------------------------*/
+/*--- begin host_mips_defs.c ---*/
+/*---------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2010-2012 RT-RK
+ mips-valgrind@rt-rk.com
+
+ 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.
+*/
+
+#include "libvex_basictypes.h"
+#include "libvex.h"
+#include "libvex_trc_values.h"
+
+#include "main_util.h"
+#include "host_generic_regs.h"
+#include "host_mips_defs.h"
+
+/*---------------- Registers ----------------*/
+
+void ppHRegMIPS(HReg reg, Bool mode64)
+{
+ Int r;
+ static HChar *ireg32_names[35]
+ = { "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7",
+ "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15",
+ "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23",
+ "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31",
+ "%32", "%33", "%34",
+ };
+
+ static HChar *freg32_names[32]
+ = { "$f0", "$f1", "$f2", "$f3", "$f4", "$f5", "$f6", "$f7",
+ "$f8", "$f9", "$f10", "$f11", "$f12", "$f13", "$f14", "$f15",
+ "$f16", "$f17", "$f18", "$f19", "$f20", "$f21", "$f22", "$f23",
+ "$f24", "$f25", "$f26", "$f27", "$f28", "$f29", "f30", "$f31"
+ };
+
+ static HChar *freg64_names[32]
+ = { "$d0", "$d1", "$d2", "$d3", "$d4", "$d5", "$d6", "$d7",
+ "$d8", "$d9", "$d10", "$d11", "$d12", "$d13", "$d14", "$d15",
+ };
+
+ /* Be generic for all virtual regs. */
+ if (hregIsVirtual(reg)) {
+ ppHReg(reg);
+ return;
+ }
+
+ /* But specific for real regs. */
+ vassert(hregClass(reg) == HRcInt32 || hregClass(reg) == HRcInt64 ||
+ hregClass(reg) == HRcFlt32 || hregClass(reg) == HRcFlt64);
+
+ /* But specific for real regs. */
+ {
+ switch (hregClass(reg)) {
+ case HRcInt32:
+ r = hregNumber(reg);
+ vassert(r >= 0 && r < 32);
+ vex_printf("%s", ireg32_names[r]);
+ return;
+ case HRcFlt32:
+ r = hregNumber(reg);
+ vassert(r >= 0 && r < 32);
+ vex_printf("%s", freg32_names[r]);
+ return;
+ case HRcFlt64:
+ r = hregNumber(reg);
+ vassert(r >= 0 && r < 32);
+ vex_printf("%s", freg64_names[r]);
+ return;
+ default:
+ vpanic("ppHRegMIPS");
+ break;
+ }
+ }
+
+ return;
+}
+
+#define MkHRegGPR(_n, _mode64) \
+ mkHReg(_n, _mode64 ? HRcInt64 : HRcInt32, False)
+
+HReg hregMIPS_GPR0(Bool mode64)
+{
+ return MkHRegGPR(0, mode64);
+}
+
+HReg hregMIPS_GPR1(Bool mode64)
+{
+ return MkHRegGPR(1, mode64);
+}
+
+HReg hregMIPS_GPR2(Bool mode64)
+{
+ return MkHRegGPR(2, mode64);
+}
+
+HReg hregMIPS_GPR3(Bool mode64)
+{
+ return MkHRegGPR(3, mode64);
+}
+
+HReg hregMIPS_GPR4(Bool mode64)
+{
+ return MkHRegGPR(4, mode64);
+}
+
+HReg hregMIPS_GPR5(Bool mode64)
+{
+ return MkHRegGPR(5, mode64);
+}
+
+HReg hregMIPS_GPR6(Bool mode64)
+{
+ return MkHRegGPR(6, mode64);
+}
+
+HReg hregMIPS_GPR7(Bool mode64)
+{
+ return MkHRegGPR(7, mode64);
+}
+
+HReg hregMIPS_GPR8(Bool mode64)
+{
+ return MkHRegGPR(8, mode64);
+}
+
+HReg hregMIPS_GPR9(Bool mode64)
+{
+ return MkHRegGPR(9, mode64);
+}
+
+HReg hregMIPS_GPR10(Bool mode64)
+{
+ return MkHRegGPR(10, mode64);
+}
+
+HReg hregMIPS_GPR11(Bool mode64)
+{
+ return MkHRegGPR(11, mode64);
+}
+
+HReg hregMIPS_GPR12(Bool mode64)
+{
+ return MkHRegGPR(12, mode64);
+}
+
+HReg hregMIPS_GPR13(Bool mode64)
+{
+ return MkHRegGPR(13, mode64);
+}
+
+HReg hregMIPS_GPR14(Bool mode64)
+{
+ return MkHRegGPR(14, mode64);
+}
+
+HReg hregMIPS_GPR15(Bool mode64)
+{
+ return MkHRegGPR(15, mode64);
+}
+
+HReg hregMIPS_GPR16(Bool mode64)
+{
+ return MkHRegGPR(16, mode64);
+}
+
+HReg hregMIPS_GPR17(Bool mode64)
+{
+ return MkHRegGPR(17, mode64);
+}
+
+HReg hregMIPS_GPR18(Bool mode64)
+{
+ return MkHRegGPR(18, mode64);
+}
+
+HReg hregMIPS_GPR19(Bool mode64)
+{
+ return MkHRegGPR(19, mode64);
+}
+
+HReg hregMIPS_GPR20(Bool mode64)
+{
+ return MkHRegGPR(20, mode64);
+}
+
+HReg hregMIPS_GPR21(Bool mode64)
+{
+ return MkHRegGPR(21, mode64);
+}
+
+HReg hregMIPS_GPR22(Bool mode64)
+{
+ return MkHRegGPR(22, mode64);
+}
+
+HReg hregMIPS_GPR23(Bool mode64)
+{
+ return MkHRegGPR(23, mode64);
+}
+
+HReg hregMIPS_GPR24(Bool mode64)
+{
+ return MkHRegGPR(24, mode64);
+}
+
+HReg hregMIPS_GPR25(Bool mode64)
+{
+ return MkHRegGPR(25, mode64);
+}
+
+HReg hregMIPS_GPR26(Bool mode64)
+{
+ return MkHRegGPR(26, mode64);
+}
+
+HReg hregMIPS_GPR27(Bool mode64)
+{
+ return MkHRegGPR(27, mode64);
+}
+
+HReg hregMIPS_GPR28(Bool mode64)
+{
+ return MkHRegGPR(28, mode64);
+}
+
+HReg hregMIPS_GPR29(Bool mode64)
+{
+ return MkHRegGPR(29, mode64);
+}
+
+HReg hregMIPS_GPR30(Bool mode64)
+{
+ return MkHRegGPR(30, mode64);
+}
+
+HReg hregMIPS_GPR31(Bool mode64)
+{
+ return MkHRegGPR(31, mode64);
+}
+
+#define MkHRegFPR(_n, _mode64) \
+ mkHReg(_n, _mode64 ? HRcFlt64 : HRcFlt32, False)
+
+HReg hregMIPS_F0(Bool mode64)
+{
+ return MkHRegFPR(0, mode64);
+}
+
+HReg hregMIPS_F1(Bool mode64)
+{
+ return MkHRegFPR(1, mode64);
+}
+
+HReg hregMIPS_F2(Bool mode64)
+{
+ return MkHRegFPR(2, mode64);
+}
+
+HReg hregMIPS_F3(Bool mode64)
+{
+ return MkHRegFPR(3, mode64);
+}
+
+HReg hregMIPS_F4(Bool mode64)
+{
+ return MkHRegFPR(4, mode64);
+}
+
+HReg hregMIPS_F5(Bool mode64)
+{
+ return MkHRegFPR(5, mode64);
+}
+
+HReg hregMIPS_F6(Bool mode64)
+{
+ return MkHRegFPR(6, mode64);
+}
+
+HReg hregMIPS_F7(Bool mode64)
+{
+ return MkHRegFPR(7, mode64);
+}
+
+HReg hregMIPS_F8(Bool mode64)
+{
+ return MkHRegFPR(8, mode64);
+}
+
+HReg hregMIPS_F9(Bool mode64)
+{
+ return MkHRegFPR(9, mode64);
+}
+
+HReg hregMIPS_F10(Bool mode64)
+{
+ return MkHRegFPR(10, mode64);
+}
+
+HReg hregMIPS_F11(Bool mode64)
+{
+ return MkHRegFPR(11, mode64);
+}
+
+HReg hregMIPS_F12(Bool mode64)
+{
+ return MkHRegFPR(12, mode64);
+}
+
+HReg hregMIPS_F13(Bool mode64)
+{
+ return MkHRegFPR(13, mode64);
+}
+
+HReg hregMIPS_F14(Bool mode64)
+{
+ return MkHRegFPR(14, mode64);
+}
+
+HReg hregMIPS_F15(Bool mode64)
+{
+ return MkHRegFPR(15, mode64);
+}
+
+HReg hregMIPS_F16(Bool mode64)
+{
+ return MkHRegFPR(16, mode64);
+}
+
+HReg hregMIPS_F17(Bool mode64)
+{
+ return MkHRegFPR(17, mode64);
+}
+
+HReg hregMIPS_F18(Bool mode64)
+{
+ return MkHRegFPR(18, mode64);
+}
+
+HReg hregMIPS_F19(Bool mode64)
+{
+ return MkHRegFPR(19, mode64);
+}
+
+HReg hregMIPS_F20(Bool mode64)
+{
+ return MkHRegFPR(20, mode64);
+}
+
+HReg hregMIPS_F21(Bool mode64)
+{
+ return MkHRegFPR(21, mode64);
+}
+
+HReg hregMIPS_F22(Bool mode64)
+{
+ return MkHRegFPR(22, mode64);
+}
+
+HReg hregMIPS_F23(Bool mode64)
+{
+ return MkHRegFPR(23, mode64);
+}
+
+HReg hregMIPS_F24(Bool mode64)
+{
+ return MkHRegFPR(24, mode64);
+}
+
+HReg hregMIPS_F25(Bool mode64)
+{
+ return MkHRegFPR(25, mode64);
+}
+
+HReg hregMIPS_F26(Bool mode64)
+{
+ return MkHRegFPR(26, mode64);
+}
+
+HReg hregMIPS_F27(Bool mode64)
+{
+ return MkHRegFPR(27, mode64);
+}
+
+HReg hregMIPS_F28(Bool mode64)
+{
+ return MkHRegFPR(28, mode64);
+}
+
+HReg hregMIPS_F29(Bool mode64)
+{
+ return MkHRegFPR(29, mode64);
+}
+
+HReg hregMIPS_F30(Bool mode64)
+{
+ return MkHRegFPR(30, mode64);
+}
+
+HReg hregMIPS_F31(Bool mode64)
+{
+ return MkHRegFPR(31, mode64);
+}
+
+HReg hregMIPS_PC(Bool mode64)
+{
+ return mkHReg(32, mode64 ? HRcFlt64 : HRcFlt32, False);
+}
+
+HReg hregMIPS_HI(Bool mode64)
+{
+ return mkHReg(33, mode64 ? HRcFlt64 : HRcFlt32, False);
+}
+
+HReg hregMIPS_LO(Bool mode64)
+{
+ return mkHReg(34, mode64 ? HRcFlt64 : HRcFlt32, False);
+}
+
+HReg hregMIPS_D0(void)
+{
+ return mkHReg(0, HRcFlt64, False);
+}
+
+HReg hregMIPS_D1(void)
+{
+ return mkHReg(2, HRcFlt64, False);
+}
+
+HReg hregMIPS_D2(void)
+{
+ return mkHReg(4, HRcFlt64, False);
+}
+
+HReg hregMIPS_D3(void)
+{
+ return mkHReg(6, HRcFlt64, False);
+}
+
+HReg hregMIPS_D4(void)
+{
+ return mkHReg(8, HRcFlt64, False);
+}
+
+HReg hregMIPS_D5(void)
+{
+ return mkHReg(10, HRcFlt64, False);
+}
+
+HReg hregMIPS_D6(void)
+{
+ return mkHReg(12, HRcFlt64, False);
+}
+
+HReg hregMIPS_D7(void)
+{
+ return mkHReg(14, HRcFlt64, False);
+}
+
+HReg hregMIPS_D8(void)
+{
+ return mkHReg(16, HRcFlt64, False);
+}
+
+HReg hregMIPS_D9(void)
+{
+ return mkHReg(18, HRcFlt64, False);
+}
+
+HReg hregMIPS_D10(void)
+{
+ return mkHReg(20, HRcFlt64, False);
+}
+
+HReg hregMIPS_D11(void)
+{
+ return mkHReg(22, HRcFlt64, False);
+}
+
+HReg hregMIPS_D12(void)
+{
+ return mkHReg(24, HRcFlt64, False);
+}
+
+HReg hregMIPS_D13(void)
+{
+ return mkHReg(26, HRcFlt64, False);
+}
+
+HReg hregMIPS_D14(void)
+{
+ return mkHReg(28, HRcFlt64, False);
+}
+
+HReg hregMIPS_D15(void)
+{
+ return mkHReg(30, HRcFlt64, False);
+}
+
+HReg hregMIPS_FIR(void)
+{
+ return mkHReg(35, HRcInt32, False);
+}
+
+HReg hregMIPS_FCCR(void)
+{
+ return mkHReg(36, HRcInt32, False);
+}
+
+HReg hregMIPS_FEXR(void)
+{
+ return mkHReg(37, HRcInt32, False);
+}
+
+HReg hregMIPS_FENR(void)
+{
+ return mkHReg(38, HRcInt32, False);
+}
+
+HReg hregMIPS_FCSR(void)
+{
+ return mkHReg(39, HRcInt32, False);
+}
+
+HReg hregMIPS_COND(void)
+{
+ return mkHReg(47, HRcInt32, False);
+}
+
+void getAllocableRegs_MIPS(Int * nregs, HReg ** arr, Bool mode64)
+{
+ if (mode64)
+ *nregs = 27;
+ else
+ *nregs = 34;
+ UInt i = 0;
+ *arr = LibVEX_Alloc(*nregs * sizeof(HReg));
+
+ //ZERO = constant 0
+ //AT = assembler temporary
+ // callee saves ones are listed first, since we prefer them
+ // if they're available
+ (*arr)[i++] = hregMIPS_GPR16(mode64);
+ (*arr)[i++] = hregMIPS_GPR17(mode64);
+ (*arr)[i++] = hregMIPS_GPR18(mode64);
+ (*arr)[i++] = hregMIPS_GPR19(mode64);
+ (*arr)[i++] = hregMIPS_GPR20(mode64);
+ (*arr)[i++] = hregMIPS_GPR21(mode64);
+ (*arr)[i++] = hregMIPS_GPR22(mode64);
+ if (!mode64)
+ (*arr)[i++] = hregMIPS_GPR23(mode64);
+
+ // otherwise we'll have to slum it out with caller-saves ones
+ if (mode64) {
+ (*arr)[i++] = hregMIPS_GPR8(mode64);
+ (*arr)[i++] = hregMIPS_GPR9(mode64);
+ (*arr)[i++] = hregMIPS_GPR10(mode64);
+ (*arr)[i++] = hregMIPS_GPR11(mode64);
+ }
+ (*arr)[i++] = hregMIPS_GPR12(mode64);
+ (*arr)[i++] = hregMIPS_GPR13(mode64);
+ (*arr)[i++] = hregMIPS_GPR14(mode64);
+ (*arr)[i++] = hregMIPS_GPR15(mode64);
+ (*arr)[i++] = hregMIPS_GPR24(mode64);
+ /***********mips32********************/
+ // t0 (=dispatch_ctr)
+ // t1 spill reg temp
+ // t2 (=guest_state)
+ // t3 (=PC = next guest address)
+ // K0 and K1 are reserved for OS kernel
+ // GP = global pointer
+ // SP = stack pointer
+ // FP = frame pointer
+ // RA = link register
+ // + PC, HI and LO
+ (*arr)[i++] = hregMIPS_F20(mode64);
+ (*arr)[i++] = hregMIPS_F21(mode64);
+ (*arr)[i++] = hregMIPS_F22(mode64);
+ (*arr)[i++] = hregMIPS_F23(mode64);
+ (*arr)[i++] = hregMIPS_F24(mode64);
+ (*arr)[i++] = hregMIPS_F25(mode64);
+ (*arr)[i++] = hregMIPS_F26(mode64);
+ (*arr)[i++] = hregMIPS_F27(mode64);
+ (*arr)[i++] = hregMIPS_F28(mode64);
+ (*arr)[i++] = hregMIPS_F29(mode64);
+ (*arr)[i++] = hregMIPS_F30(mode64);
+ if (!mode64) {
+ /* Fake double floating point */
+ (*arr)[i++] = hregMIPS_D0();
+ (*arr)[i++] = hregMIPS_D1();
+ (*arr)[i++] = hregMIPS_D2();
+ (*arr)[i++] = hregMIPS_D3();
+ (*arr)[i++] = hregMIPS_D4();
+ (*arr)[i++] = hregMIPS_D5();
+ (*arr)[i++] = hregMIPS_D6();
+ (*arr)[i++] = hregMIPS_D7();
+ (*arr)[i++] = hregMIPS_D8();
+ (*arr)[i++] = hregMIPS_D9();
+ }
+ vassert(i == *nregs);
+
+}
+
+/*----------------- Condition Codes ----------------------*/
+
+HChar *showMIPSCondCode(MIPSCondCode cond)
+{
+ HChar* ret;
+ switch (cond) {
+ case MIPScc_EQ:
+ ret = "EQ"; /* equal */
+ break;
+ case MIPScc_NE:
+ ret = "NEQ"; /* not equal */
+ break;
+ case MIPScc_HS:
+ ret = "GE"; /* >=u (Greater Than or Equal) */
+ break;
+ case MIPScc_LO:
+ ret = "LT"; /* <u (lower) */
+ break;
+ case MIPScc_MI:
+ ret = "mi"; /* minus (negative) */
+ break;
+ case MIPScc_PL:
+ ret = "pl"; /* plus (zero or +ve) */
+ break;
+ case MIPScc_VS:
+ ret = "vs"; /* overflow */
+ break;
+ case MIPScc_VC:
+ ret = "vc"; /* no overflow */
+ break;
+ case MIPScc_HI:
+ ret = "hi"; /* >u (higher) */
+ break;
+ case MIPScc_LS:
+ ret = "ls"; /* <=u (lower or same) */
+ break;
+ case MIPScc_GE:
+ ret = "ge"; /* >=s (signed greater or equal) */
+ break;
+ case MIPScc_LT:
+ ret = "lt"; /* <s (signed less than) */
+ break;
+ case MIPScc_GT:
+ ret = "gt"; /* >s (signed greater) */
+ break;
+ case MIPScc_LE:
+ ret = "le"; /* <=s (signed less or equal) */
+ break;
+ case MIPScc_AL:
+ ret = "al"; /* always (unconditional) */
+ break;
+ case MIPScc_NV:
+ ret = "nv"; /* never (unconditional): */
+ break;
+ default:
+ vpanic("showMIPSCondCode");
+ break;
+ }
+ return ret;
+}
+
+HChar *showMIPSFpOp(MIPSFpOp op)
+{
+ HChar *ret;
+ switch (op) {
+ case Mfp_ADDD:
+ ret = "ADD.D";
+ break;
+ case Mfp_SUBD:
+ ret = "SUB.D";
+ break;
+ case Mfp_MULD:
+ ret = "MUL.D";
+ break;
+ case Mfp_DIVD:
+ ret = "DIV.D";
+ break;
+ case Mfp_MADDD:
+ ret = "MADD.D";
+ break;
+ case Mfp_MSUBD:
+ ret = "MSUB.D";
+ break;
+ case Mfp_MADDS:
+ ret = "MADD.S";
+ break;
+ case Mfp_MSUBS:
+ ret = "MSUB.S";
+ break;
+ case Mfp_ADDS:
+ ret = "ADD.S";
+ break;
+ case Mfp_SUBS:
+ ret = "SUB.S";
+ break;
+ case Mfp_MULS:
+ ret = "MUL.S";
+ break;
+ case Mfp_DIVS:
+ ret = "DIV.S";
+ break;
+ case Mfp_SQRTS:
+ ret = "SQRT.S";
+ break;
+ case Mfp_SQRTD:
+ ret = "SQRT.D";
+ break;
+ case Mfp_RSQRTS:
+ ret = "RSQRT.S";
+ break;
+ case Mfp_RSQRTD:
+ ret = "RSQRT.D";
+ break;
+ case Mfp_RECIPS:
+ ret = "RECIP.S";
+ break;
+ case Mfp_RECIPD:
+ ret = "RECIP.D";
+ break;
+ case Mfp_ABSS:
+ ret = "ABS.S";
+ break;
+ case Mfp_ABSD:
+ ret = "ABS.D";
+ break;
+ case Mfp_NEGS:
+ ret = "NEG.S";
+ break;
+ case Mfp_NEGD:
+ ret = "NEG.D";
+ break;
+ case Mfp_MOVS:
+ ret = "MOV.S";
+ break;
+ case Mfp_MOVD:
+ ret = "MOV.D";
+ break;
+ case Mfp_RES:
+ ret = "RES";
+ break;
+ case Mfp_ROUNDWS:
+ ret = "ROUND.W.S";
+ break;
+ case Mfp_ROUNDWD:
+ ret = "ROUND.W.D";
+ break;
+ case Mfp_FLOORWS:
+ ret = "FLOOR.W.S";
+ break;
+ case Mfp_FLOORWD:
+ ret = "FLOOR.W.D";
+ break;
+ case Mfp_RSQRTE:
+ ret = "frsqrte";
+ break;
+ case Mfp_CVTDW:
+ case Mfp_CVTD:
+ ret = "CVT.D";
+ break;
+ case Mfp_CVTSD:
+ case Mfp_CVTSW:
+ ret = "CVT.S";
+ break;
+ case Mfp_CVTWS:
+ case Mfp_CVTWD:
+ ret = "CVT.W";
+ break;
+ case Mfp_TRUWD:
+ case Mfp_TRUWS:
+ ret = "TRUNC.W";
+ break;
+ case Mfp_TRULD:
+ case Mfp_TRULS:
+ ret = "TRUNC.L";
+ break;
+ case Mfp_CEILWS:
+ case Mfp_CEILWD:
+ ret = "CEIL.W";
+ break;
+ case Mfp_CEILLS:
+ case Mfp_CEILLD:
+ ret = "CEIL.L";
+ break;
+ case Mfp_CMP:
+ ret = "C.cond.d";
+ break;
+ default:
+ vpanic("showMIPSFpOp");
+ break;
+ }
+ return ret;
+}
+
+/* --------- MIPSAMode: memory address expressions. --------- */
+
+MIPSAMode *MIPSAMode_IR(Int idx, HReg base)
+{
+ MIPSAMode *am = LibVEX_Alloc(sizeof(MIPSAMode));
+ am->tag = Mam_IR;
+ am->Mam.IR.base = base;
+ am->Mam.IR.index = idx;
+
+ return am;
+}
+
+MIPSAMode *MIPSAMode_RR(HReg idx, HReg base)
+{
+ MIPSAMode *am = LibVEX_Alloc(sizeof(MIPSAMode));
+ am->tag = Mam_RR;
+ am->Mam.RR.base = base;
+ am->Mam.RR.index = idx;
+
+ return am;
+}
+
+MIPSAMode *dopyMIPSAMode(MIPSAMode * am)
+{
+ MIPSAMode* ret;
+ switch (am->tag) {
+ case Mam_IR:
+ ret = MIPSAMode_IR(am->Mam.IR.index, am->Mam.IR.base);
+ break;
+ case Mam_RR:
+ ret = MIPSAMode_RR(am->Mam.RR.index, am->Mam.RR.base);
+ break;
+ default:
+ vpanic("dopyMIPSAMode");
+ break;
+ }
+ return ret;
+}
+
+MIPSAMode *nextMIPSAModeFloat(MIPSAMode * am)
+{
+ MIPSAMode* ret;
+ switch (am->tag) {
+ case Mam_IR:
+ ret = MIPSAMode_IR(am->Mam.IR.index + 8, am->Mam.IR.base);
+ break;
+ case Mam_RR:
+ ret = MIPSAMode_RR(am->Mam.RR.index + 1, am->Mam.RR.base);
+ break;
+ default:
+ vpanic("dopyMIPSAMode");
+ break;
+ }
+ return ret;
+}
+
+MIPSAMode *nextMIPSAModeInt(MIPSAMode * am)
+{
+ MIPSAMode* ret;
+ switch (am->tag) {
+ case Mam_IR:
+ ret = MIPSAMode_IR(am->Mam.IR.index + 4, am->Mam.IR.base);
+ break;
+ case Mam_RR:
+ ret = MIPSAMode_RR(am->Mam.RR.index + 1, am->Mam.RR.base);
+ break;
+ default:
+ vpanic("dopyMIPSAMode");
+ break;
+ }
+ return ret;
+}
+
+void ppMIPSAMode(MIPSAMode * am, Bool mode64)
+{
+ switch (am->tag) {
+ case Mam_IR:
+ if (am->Mam.IR.index == 0)
+ vex_printf("0(");
+ else
+ vex_printf("%d(", (Int) am->Mam.IR.index);
+ ppHRegMIPS(am->Mam.IR.base, mode64);
+ vex_printf(")");
+ return;
+ case Mam_RR:
+ ppHRegMIPS(am->Mam.RR.base, mode64);
+ vex_printf(", ");
+ ppHRegMIPS(am->Mam.RR.index, mode64);
+ return;
+ default:
+ vpanic("ppMIPSAMode");
+ break;
+ }
+}
+
+static void addRegUsage_MIPSAMode(HRegUsage * u, MIPSAMode * am)
+{
+ switch (am->tag) {
+ case Mam_IR:
+ addHRegUse(u, HRmRead, am->Mam.IR.base);
+ return;
+ case Mam_RR:
+ addHRegUse(u, HRmRead, am->Mam.RR.base);
+ addHRegUse(u, HRmRead, am->Mam.RR.index);
+ return;
+ default:
+ vpanic("addRegUsage_MIPSAMode");
+ break;
+ }
+}
+
+static void mapRegs_MIPSAMode(HRegRemap * m, MIPSAMode * am)
+{
+ switch (am->tag) {
+ case Mam_IR:
+ am->Mam.IR.base = lookupHRegRemap(m, am->Mam.IR.base);
+ return;
+ case Mam_RR:
+ am->Mam.RR.base = lookupHRegRemap(m, am->Mam.RR.base);
+ am->Mam.RR.index = lookupHRegRemap(m, am->Mam.RR.index);
+ return;
+ default:
+ vpanic("mapRegs_MIPSAMode");
+ break;
+ }
+}
+
+/* --------- Operand, which can be a reg or a u16/s16. --------- */
+
+MIPSRH *MIPSRH_Imm(Bool syned, UShort imm16)
+{
+ MIPSRH *op = LibVEX_Alloc(sizeof(MIPSRH));
+ op->tag = Mrh_Imm;
+ op->Mrh.Imm.syned = syned;
+ op->Mrh.Imm.imm16 = imm16;
+ /* If this is a signed value, ensure it's not -32768, so that we
+ are guaranteed always to be able to negate if needed. */
+ if (syned)
+ vassert(imm16 != 0x8000);
+ vassert(syned == True || syned == False);
+ return op;
+}
+
+MIPSRH *MIPSRH_Reg(HReg reg)
+{
+ MIPSRH *op = LibVEX_Alloc(sizeof(MIPSRH));
+ op->tag = Mrh_Reg;
+ op->Mrh.Reg.reg = reg;
+ return op;
+}
+
+void ppMIPSRH(MIPSRH * op, Bool mode64)
+{
+ MIPSRHTag tag = op->tag;
+ switch (tag) {
+ case Mrh_Imm:
+ if (op->Mrh.Imm.syned)
+ vex_printf("%d", (Int) (Short) op->Mrh.Imm.imm16);
+ else
+ vex_printf("%u", (UInt) (UShort) op->Mrh.Imm.imm16);
+ return;
+ case Mrh_Reg:
+ ppHRegMIPS(op->Mrh.Reg.reg, mode64);
+ return;
+ default:
+ vpanic("ppMIPSRH");
+ break;
+ }
+}
+
+/* An MIPSRH can only be used in a "read" context (what would it mean
+ to write or modify a literal?) and so we enumerate its registers
+ accordingly. */
+static void addRegUsage_MIPSRH(HRegUsage * u, MIPSRH * op)
+{
+ switch (op->tag) {
+ case Mrh_Imm:
+ return;
+ case Mrh_Reg:
+ addHRegUse(u, HRmRead, op->Mrh.Reg.reg);
+ return;
+ default:
+ vpanic("addRegUsage_MIPSRH");
+ break;
+ }
+}
+
+static void mapRegs_MIPSRH(HRegRemap * m, MIPSRH * op)
+{
+ switch (op->tag) {
+ case Mrh_Imm:
+ return;
+ case Mrh_Reg:
+ op->Mrh.Reg.reg = lookupHRegRemap(m, op->Mrh.Reg.reg);
+ return;
+ default:
+ vpanic("mapRegs_MIPSRH");
+ break;
+ }
+}
+
+/* --------- Instructions. --------- */
+
+HChar *showMIPSUnaryOp(MIPSUnaryOp op)
+{
+ HChar* ret;
+ switch (op) {
+ case Mun_CLO:
+ ret = "clo";
+ break;
+ case Mun_CLZ:
+ ret = "clz";
+ break;
+ case Mun_NOP:
+ ret = "nop";
+ break;
+ default:
+ vpanic("showMIPSUnaryOp");
+ break;
+ }
+ return ret;
+}
+
+HChar *showMIPSAluOp(MIPSAluOp op, Bool immR)
+{
+ HChar* ret;
+ switch (op) {
+ case Malu_ADD:
+ ret = immR ? "addiu" : "addu";
+ break;
+ case Malu_SUB:
+ ret = "subu";
+ break;
+ case Malu_AND:
+ ret = immR ? "andi" : "and";
+ break;
+ case Malu_OR:
+ ret = immR ? "ori" : "or";
+ break;
+ case Malu_NOR:
+ vassert(immR == False); /*there's no nor with an immediate operand!? */
+ ret = "nor";
+ break;
+ case Malu_XOR:
+ ret = immR ? "xori" : "xor";
+ break;
+ default:
+ vpanic("showMIPSAluOp");
+ break;
+ }
+ return ret;
+}
+
+HChar *showMIPSShftOp(MIPSShftOp op, Bool immR, Bool sz32)
+{
+ HChar *ret;
+ switch (op) {
+ case Mshft_SRA:
+ ret = immR ? (sz32 ? "sar" : "dsar") : (sz32 ? "sarv" : "dsrav");
+ break;
+ case Mshft_SLL:
+ ret = immR ? (sz32 ? "sll" : "dsll") : (sz32 ? "sllv" : "dsllv");
+ break;
+ case Mshft_SRL:
+ ret = immR ? (sz32 ? "srl" : "dsrl") : (sz32 ? "srlv" : "dsrlv");
+ break;
+ default:
+ vpanic("showMIPSShftOp");
+ break;
+ }
+ return ret;
+}
+
+HChar *showMIPSMaccOp(MIPSMaccOp op, Bool variable)
+{
+ HChar *ret;
+ switch (op) {
+ case Macc_ADD:
+ ret = variable ? "madd" : "maddu";
+ break;
+ case Macc_SUB:
+ ret = variable ? "msub" : "msubu";
+ break;
+ default:
+ vpanic("showMIPSAccOp");
+ break;
+ }
+ return ret;
+}
+
+MIPSInstr *MIPSInstr_LI(HReg dst, ULong imm)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_LI;
+ i->Min.LI.dst = dst;
+ i->Min.LI.imm = imm;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_Alu(MIPSAluOp op, HReg dst, HReg srcL, MIPSRH * srcR)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Alu;
+ i->Min.Alu.op = op;
+ i->Min.Alu.dst = dst;
+ i->Min.Alu.srcL = srcL;
+ i->Min.Alu.srcR = srcR;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_Shft(MIPSShftOp op, Bool sz32, HReg dst, HReg srcL,
+ MIPSRH * srcR)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Shft;
+ i->Min.Shft.op = op;
+ i->Min.Shft.sz32 = sz32;
+ i->Min.Shft.dst = dst;
+ i->Min.Shft.srcL = srcL;
+ i->Min.Shft.srcR = srcR;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_Unary(MIPSUnaryOp op, HReg dst, HReg src)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Unary;
+ i->Min.Unary.op = op;
+ i->Min.Unary.dst = dst;
+ i->Min.Unary.src = src;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_Cmp(Bool syned, Bool sz32, HReg dst, HReg srcL, HReg srcR,
+ MIPSCondCode cond)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Cmp;
+ i->Min.Cmp.syned = syned;
+ i->Min.Cmp.sz32 = sz32;
+ i->Min.Cmp.dst = dst;
+ i->Min.Cmp.srcL = srcL;
+ i->Min.Cmp.srcR = srcR;
+ i->Min.Cmp.cond = cond;
+ return i;
+}
+
+/* multiply */
+MIPSInstr *MIPSInstr_Mul(Bool syned, Bool wid, Bool sz32, HReg dst, HReg srcL,
+ HReg srcR)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Mul;
+ i->Min.Mul.syned = syned;
+ i->Min.Mul.widening = wid; /* widen=True else False */
+ i->Min.Mul.sz32 = sz32; /* True = 32 bits */
+ i->Min.Mul.dst = dst;
+ i->Min.Mul.srcL = srcL;
+ i->Min.Mul.srcR = srcR;
+ return i;
+}
+
+/* msub */
+MIPSInstr *MIPSInstr_Msub(Bool syned, HReg srcL, HReg srcR)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Macc;
+
+ i->Min.Macc.op = Macc_SUB;
+ i->Min.Macc.syned = syned;
+ i->Min.Macc.srcL = srcL;
+ i->Min.Macc.srcR = srcR;
+ return i;
+}
+
+/* madd */
+MIPSInstr *MIPSInstr_Madd(Bool syned, HReg srcL, HReg srcR)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Macc;
+
+ i->Min.Macc.op = Macc_ADD;
+ i->Min.Macc.syned = syned;
+ i->Min.Macc.srcL = srcL;
+ i->Min.Macc.srcR = srcR;
+ return i;
+}
+
+/* div */
+MIPSInstr *MIPSInstr_Div(Bool syned, Bool sz32, HReg srcL, HReg srcR)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Div;
+ i->Min.Div.syned = syned;
+ i->Min.Div.sz32 = sz32; /* True = 32 bits */
+ i->Min.Div.srcL = srcL;
+ i->Min.Div.srcR = srcR;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_Call(MIPSCondCode cond, Addr32 target, UInt argiregs,
+ HReg src)
+{
+ UInt mask;
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Call;
+ i->Min.Call.cond = cond;
+ i->Min.Call.target = target;
+ i->Min.Call.argiregs = argiregs;
+ i->Min.Call.src = src;
+ /* Only r4 .. r7 inclusive may be used as arg regs. Hence: */
+ mask = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7);
+ vassert(0 == (argiregs & ~mask));
+ return i;
+}
+
+MIPSInstr *MIPSInstr_CallAlways(MIPSCondCode cond, Addr32 target, UInt argiregs)
+{
+ UInt mask;
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Call;
+ i->Min.Call.cond = cond;
+ i->Min.Call.target = target;
+ i->Min.Call.argiregs = argiregs;
+ /* Only r4 .. r7 inclusive may be used as arg regs. Hence: */
+ mask = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7);
+ vassert(0 == (argiregs & ~mask));
+ return i;
+}
+
+MIPSInstr *MIPSInstr_XDirect ( Addr32 dstGA, MIPSAMode* amPC,
+ MIPSCondCode cond, Bool toFastEP ) {
+ MIPSInstr* i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_XDirect;
+ i->Min.XDirect.dstGA = dstGA;
+ i->Min.XDirect.amPC = amPC;
+ i->Min.XDirect.cond = cond;
+ i->Min.XDirect.toFastEP = toFastEP;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_XIndir ( HReg dstGA, MIPSAMode* amPC,
+ MIPSCondCode cond ) {
+ MIPSInstr* i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_XIndir;
+ i->Min.XIndir.dstGA = dstGA;
+ i->Min.XIndir.amPC = amPC;
+ i->Min.XIndir.cond = cond;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_XAssisted ( HReg dstGA, MIPSAMode* amPC,
+ MIPSCondCode cond, IRJumpKind jk ) {
+ MIPSInstr* i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_XAssisted;
+ i->Min.XAssisted.dstGA = dstGA;
+ i->Min.XAssisted.amPC = amPC;
+ i->Min.XAssisted.cond = cond;
+ i->Min.XAssisted.jk = jk;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_Load(UChar sz, HReg dst, MIPSAMode * src, Bool mode64)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Load;
+ i->Min.Load.sz = sz;
+ i->Min.Load.src = src;
+ i->Min.Load.dst = dst;
+ vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
+
+ if (sz == 8)
+ vassert(mode64);
+ return i;
+}
+
+MIPSInstr *MIPSInstr_Store(UChar sz, MIPSAMode * dst, HReg src, Bool mode64)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Store;
+ i->Min.Store.sz = sz;
+ i->Min.Store.src = src;
+ i->Min.Store.dst = dst;
+ vassert(sz == 1 || sz == 2 || sz == 4 || sz == 8);
+
+ if (sz == 8)
+ vassert(mode64);
+ return i;
+}
+
+MIPSInstr *MIPSInstr_LoadL(UChar sz, HReg dst, MIPSAMode * src, Bool mode64)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_LoadL;
+ i->Min.LoadL.sz = sz;
+ i->Min.LoadL.src = src;
+ i->Min.LoadL.dst = dst;
+ vassert(sz == 4 || sz == 8);
+
+ if (sz == 8)
+ vassert(mode64);
+ return i;
+}
+
+MIPSInstr *MIPSInstr_StoreC(UChar sz, MIPSAMode * dst, HReg src, Bool mode64)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_StoreC;
+ i->Min.StoreC.sz = sz;
+ i->Min.StoreC.src = src;
+ i->Min.StoreC.dst = dst;
+ vassert(sz == 4 || sz == 8);
+
+ if (sz == 8)
+ vassert(mode64);
+ return i;
+}
+
+MIPSInstr *MIPSInstr_Mthi(HReg src)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Mthi;
+ i->Min.MtHL.src = src;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_Mtlo(HReg src)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Mtlo;
+ i->Min.MtHL.src = src;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_Mfhi(HReg dst)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Mfhi;
+ i->Min.MfHL.dst = dst;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_Mflo(HReg dst)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_Mflo;
+ i->Min.MfHL.dst = dst;
+ return i;
+}
+
+/* Read/Write Link Register */
+MIPSInstr *MIPSInstr_RdWrLR(Bool wrLR, HReg gpr)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_RdWrLR;
+ i->Min.RdWrLR.wrLR = wrLR;
+ i->Min.RdWrLR.gpr = gpr;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_FpLdSt(Bool isLoad, UChar sz, HReg reg, MIPSAMode * addr)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_FpLdSt;
+ i->Min.FpLdSt.isLoad = isLoad;
+ i->Min.FpLdSt.sz = sz;
+ i->Min.FpLdSt.reg = reg;
+ i->Min.FpLdSt.addr = addr;
+ vassert(sz == 4 || sz == 8);
+ return i;
+}
+
+MIPSInstr *MIPSInstr_FpUnary(MIPSFpOp op, HReg dst, HReg src)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_FpUnary;
+ i->Min.FpUnary.op = op;
+ i->Min.FpUnary.dst = dst;
+ i->Min.FpUnary.src = src;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_FpBinary(MIPSFpOp op, HReg dst, HReg srcL, HReg srcR)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_FpBinary;
+ i->Min.FpBinary.op = op;
+ i->Min.FpBinary.dst = dst;
+ i->Min.FpBinary.srcL = srcL;
+ i->Min.FpBinary.srcR = srcR;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_FpConvert(MIPSFpOp op, HReg dst, HReg src)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_FpConvert;
+ i->Min.FpConvert.op = op;
+ i->Min.FpConvert.dst = dst;
+ i->Min.FpConvert.src = src;
+ return i;
+
+}
+
+MIPSInstr *MIPSInstr_FpCompare(MIPSFpOp op, HReg dst, HReg srcL, HReg srcR,
+ UChar cond1)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_FpCompare;
+ i->Min.FpCompare.op = op;
+ i->Min.FpCompare.dst = dst;
+ i->Min.FpCompare.srcL = srcL;
+ i->Min.FpCompare.srcR = srcR;
+ i->Min.FpCompare.cond1 = cond1;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_MovCond(HReg dst, HReg argL, MIPSRH * argR, HReg condR,
+ MIPSCondCode cond)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_MovCond;
+ i->Min.MovCond.dst = dst;
+ i->Min.MovCond.srcL = argL;
+ i->Min.MovCond.srcR = argR;
+ i->Min.MovCond.condR = condR;
+ i->Min.MovCond.cond = cond;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_MtFCSR(HReg src)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_MtFCSR;
+ i->Min.MtFCSR.src = src;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_MfFCSR(HReg dst)
+{
+ MIPSInstr *i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_MfFCSR;
+ i->Min.MfFCSR.dst = dst;
+ return i;
+}
+
+MIPSInstr *MIPSInstr_EvCheck ( MIPSAMode* amCounter,
+ MIPSAMode* amFailAddr ) {
+ MIPSInstr* i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_EvCheck;
+ i->Min.EvCheck.amCounter = amCounter;
+ i->Min.EvCheck.amFailAddr = amFailAddr;
+ return i;
+}
+
+MIPSInstr* MIPSInstr_ProfInc ( void ) {
+ MIPSInstr* i = LibVEX_Alloc(sizeof(MIPSInstr));
+ i->tag = Min_ProfInc;
+ return i;
+}
+
+/* -------- Pretty Print instructions ------------- */
+static void ppLoadImm(HReg dst, ULong imm, Bool mode64)
+{
+ vex_printf("li ");
+ ppHRegMIPS(dst, mode64);
+ vex_printf(",0x%016llx", imm);
+}
+
+void ppMIPSInstr(MIPSInstr * i, Bool mode64)
+{
+ switch (i->tag) {
+ case Min_LI:
+ ppLoadImm(i->Min.LI.dst, i->Min.LI.imm, mode64);
+ break;
+ case Min_Alu: {
+ HReg r_srcL = i->Min.Alu.srcL;
+ MIPSRH *rh_srcR = i->Min.Alu.srcR;
+ /* generic */
+ vex_printf("%s ", showMIPSAluOp(i->Min.Alu.op,
+ toBool(rh_srcR->tag == Mrh_Imm)));
+ ppHRegMIPS(i->Min.Alu.dst, mode64);
+ vex_printf(",");
+ ppHRegMIPS(r_srcL, mode64);
+ vex_printf(",");
+ ppMIPSRH(rh_srcR, mode64);
+ return;
+ }
+ case Min_Shft: {
+ HReg r_srcL = i->Min.Shft.srcL;
+ MIPSRH *rh_srcR = i->Min.Shft.srcR;
+ vex_printf("%s ", showMIPSShftOp(i->Min.Shft.op,
+ toBool(rh_srcR->tag == Mrh_Imm),
+ i->Min.Shft.sz32));
+ ppHRegMIPS(i->Min.Shft.dst, mode64);
+ vex_printf(",");
+ ppHRegMIPS(r_srcL, mode64);
+ vex_printf(",");
+ ppMIPSRH(rh_srcR, mode64);
+ return;
+ }
+ case Min_Unary: {
+ vex_printf("%s ", showMIPSUnaryOp(i->Min.Unary.op));
+ ppHRegMIPS(i->Min.Unary.dst, mode64);
+ vex_printf(",");
+ ppHRegMIPS(i->Min.Unary.src, mode64);
+ return;
+ }
+ case Min_Cmp: {
+ vex_printf("word_compare ");
+ ppHRegMIPS(i->Min.Cmp.dst, mode64);
+ vex_printf(" = %s ( ", showMIPSCondCode(i->Min.Cmp.cond));
+ ppHRegMIPS(i->Min.Cmp.srcL, mode64);
+ vex_printf(", ");
+ ppHRegMIPS(i->Min.Cmp.srcR, mode64);
+ vex_printf(" )");
+
+ return;
+ }
+ case Min_Mul: {
+ switch (i->Min.Mul.widening) {
+ case False:
+ vex_printf("mul ");
+ ppHRegMIPS(i->Min.Mul.dst, mode64);
+ vex_printf(", ");
+ ppHRegMIPS(i->Min.Mul.srcL, mode64);
+ vex_printf(", ");
+ ppHRegMIPS(i->Min.Mul.srcR, mode64);
+ return;
+ case True:
+ vex_printf("%s%s ", i->Min.Mul.sz32 ? "mult" : "dmult",
+ i->Min.Mul.syned ? "" : "u");
+ ppHRegMIPS(i->Min.Mul.dst, mode64);
+ vex_printf(", ");
+ ppHRegMIPS(i->Min.Mul.srcL, mode64);
+ vex_printf(", ");
+ ppHRegMIPS(i->Min.Mul.srcR, mode64);
+ return;
+ }
+ break;
+ }
+ case Min_Mthi: {
+ vex_printf("mthi ");
+ ppHRegMIPS(i->Min.MtHL.src, mode64);
+ return;
+ }
+ case Min_Mtlo: {
+ vex_printf("mtlo ");
+ ppHRegMIPS(i->Min.MtHL.src, mode64);
+ return;
+ }
+ case Min_Mfhi: {
+ vex_printf("mfhi ");
+ ppHRegMIPS(i->Min.MfHL.dst, mode64);
+ return;
+ }
+ case Min_Mflo: {
+ vex_printf("mflo ");
+ ppHRegMIPS(i->Min.MfHL.dst, mode64);
+ return;
+ }
+ case Min_Macc: {
+ vex_printf("%s ", showMIPSMaccOp(i->Min.Macc.op, i->Min.Macc.syned));
+ ppHRegMIPS(i->Min.Macc.srcL, mode64);
+ vex_printf(", ");
+ ppHRegMIPS(i->Min.Macc.srcR, mode64);
+ return;
+ }
+ case Min_Div: {
+ if (!i->Min.Div.sz32)
+ vex_printf("d");
+ vex_printf("div");
+ vex_printf("%s ", i->Min.Div.syned ? "s" : "u");
+ ppHRegMIPS(i->Min.Div.srcL, mode64);
+ vex_printf(", ");
+ ppHRegMIPS(i->Min.Div.srcR, mode64);
+ return;
+ }
+ case Min_Call: {
+ Int n;
+ vex_printf("call: ");
+ if (i->Min.Call.cond != MIPScc_AL) {
+ vex_printf("if (%s) ", showMIPSCondCode(i->Min.Call.cond));
+ }
+ vex_printf("{ ");
+ ppLoadImm(hregMIPS_GPR11(mode64), i->Min.Call.target, mode64);
+
+ vex_printf(" ; mtctr r10 ; bctrl [");
+ for (n = 0; n < 32; n++) {
+ if (i->Min.Call.argiregs & (1 << n)) {
+ vex_printf("r%d", n);
+ if ((i->Min.Call.argiregs >> n) > 1)
+ vex_printf(",");
+ }
+ }
+ vex_printf("] }");
+ break;
+ }
+ case Min_XDirect:
+ vex_printf("(xDirect) ");
+ vex_printf("if (guest_COND.%s) { ",
+ showMIPSCondCode(i->Min.XDirect.cond));
+ vex_printf("move $9, 0x%x,", i->Min.XDirect.dstGA);
+ vex_printf("; sw $9, ");
+ ppMIPSAMode(i->Min.XDirect.amPC, mode64);
+ vex_printf("; move $9, $disp_cp_chain_me_to_%sEP; jalr $9; nop}",
+ i->Min.XDirect.toFastEP ? "fast" : "slow");
+ return;
+ case Min_XIndir:
+ vex_printf("(xIndir) ");
+ vex_printf("if (guest_COND.%s) { sw ",
+ showMIPSCondCode(i->Min.XIndir.cond));
+ ppHRegMIPS(i->Min.XIndir.dstGA, mode64);
+ vex_printf(", ");
+ ppMIPSAMode(i->Min.XIndir.amPC, mode64);
+ vex_printf("; move $9, $disp_indir; jalr $9; nop}");
+ return;
+ case Min_XAssisted:
+ vex_printf("(xAssisted) ");
+ vex_printf("if (guest_COND.%s) { ",
+ showMIPSCondCode(i->Min.XAssisted.cond));
+ vex_printf("sw ");
+ ppHRegMIPS(i->Min.XAssisted.dstGA, mode64);
+ vex_printf(", ");
+ ppMIPSAMode(i->Min.XAssisted.amPC, mode64);
+ vex_printf("; move $9, $IRJumpKind_to_TRCVAL(%d)",
+ (Int)i->Min.XAssisted.jk);
+ vex_printf("; move $9, $disp_assisted; jalr $9; nop; }");
+ return;
+ case Min_Load: {
+ Bool idxd = toBool(i->Min.Load.src->tag == Mam_RR);
+ UChar sz = i->Min.Load.sz;
+ UChar c_sz = sz == 1 ? 'b' : sz == 2 ? 'h' : sz == 4 ? 'w' : 'd';
+ vex_printf("l%c%s ", c_sz, idxd ? "x" : "");
+ ppHRegMIPS(i->Min.Load.dst, mode64);
+ vex_printf(",");
+ ppMIPSAMode(i->Min.Load.src, mode64);
+ return;
+ }
+ case Min_Store: {
+ UChar sz = i->Min.Store.sz;
+ Bool idxd = toBool(i->Min.Store.dst->tag == Mam_RR);
+ UChar c_sz = sz == 1 ? 'b' : sz == 2 ? 'h' : sz == 4 ? 'w' : 'd';
+ vex_printf("s%c%s ", c_sz, idxd ? "x" : "");
+ ppHRegMIPS(i->Min.Store.src, mode64);
+ vex_printf(",");
+ ppMIPSAMode(i->Min.Store.dst, mode64);
+ return;
+ }
+ case Min_LoadL: {
+ vex_printf("ll ");
+ ppHRegMIPS(i->Min.LoadL.dst, mode64);
+ vex_printf(",");
+ ppMIPSAMode(i->Min.LoadL.src, mode64);
+ return;
+ }
+ case Min_StoreC: {
+ vex_printf("sc ");
+ ppHRegMIPS(i->Min.StoreC.src, mode64);
+ vex_printf(",");
+ ppMIPSAMode(i->Min.StoreC.dst, mode64);
+ return;
+ }
+ case Min_RdWrLR: {
+ vex_printf("%s ", i->Min.RdWrLR.wrLR ? "mtlr" : "mflr");
+ ppHRegMIPS(i->Min.RdWrLR.gpr, mode64);
+ return;
+ }
+ case Min_FpUnary:
+ vex_printf("%s ", showMIPSFpOp(i->Min.FpUnary.op));
+ ppHRegMIPS(i->Min.FpUnary.dst, mode64);
+ vex_printf(",");
+ ppHRegMIPS(i->Min.FpUnary.src, mode64);
+ return;
+ case Min_FpBinary:
+ vex_printf("%s", showMIPSFpOp(i->Min.FpBinary.op));
+ ppHRegMIPS(i->Min.FpBinary.dst, mode64);
+ vex_printf(",");
+ ppHRegMIPS(i->Min.FpBinary.srcL, mode64);
+ vex_printf(",");
+ ppHRegMIPS(i->Min.FpBinary.srcR, mode64);
+ return;
+ case Min_FpConvert:
+ vex_printf("%s", showMIPSFpOp(i->Min.FpConvert.op));
+ ppHRegMIPS(i->Min.FpConvert.dst, mode64);
+ vex_printf(",");
+ ppHRegMIPS(i->Min.FpConvert.src, mode64);
+ return;
+ case Min_FpCompare:
+ vex_printf("%s ", showMIPSFpOp(i->Min.FpCompare.op));
+ ppHRegMIPS(i->Min.FpCompare.srcL, mode64);
+ vex_printf(",");
+ ppHRegMIPS(i->Min.FpCompare.srcR, mode64);
+ vex_printf(" cond: %c", i->Min.FpCompare.cond1);
+ return;
+ case Min_FpMulAcc:
+ vex_printf("%s ", showMIPSFpOp(i->Min.FpMulAcc.op));
+ ppHRegMIPS(i->Min.FpMulAcc.dst, mode64);
+ vex_printf(",");
+ ppHRegMIPS(i->Min.FpMulAcc.srcML, mode64);
+ vex_printf(",");
+ ppHRegMIPS(i->Min.FpMulAcc.srcMR, mode64);
+ vex_printf(",");
+ ppHRegMIPS(i->Min.FpMulAcc.srcAcc, mode64);
+ return;
+ case Min_FpLdSt: {
+ if (i->Min.FpLdSt.sz == 4) {
+ if (i->Min.FpLdSt.isLoad) {
+ vex_printf("lwc1 ");
+ ppHRegMIPS(i->Min.FpLdSt.reg, mode64);
+ vex_printf(",");
+ ppMIPSAMode(i->Min.FpLdSt.addr, mode64);
+ } else {
+ vex_printf("swc1 ");
+ ppHRegMIPS(i->Min.FpLdSt.reg, mode64);
+ vex_printf(",");
+ ppMIPSAMode(i->Min.FpLdSt.addr, mode64);
+ }
+ } else if (i->Min.FpLdSt.sz == 8) {
+ if (i->Min.FpLdSt.isLoad) {
+ if (mode64)
+ vex_printf("ldc1 ");
+ else
+ vex_printf("lwc1 ");
+ ppHRegMIPS(i->Min.FpLdSt.reg, mode64);
+ vex_printf(",");
+ ppMIPSAMode(i->Min.FpLdSt.addr, mode64);
+ } else {
+ if (mode64)
+ vex_printf("sdc1 ");
+ else
+ vex_printf("swc1 ");
+ ppHRegMIPS(i->Min.FpLdSt.reg, mode64);
+ vex_printf(",");
+ ppMIPSAMode(i->Min.FpLdSt.addr, mode64);
+ }
+ }
+ return;
+ }
+ case Min_MovCond: {
+ if (i->Min.MovCond.cond == MIPScc_MI) {
+ vex_printf("\ncond move\n");
+ return;
+
+ }
+ break;
+ }
+ case Min_MtFCSR: {
+ vex_printf("ctc1 ");
+ ppHRegMIPS(i->Min.MtFCSR.src, mode64);
+ vex_printf(", $31");
+ return;
+ }
+
+ case Min_MfFCSR: {
+ vex_printf("ctc1 ");
+ ppHRegMIPS(i->Min.MfFCSR.dst, mode64);
+ vex_printf(", $31");
+ return;
+ }
+ case Min_EvCheck:
+ vex_printf("(evCheck) lw $9, ");
+ ppMIPSAMode(i->Min.EvCheck.amCounter, mode64);
+ vex_printf("; addiu $9, $9, -1");
+ vex_printf("; sw $9, ");
+ ppMIPSAMode(i->Min.EvCheck.amCounter, mode64);
+ vex_printf("; bgez $t9, nofail; jalr *");
+ ppMIPSAMode(i->Min.EvCheck.amFailAddr, mode64);
+ vex_printf("; nofail:");
+ return;
+ case Min_ProfInc:
+ vex_printf("(profInc) move $9, ($NotKnownYet); "
+ "lw $8, 0($9); "
+ "addiu $8, $8, 1; "
+ "sw $8, 0($9); "
+ "sltiu $1, $8, 1; "
+ "lw $8, 4($9); "
+ "addu $8, $8, $1; "
+ "sw $8, 4($9); " );
+ return;
+ default:
+ vpanic("ppMIPSInstr");
+ break;
+ }
+}
+
+/* --------- Helpers for register allocation. --------- */
+
+void getRegUsage_MIPSInstr(HRegUsage * u, MIPSInstr * i, Bool mode64)
+{
+ initHRegUsage(u);
+ switch (i->tag) {
+ case Min_LI:
+ addHRegUse(u, HRmWrite, i->Min.LI.dst);
+ break;
+ case Min_Alu:
+ addHRegUse(u, HRmRead, i->Min.Alu.srcL);
+ addRegUsage_MIPSRH(u, i->Min.Alu.srcR);
+ addHRegUse(u, HRmWrite, i->Min.Alu.dst);
+ return;
+ case Min_Shft:
+ addHRegUse(u, HRmRead, i->Min.Shft.srcL);
+ addRegUsage_MIPSRH(u, i->Min.Shft.srcR);
+ addHRegUse(u, HRmWrite, i->Min.Shft.dst);
+ return;
+ case Min_Cmp:
+ addHRegUse(u, HRmRead, i->Min.Cmp.srcL);
+ addHRegUse(u, HRmRead, i->Min.Cmp.srcR);
+ addHRegUse(u, HRmWrite, i->Min.Cmp.dst);
+ return;
+ case Min_Unary:
+ addHRegUse(u, HRmRead, i->Min.Unary.src);
+ addHRegUse(u, HRmWrite, i->Min.Unary.dst);
+ return;
+ case Min_Mul:
+ addHRegUse(u, HRmWrite, i->Min.Mul.dst);
+ addHRegUse(u, HRmRead, i->Min.Mul.srcL);
+ addHRegUse(u, HRmRead, i->Min.Mul.srcR);
+ return;
+ case Min_Mthi:
+ case Min_Mtlo:
+ addHRegUse(u, HRmWrite, hregMIPS_HI(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_LO(mode64));
+ addHRegUse(u, HRmRead, i->Min.MtHL.src);
+ return;
+ case Min_Mfhi:
+ case Min_Mflo:
+ addHRegUse(u, HRmRead, hregMIPS_HI(mode64));
+ addHRegUse(u, HRmRead, hregMIPS_LO(mode64));
+ addHRegUse(u, HRmWrite, i->Min.MfHL.dst);
+ return;
+ case Min_MtFCSR:
+ addHRegUse(u, HRmRead, i->Min.MtFCSR.src);
+ return;
+ case Min_MfFCSR:
+ addHRegUse(u, HRmWrite, i->Min.MfFCSR.dst);
+ return;
+ case Min_Macc:
+ addHRegUse(u, HRmModify, hregMIPS_HI(mode64));
+ addHRegUse(u, HRmModify, hregMIPS_LO(mode64));
+ addHRegUse(u, HRmRead, i->Min.Macc.srcL);
+ addHRegUse(u, HRmRead, i->Min.Macc.srcR);
+ return;
+ case Min_Div:
+ addHRegUse(u, HRmWrite, hregMIPS_HI(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_LO(mode64));
+ addHRegUse(u, HRmRead, i->Min.Div.srcL);
+ addHRegUse(u, HRmRead, i->Min.Div.srcR);
+ return;
+ case Min_Call: {
+ if (i->Min.Call.cond != MIPScc_AL)
+ addHRegUse(u, HRmRead, i->Min.Call.src);
+ UInt argir;
+ addHRegUse(u, HRmWrite, hregMIPS_GPR1(mode64));
+
+ addHRegUse(u, HRmWrite, hregMIPS_GPR2(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_GPR3(mode64));
+
+ addHRegUse(u, HRmWrite, hregMIPS_GPR4(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_GPR5(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_GPR6(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_GPR7(mode64));
+
+ addHRegUse(u, HRmWrite, hregMIPS_GPR8(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_GPR9(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_GPR10(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_GPR11(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_GPR12(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_GPR13(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_GPR14(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_GPR15(mode64));
+
+ addHRegUse(u, HRmWrite, hregMIPS_GPR24(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_GPR25(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_GPR26(mode64));
+ addHRegUse(u, HRmWrite, hregMIPS_GPR27(mode64));
+
+ /* Now we have to state any parameter-carrying registers
+ which might be read. This depends on the argiregs field. */
+ argir = i->Min.Call.argiregs;
+ if (argir & (1 << 7))
+ addHRegUse(u, HRmRead, hregMIPS_GPR7(mode64));
+ if (argir & (1 << 6))
+ addHRegUse(u, HRmRead, hregMIPS_GPR6(mode64));
+ if (argir & (1 << 5))
+ addHRegUse(u, HRmRead, hregMIPS_GPR5(mode64));
+ if (argir & (1 << 4))
+ addHRegUse(u, HRmRead, hregMIPS_GPR4(mode64));
+
+ vassert(0 == (argir & ~((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7))));
+ return;
+ }
+ /* XDirect/XIndir/XAssisted are also a bit subtle. They
+ conditionally exit the block. Hence we only need to list (1)
+ the registers that they read, and (2) the registers that they
+ write in the case where the block is not exited. (2) is
+ empty, hence only (1) is relevant here. */
+ case Min_XDirect:
+ addRegUsage_MIPSAMode(u, i->Min.XDirect.amPC);
+ return;
+ case Min_XIndir:
+ addHRegUse(u, HRmRead, i->Min.XIndir.dstGA);
+ addRegUsage_MIPSAMode(u, i->Min.XIndir.amPC);
+ return;
+ case Min_XAssisted:
+ addHRegUse(u, HRmRead, i->Min.XAssisted.dstGA);
+ addRegUsage_MIPSAMode(u, i->Min.XAssisted.amPC);
+ return;
+ case Min_Load:
+ addRegUsage_MIPSAMode(u, i->Min.Load.src);
+ addHRegUse(u, HRmWrite, i->Min.Load.dst);
+ return;
+ case Min_Store:
+ addHRegUse(u, HRmRead, i->Min.Store.src);
+ addRegUsage_MIPSAMode(u, i->Min.Store.dst);
+ return;
+ case Min_LoadL:
+ addRegUsage_MIPSAMode(u, i->Min.LoadL.src);
+ addHRegUse(u, HRmWrite, i->Min.LoadL.dst);
+ return;
+ case Min_StoreC:
+ addHRegUse(u, HRmWrite, i->Min.StoreC.src);
+ addHRegUse(u, HRmRead, i->Min.StoreC.src);
+ addRegUsage_MIPSAMode(u, i->Min.StoreC.dst);
+ return;
+ case Min_RdWrLR:
+ addHRegUse(u, (i->Min.RdWrLR.wrLR ? HRmRead : HRmWrite),
+ i->Min.RdWrLR.gpr);
+ return;
+ case Min_FpLdSt:
+ if (i->Min.FpLdSt.sz == 4) {
+ addHRegUse(u, (i->Min.FpLdSt.isLoad ? HRmWrite : HRmRead),
+ i->Min.FpLdSt.reg);
+ addRegUsage_MIPSAMode(u, i->Min.FpLdSt.addr);
+ return;
+ } else if (i->Min.FpLdSt.sz == 8) {
+ if (mode64) {
+ addHRegUse(u, (i->Min.FpLdSt.isLoad ? HRmWrite : HRmRead),
+ i->Min.FpLdSt.reg);
+ addRegUsage_MIPSAMode(u, i->Min.FpLdSt.addr);
+ } else {
+ addHRegUse(u, (i->Min.FpLdSt.isLoad ? HRmWrite : HRmRead),
+ i->Min.FpLdSt.reg);
+ addRegUsage_MIPSAMode(u, i->Min.FpLdSt.addr);
+ addRegUsage_MIPSAMode(u, nextMIPSAModeFloat(i->Min.FpLdSt.addr));
+ }
+ return;
+ }
+ break;
+ case Min_FpUnary:
+ if (i->Min.FpUnary.op == Mfp_CVTD) {
+ addHRegUse(u, HRmWrite, i->Min.FpUnary.dst);
+ addHRegUse(u, HRmRead, i->Min.FpUnary.src);
+ return;
+ } else {
+ addHRegUse(u, HRmWrite, i->Min.FpUnary.dst);
+ addHRegUse(u, HRmRead, i->Min.FpUnary.src);
+ return;
+ }
+ case Min_FpBinary:
+ addHRegUse(u, HRmWrite, i->Min.FpBinary.dst);
+ addHRegUse(u, HRmRead, i->Min.FpBinary.srcL);
+ addHRegUse(u, HRmRead, i->Min.FpBinary.srcR);
+ return;
+ case Min_FpConvert:
+ addHRegUse(u, HRmWrite, i->Min.FpConvert.dst);
+ addHRegUse(u, HRmRead, i->Min.FpConvert.src);
+ return;
+ case Min_FpCompare:
+ addHRegUse(u, HRmWrite, i->Min.FpCompare.dst);
+ addHRegUse(u, HRmRead, i->Min.FpCompare.srcL);
+ addHRegUse(u, HRmRead, i->Min.FpCompare.srcR);
+ return;
+ case Min_MovCond:
+ if (i->Min.MovCond.srcR->tag == Mrh_Reg) {
+ addHRegUse(u, HRmRead, i->Min.MovCond.srcR->Mrh.Reg.reg);
+ }
+ addHRegUse(u, HRmRead, i->Min.MovCond.srcL);
+ addHRegUse(u, HRmRead, i->Min.MovCond.condR);
+ addHRegUse(u, HRmWrite, i->Min.MovCond.dst);
+ return;
+ case Min_EvCheck:
+ /* We expect both amodes only to mention %ebp, so this is in
+ fact pointless, since %ebp isn't allocatable, but anyway.. */
+ addRegUsage_MIPSAMode(u, i->Min.EvCheck.amCounter);
+ addRegUsage_MIPSAMode(u, i->Min.EvCheck.amFailAddr);
+ return;
+ case Min_ProfInc:
+ /* does not use any registers. */
+ return;
+ default:
+ ppMIPSInstr(i, mode64);
+ vpanic("getRegUsage_MIPSInstr");
+ break;
+ }
+}
+
+/* local helper */
+static void mapReg(HRegRemap * m, HReg * r)
+{
+ *r = lookupHRegRemap(m, *r);
+}
+
+void mapRegs_MIPSInstr(HRegRemap * m, MIPSInstr * i, Bool mode64)
+{
+ switch (i->tag) {
+ case Min_LI:
+ mapReg(m, &i->Min.LI.dst);
+ break;
+ case Min_Alu:
+ mapReg(m, &i->Min.Alu.srcL);
+ mapRegs_MIPSRH(m, i->Min.Alu.srcR);
+ mapReg(m, &i->Min.Alu.dst);
+ return;
+ case Min_Shft:
+ mapReg(m, &i->Min.Shft.srcL);
+ mapRegs_MIPSRH(m, i->Min.Shft.srcR);
+ mapReg(m, &i->Min.Shft.dst);
+ return;
+ case Min_Cmp:
+ mapReg(m, &i->Min.Cmp.srcL);
+ mapReg(m, &i->Min.Cmp.srcR);
+ mapReg(m, &i->Min.Cmp.dst);
+ return;
+ case Min_Unary:
+ mapReg(m, &i->Min.Unary.src);
+ mapReg(m, &i->Min.Unary.dst);
+ return;
+ case Min_Mul:
+ mapReg(m, &i->Min.Mul.dst);
+ mapReg(m, &i->Min.Mul.srcL);
+ mapReg(m, &i->Min.Mul.srcR);
+ return;
+ case Min_Mthi:
+ case Min_Mtlo:
+ mapReg(m, &i->Min.MtHL.src);
+ return;
+ case Min_Mfhi:
+ case Min_Mflo:
+ mapReg(m, &i->Min.MfHL.dst);
+ return;
+ case Min_Macc:
+ mapReg(m, &i->Min.Macc.srcL);
+ mapReg(m, &i->Min.Macc.srcR);
+ return;
+ case Min_Div:
+ mapReg(m, &i->Min.Div.srcL);
+ mapReg(m, &i->Min.Div.srcR);
+ return;
+ case Min_Call:
+ {
+ if (i->Min.Call.cond != MIPScc_AL)
+ mapReg(m, &i->Min.Call.src);
+ return;
+ }
+ case Min_XDirect:
+ mapRegs_MIPSAMode(m, i->Min.XDirect.amPC);
+ return;
+ case Min_XIndir:
+ mapReg(m, &i->Min.XIndir.dstGA);
+ mapRegs_MIPSAMode(m, i->Min.XIndir.amPC);
+ return;
+ case Min_XAssisted:
+ mapReg(m, &i->Min.XAssisted.dstGA);
+ mapRegs_MIPSAMode(m, i->Min.XAssisted.amPC);
+ return;
+ case Min_Load:
+ mapRegs_MIPSAMode(m, i->Min.Load.src);
+ mapReg(m, &i->Min.Load.dst);
+ return;
+ case Min_Store:
+ mapReg(m, &i->Min.Store.src);
+ mapRegs_MIPSAMode(m, i->Min.Store.dst);
+ return;
+ case Min_LoadL:
+ mapRegs_MIPSAMode(m, i->Min.LoadL.src);
+ mapReg(m, &i->Min.LoadL.dst);
+ return;
+ case Min_StoreC:
+ mapReg(m, &i->Min.StoreC.src);
+ mapRegs_MIPSAMode(m, i->Min.StoreC.dst);
+ return;
+ case Min_RdWrLR:
+ mapReg(m, &i->Min.RdWrLR.gpr);
+ return;
+ case Min_FpLdSt:
+ if (i->Min.FpLdSt.sz == 4) {
+ mapReg(m, &i->Min.FpLdSt.reg);
+ mapRegs_MIPSAMode(m, i->Min.FpLdSt.addr);
+ return;
+ } else if (i->Min.FpLdSt.sz == 8) {
+ if (mode64) {
+ mapReg(m, &i->Min.FpLdSt.reg);
+ mapRegs_MIPSAMode(m, i->Min.FpLdSt.addr);
+ } else {
+ mapReg(m, &i->Min.FpLdSt.reg);
+ mapRegs_MIPSAMode(m, i->Min.FpLdSt.addr);
+ mapRegs_MIPSAMode(m, nextMIPSAModeFloat(i->Min.FpLdSt.addr));
+ }
+ return;
+ }
+ break;
+ case Min_FpUnary:
+ if (i->Min.FpUnary.op == Mfp_CVTD) {
+ mapReg(m, &i->Min.FpUnary.dst);
+ mapReg(m, &i->Min.FpUnary.src);
+ return;
+ } else {
+ mapReg(m, &i->Min.FpUnary.dst);
+ mapReg(m, &i->Min.FpUnary.src);
+ return;
+ }
+ case Min_FpBinary:
+ mapReg(m, &i->Min.FpBinary.dst);
+ mapReg(m, &i->Min.FpBinary.srcL);
+ mapReg(m, &i->Min.FpBinary.srcR);
+ return;
+ case Min_FpConvert:
+ mapReg(m, &i->Min.FpConvert.dst);
+ mapReg(m, &i->Min.FpConvert.src);
+ return;
+ case Min_FpCompare:
+ mapReg(m, &i->Min.FpCompare.dst);
+ mapReg(m, &i->Min.FpCompare.srcL);
+ mapReg(m, &i->Min.FpCompare.srcR);
+ return;
+ case Min_MtFCSR:
+ mapReg(m, &i->Min.MtFCSR.src);
+ return;
+ case Min_MfFCSR:
+ mapReg(m, &i->Min.MfFCSR.dst);
+ return;
+ case Min_MovCond:
+ if (i->Min.MovCond.srcR->tag == Mrh_Reg) {
+ mapReg(m, &(i->Min.MovCond.srcR->Mrh.Reg.reg));
+ }
+ mapReg(m, &i->Min.MovCond.srcL);
+ mapReg(m, &i->Min.MovCond.condR);
+ mapReg(m, &i->Min.MovCond.dst);
+
+ return;
+ case Min_EvCheck:
+ /* We expect both amodes only to mention %ebp, so this is in
+ fact pointless, since %ebp isn't allocatable, but anyway.. */
+ mapRegs_MIPSAMode(m, i->Min.EvCheck.amCounter);
+ mapRegs_MIPSAMode(m, i->Min.EvCheck.amFailAddr);
+ return;
+ case Min_ProfInc:
+ /* does not use any registers. */
+ return;
+ default:
+ ppMIPSInstr(i, mode64);
+ vpanic("mapRegs_MIPSInstr");
+ break;
+ }
+
+}
+
+/* Figure out if i represents a reg-reg move, and if so assign the
+ source and destination to *src and *dst. If in doubt say No. Used
+ by the register allocator to do move coalescing.
+*/
+Bool isMove_MIPSInstr(MIPSInstr * i, HReg * src, HReg * dst)
+{
+ /* Moves between integer regs */
+ if (i->tag == Min_Alu) {
+ // or Rd,Rs,Rs == mr Rd,Rs
+ if (i->Min.Alu.op != Malu_OR)
+ return False;
+ if (i->Min.Alu.srcR->tag != Mrh_Reg)
+ return False;
+ if (i->Min.Alu.srcR->Mrh.Reg.reg != i->Min.Alu.srcL)
+ return False;
+ *src = i->Min.Alu.srcL;
+ *dst = i->Min.Alu.dst;
+ return True;
+ }
+ return False;
+}
+
+/* Generate mips spill/reload instructions under the direction of the
+ register allocator.
+*/
+void genSpill_MIPS( /*OUT*/ HInstr ** i1, /*OUT*/ HInstr ** i2, HReg rreg,
+ Int offsetB, Bool mode64)
+{
+ MIPSAMode *am;
+ vassert(offsetB >= 0);
+ vassert(!hregIsVirtual(rreg));
+ *i1 = *i2 = NULL;
+ am = MIPSAMode_IR(offsetB, GuestStatePointer(mode64));
+
+ switch (hregClass(rreg)) {
+ case HRcInt64:
+ vassert(mode64);
+ *i1 = MIPSInstr_Store(8, am, rreg, mode64);
+ break;
+ case HRcInt32:
+ vassert(!mode64);
+ *i1 = MIPSInstr_Store(4, am, rreg, mode64);
+ break;
+ case HRcFlt32:
+ vassert(!mode64);
+ *i1 = MIPSInstr_FpLdSt(False /*Store */ , 4, rreg, am);
+ break;
+ case HRcFlt64:
+ *i1 = MIPSInstr_FpLdSt(False /*Store */ , 8, rreg, am);
+ break;
+ default:
+ ppHRegClass(hregClass(rreg));
+ vpanic("genSpill_MIPS: unimplemented regclass");
+ break;
+ }
+}
+
+void genReload_MIPS( /*OUT*/ HInstr ** i1, /*OUT*/ HInstr ** i2, HReg rreg,
+ Int offsetB, Bool mode64)
+{
+ MIPSAMode *am;
+ vassert(!hregIsVirtual(rreg));
+ am = MIPSAMode_IR(offsetB, GuestStatePointer(mode64));
+
+ switch (hregClass(rreg)) {
+ case HRcInt64:
+ vassert(mode64);
+ *i1 = MIPSInstr_Load(8, rreg, am, mode64);
+ break;
+ case HRcInt32:
+ vassert(!mode64);
+ *i1 = MIPSInstr_Load(4, rreg, am, mode64);
+ break;
+ case HRcFlt32:
+ if (mode64)
+ *i1 = MIPSInstr_FpLdSt(True /*Load */ , 8, rreg, am);
+ else
+ *i1 = MIPSInstr_FpLdSt(True /*Load */ , 4, rreg, am);
+ break;
+ case HRcFlt64:
+ *i1 = MIPSInstr_FpLdSt(True /*Load */ , 8, rreg, am);
+ break;
+ default:
+ ppHRegClass(hregClass(rreg));
+ vpanic("genReload_MIPS: unimplemented regclass");
+ break;
+ }
+}
+
+/* --------- The mips assembler --------- */
+
+static UInt iregNo(HReg r, Bool mode64)
+{
+ UInt n;
+ vassert(hregClass(r) == mode64 ? HRcInt64 : HRcInt32);
+ vassert(!hregIsVirtual(r));
+ n = hregNumber(r);
+ vassert(n <= 32);
+ return n;
+}
+
+static UChar fregNo(HReg r, Bool mode64)
+{
+ UInt n;
+ vassert(hregClass(r) == mode64 ? HRcFlt64 : HRcFlt32);
+ vassert(!hregIsVirtual(r));
+ n = hregNumber(r);
+ vassert(n <= 31);
+ return n;
+}
+
+static UChar dregNo(HReg r)
+{
+ UInt n;
+ vassert(hregClass(r) == HRcFlt64);
+ vassert(!hregIsVirtual(r));
+ n = hregNumber(r);
+ vassert(n <= 31);
+ return n;
+}
+
+/* Emit 32bit instruction */
+static UChar *emit32(UChar * p, UInt w32)
+{
+#if defined (_MIPSEL)
+ *p++ = toUChar(w32 & 0x000000FF);
+ *p++ = toUChar((w32 >> 8) & 0x000000FF);
+ *p++ = toUChar((w32 >> 16) & 0x000000FF);
+ *p++ = toUChar((w32 >> 24) & 0x000000FF);
+#elif defined (_MIPSEB)
+ *p++ = toUChar((w32 >> 24) & 0x000000FF);
+ *p++ = toUChar((w32 >> 16) & 0x000000FF);
+ *p++ = toUChar((w32 >> 8) & 0x000000FF);
+ *p++ = toUChar(w32 & 0x000000FF);
+#endif
+ return p;
+}
+/* Fetch an instruction */
+static UInt fetch32 ( UChar* p )
+{
+ UInt w32 = 0;
+#if defined (_MIPSEL)
+ w32 |= ((0xFF & (UInt)p[0]) << 0);
+ w32 |= ((0xFF & (UInt)p[1]) << 8);
+ w32 |= ((0xFF & (UInt)p[2]) << 16);
+ w32 |= ((0xFF & (UInt)p[3]) << 24);
+#elif defined (_MIPSEB)
+ w32 |= ((0xFF & (UInt)p[0]) << 24);
+ w32 |= ((0xFF & (UInt)p[1]) << 16);
+ w32 |= ((0xFF & (UInt)p[2]) << 8);
+ w32 |= ((0xFF & (UInt)p[3]) << 0);
+#endif
+ return w32;
+}
+
+/* physical structure of mips instructions */
+/* type I : opcode - 6 bits
+ rs - 5 bits
+ rt - 5 bits
+ immediate - 16 bits
+*/
+static UChar *mkFormI(UChar * p, UInt opc, UInt rs, UInt rt, UInt imm)
+{
+ UInt theInstr;
+ vassert(opc < 0x40);
+ vassert(rs < 0x20);
+ vassert(rt < 0x20);
+ imm = imm & 0xFFFF;
+ theInstr = ((opc << 26) | (rs << 21) | (rt << 16) | (imm));
+ return emit32(p, theInstr);
+}
+
+/* type R: opcode - 6 bits
+ rs - 5 bits
+ rt - 5 bits
+ rd - 5 bits
+ sa - 5 bits
+ func - 6 bits
+*/
+static UChar *mkFormR(UChar * p, UInt opc, UInt rs, UInt rt, UInt rd, UInt sa,
+ UInt func)
+{
+ if (rs >= 0x20)
+ vex_printf("rs = %d\n", rs);
+ UInt theInstr;
+ vassert(opc < 0x40);
+ vassert(rs < 0x20);
+ vassert(rt < 0x20);
+ vassert(rd < 0x20);
+ vassert(sa < 0x20);
+ func = func & 0xFFFF;
+ theInstr = ((opc << 26) | (rs << 21) | (rt << 16) | (rd << 11) | (sa << 6) |
+ (func));
+
+ return emit32(p, theInstr);
+}
+
+static UChar *mkFormS(UChar * p, UInt opc1, UInt rRD, UInt rRS, UInt rRT,
+ UInt sa, UInt opc2)
+{
+ UInt theInstr;
+ vassert(opc1 <= 0x3F);
+ vassert(rRD < 0x20);
+ vassert(rRS < 0x20);
+ vassert(rRT < 0x20);
+ vassert(opc2 <= 0x3F);
+ vassert(sa >= 0 && sa <= 0x3F);
+
+ theInstr = ((opc1 << 26) | (rRS << 21) | (rRT << 16) | (rRD << 11) |
+ ((sa & 0x1F) << 6) | (opc2));
+
+ return emit32(p, theInstr);
+}
+
+static UChar *doAMode_IR(UChar * p, UInt opc1, UInt rSD, MIPSAMode * am,
+ Bool mode64)
+{
+ UInt rA, idx, r_dst;
+ vassert(am->tag == Mam_IR);
+ vassert(am->Mam.IR.index < 0x10000);
+
+ rA = iregNo(am->Mam.IR.base, mode64);
+ idx = am->Mam.IR.index;
+
+ if (rSD == 33 || rSD == 34)
+ r_dst = 24;
+ else
+ r_dst = rSD;
+
+ if (opc1 < 40) {
+ //load
+ if (rSD == 33)
+ /* mfhi */
+ p = mkFormR(p, 0, 0, 0, r_dst, 0, 16);
+ else if (rSD == 34)
+ /* mflo */
+ p = mkFormR(p, 0, 0, 0, r_dst, 0, 18);
+ }
+
+ p = mkFormI(p, opc1, rA, r_dst, idx);
+
+ if (opc1 >= 40) {
+ //store
+ if (rSD == 33)
+ /* mthi */
+ p = mkFormR(p, 0, r_dst, 0, 0, 0, 17);
+ else if (rSD == 34)
+ /* mtlo */
+ p = mkFormR(p, 0, r_dst, 0, 0, 0, 19);
+ }
+
+ return p;
+}
+
+static UChar *doAMode_RR(UChar * p, UInt opc1, UInt rSD, MIPSAMode * am,
+ Bool mode64)
+{
+ UInt rA, rB, r_dst;
+ vassert(am->tag == Mam_RR);
+
+ rA = iregNo(am->Mam.RR.base, mode64);
+ rB = iregNo(am->Mam.RR.index, mode64);
+
+ if (rSD == 33 || rSD == 34)
+ r_dst = 24;
+ else
+ r_dst = rSD;
+
+ if (opc1 < 40) {
+ //load
+ if (rSD == 33)
+ /* mfhi */
+ p = mkFormR(p, 0, 0, 0, r_dst, 0, 16);
+ else if (rSD == 34)
+ /* mflo */
+ p = mkFormR(p, 0, 0, 0, r_dst, 0, 18);
+ }
+ /* addiu sp, sp, -4
+ * sw rA, 0(sp)
+ * addu rA, rA, rB
+ * sw/lw r_dst, 0(rA)
+ * lw rA, 0(sp)
+ * addiu sp, sp, 4 */
+ if (mode64) {
+ p = mkFormI(p, 25, 29, 29, 0xFFFC);
+ p = mkFormI(p, 63, 29, rA, 0);
+ p = mkFormR(p, 0, rA, rB, rA, 0, 45);
+ p = mkFormI(p, opc1, rA, r_dst, 0);
+ p = mkFormI(p, 55, 29, rA, 0);
+ p = mkFormI(p, 25, 29, 29, 4);
+ } else {
+ p = mkFormI(p, 9, 29, 29, 0xFFFC);
+ p = mkFormI(p, 43, 29, rA, 0);
+ p = mkFormR(p, 0, rA, rB, rA, 0, 33);
+ p = mkFormI(p, opc1, rA, r_dst, 0);
+ p = mkFormI(p, 35, 29, rA, 0);
+ p = mkFormI(p, 9, 29, 29, 4);
+ }
+ if (opc1 >= 40) {
+ //store
+ if (rSD == 33)
+ /* mthi */
+ p = mkFormR(p, 0, r_dst, 0, 0, 0, 17);
+ else if (rSD == 34)
+ /* mtlo */
+ p = mkFormR(p, 0, r_dst, 0, 0, 0, 19);
+ }
+
+ return p;
+}
+
+/* Load imm to r_dst */
+static UChar *mkLoadImm(UChar * p, UInt r_dst, ULong imm, Bool mode64)
+{
+ if (!mode64) {
+ vassert(r_dst < 0x20);
+ UInt u32 = (UInt) imm;
+ Int s32 = (Int) u32;
+ Long s64 = (Long) s32;
+ imm = (ULong) s64;
+ }
+
+ if (imm >= 0xFFFFFFFFFFFF8000ULL || imm < 0x8000) {
+ // sign-extendable from 16 bits
+ // addiu r_dst,0,imm => li r_dst,imm
+ p = mkFormI(p, 9, 0, r_dst, imm & 0xFFFF);
+ } else {
+ if (imm >= 0xFFFFFFFF80000000ULL || imm < 0x80000000ULL) {
+ // sign-extendable from 32 bits
+ // addiu r_dst,r0,(imm>>16) => lis r_dst, (imm>>16)
+ // lui r_dst, (imm>>16)
+ p = mkFormI(p, 15, 0, r_dst, (imm >> 16) & 0xFFFF);
+ // ori r_dst, r_dst, (imm & 0xFFFF)
+ p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
+ } else {
+ vassert(mode64);
+ // lui load in upper half of low word
+ p = mkFormI(p, 15, 0, r_dst, (imm >> 48) & 0xFFFF);
+ // ori
+ p = mkFormI(p, 13, r_dst, r_dst, (imm >> 32) & 0xFFFF);
+ //shift
+ p = mkFormS(p, 0, r_dst, 0, r_dst, 16, 56);
+ // ori
+ p = mkFormI(p, 13, r_dst, r_dst, (imm >> 16) & 0xFFFF);
+ //shift
+ p = mkFormS(p, 0, r_dst, 0, r_dst, 16, 56);
+ // ori
+ p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
+ }
+ }
+ return p;
+}
+
+/* A simplified version of mkLoadImm that always generates 2 or 5
+ instructions (32 or 64 bits respectively) even if it could generate
+ fewer. This is needed for generating fixed sized patchable
+ sequences. */
+static UChar* mkLoadImm_EXACTLY2or5 ( UChar* p,
+ UInt r_dst, ULong imm, Bool mode64 )
+{
+ vassert(r_dst < 0x20);
+
+ if (!mode64) {
+ /* In 32-bit mode, make sure the top 32 bits of imm are a sign
+ extension of the bottom 32 bits. (Probably unnecessary.) */
+ UInt u32 = (UInt)imm;
+ Int s32 = (Int)u32;
+ Long s64 = (Long)s32;
+ imm = (ULong)s64;
+ }
+
+ if (!mode64) {
+ // sign-extendable from 32 bits
+ // addiu r_dst,r0,(imm>>16) => lis r_dst, (imm>>16)
+ // lui r_dst, (imm>>16)
+ p = mkFormI(p, 15, 0, r_dst, (imm >> 16) & 0xFFFF);
+ // ori r_dst, r_dst, (imm & 0xFFFF)
+ p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
+ } else {
+ vassert(0);
+ }
+ return p;
+}
+
+/* Checks whether the sequence of bytes at p was indeed created
+ by mkLoadImm_EXACTLY2or5 with the given parameters. */
+static Bool isLoadImm_EXACTLY2or5 ( UChar* p_to_check,
+ UInt r_dst, ULong imm, Bool mode64 )
+{
+ vassert(r_dst < 0x20);
+ Bool ret;
+ if (!mode64) {
+ /* In 32-bit mode, make sure the top 32 bits of imm are a sign
+ extension of the bottom 32 bits. (Probably unnecessary.) */
+ UInt u32 = (UInt)imm;
+ Int s32 = (Int)u32;
+ Long s64 = (Long)s32;
+ imm = (ULong)s64;
+ }
+
+ if (!mode64) {
+ UInt expect[2] = { 0, 0 };
+ UChar* p = (UChar*)&expect[0];
+ // lui r_dst, (imm>>16)
+ p = mkFormI(p, 15, 0, r_dst, (imm >> 16) & 0xFFFF);
+ // ori r_dst, r_dst, (imm & 0xFFFF)
+ p = mkFormI(p, 13, r_dst, r_dst, imm & 0xFFFF);
+ vassert(p == (UChar*)&expect[2]);
+
+ ret = fetch32(p_to_check + 0) == expect[0]
+ && fetch32(p_to_check + 4) == expect[1];
+
+ } else {
+ vassert(0);
+ }
+ return ret;
+}
+
+/* Generate a machine-word sized load or store. Simplified version of
+ the Min_Load and Min_Store cases below. */
+static UChar* do_load_or_store_machine_word (
+ UChar* p, Bool isLoad,
+ UInt reg, MIPSAMode* am, Bool mode64 )
+{
+ if (isLoad) { /* load */
+ UInt opc1, sz = mode64 ? 8 : 4;
+ switch (am->tag) {
+ case Mam_IR:
+ if (mode64) {
+ vassert(0 == (am->Mam.IR.index & 3));
+ }
+ switch (sz) {
+ case 1:
+ opc1 = 32;
+ break;
+ case 2:
+ opc1 = 33;
+ break;
+ case 4:
+ opc1 = 35;
+ break;
+ case 8:
+ opc1 = 55;
+ vassert(mode64);
+ break;
+ break;
+ default:
+ vassert(0);
+ break;
+ }
+ p = doAMode_IR(p, opc1, reg, am, mode64);
+ break;
+ case Mam_RR:
+ /* we could handle this case, but we don't expect to ever
+ need to. */
+ vassert(0);
+ break;
+ default:
+ vassert(0);
+ break;
+ }
+ } else /* store */ {
+ UInt opc1, sz = mode64 ? 8 : 4;
+ switch (am->tag) {
+ case Mam_IR:
+ if (mode64) {
+ vassert(0 == (am->Mam.IR.index & 3));
+ }
+ switch (sz) {
+ case 1:
+ opc1 = 40;
+ break;
+ case 2:
+ opc1 = 41;
+ break;
+ case 4:
+ opc1 = 43;
+ break;
+ case 8:
+ vassert(mode64);
+ opc1 = 63;
+ break;
+ default:
+ vassert(0);
+ break;
+ }
+ p = doAMode_IR(p, opc1, reg, am, mode64);
+ break;
+ case Mam_RR:
+ /* we could handle this case, but we don't expect to ever
+ need to. */
+ vassert(0);
+ break;
+ default:
+ vassert(0);
+ break;
+ }
+ }
+ return p;
+}
+
+/* Move r_dst to r_src */
+static UChar *mkMoveReg(UChar * p, UInt r_dst, UInt r_src)
+{
+ vassert(r_dst < 0x20);
+ vassert(r_src < 0x20);
+
+ if (r_dst != r_src) {
+ /* or r_dst, r_src, r_src */
+ p = mkFormR(p, 0, r_src, r_src, r_dst, 0, 37);
+ }
+ return p;
+}
+
+/* Emit an instruction into buf and return the number of bytes used.
+ Note that buf is not the insn's final place, and therefore it is
+ imperative to emit position-independent code. If the emitted
+ instruction was a profiler inc, set *is_profInc to True, else
+ leave it unchanged. */
+Int emit_MIPSInstr ( /*MB_MOD*/Bool* is_profInc,
+ UChar* buf, Int nbuf, MIPSInstr* i,
+ Bool mode64,
+ void* disp_cp_chain_me_to_slowEP,
+ void* disp_cp_chain_me_to_fastEP,
+ void* disp_cp_xindir,
+ void* disp_cp_xassisted )
+{
+ UChar *p = &buf[0];
+ UChar *ptmp = p;
+ vassert(nbuf >= 32);
+
+ switch (i->tag) {
+ case Min_MovCond: {
+ MIPSRH *srcR = i->Min.MovCond.srcR;
+ UInt condR = iregNo(i->Min.MovCond.condR, mode64);
+ UInt dst = iregNo(i->Min.MovCond.dst, mode64);
+
+ UInt srcL = iregNo(i->Min.MovCond.srcL, mode64);
+
+ p = mkMoveReg(p, dst, srcL);
+ if (i->Min.MovCond.cond == MIPScc_MI) {
+ p = mkFormI(p, 7, condR, 0, 2); //bgtz cond,2
+ }
+
+ p = mkFormR(p, 0, 0, 0, 0, 0, 0); //nop
+
+ if (srcR->tag == Mrh_Reg) {
+ //or dst,src,src
+ p = mkMoveReg(p, dst, iregNo(srcR->Mrh.Reg.reg, mode64));
+ /*p = mkFormR(p, 0, dst, iregNo(src->Mrh.Reg.reg, mode64),
+ iregNo(src->Mrh.Reg.reg, mode64), 0, 37);*/
+ } else {
+ p = mkLoadImm(p, dst, srcR->Mrh.Imm.imm16, mode64);
+ }
+ }
+ goto done;
+
+ case Min_LI:
+ p = mkLoadImm(p, iregNo(i->Min.LI.dst, mode64), i->Min.LI.imm, mode64);
+ goto done;
+
+ case Min_Alu: {
+ MIPSRH *srcR = i->Min.Alu.srcR;
+ Bool immR = toBool(srcR->tag == Mrh_Imm);
+ UInt r_dst = iregNo(i->Min.Alu.dst, mode64);
+ UInt r_srcL = iregNo(i->Min.Alu.srcL, mode64);
+ UInt r_srcR = immR ? (-1) /*bogus */ : iregNo(srcR->Mrh.Reg.reg, mode64);
+
+ switch (i->Min.Alu.op) {
+ /*Malu_ADD, Malu_SUB, Malu_AND, Malu_OR, Malu_NOR, Malu_XOR */
+ case Malu_ADD:
+ if (immR) {
+ vassert(srcR->Mrh.Imm.imm16 != 0x8000);
+ if (srcR->Mrh.Imm.syned)
+ /* addi */
+ p = mkFormI(p, 9, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
+ else
+ /* addiu */
+ p = mkFormI(p, 9, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
+ } else {
+ /* addu */
+ p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 33);
+ }
+ break;
+ case Malu_SUB:
+ if (immR) {
+ /* addi , but with negated imm */
+ vassert(srcR->Mrh.Imm.syned);
+ vassert(srcR->Mrh.Imm.imm16 != 0x8000);
+ p = mkFormI(p, 8, r_srcL, r_dst, (-srcR->Mrh.Imm.imm16));
+ } else {
+ /* subu */
+ p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 35);
+ }
+ break;
+ case Malu_AND:
+ if (immR) {
+ /* andi */
+ vassert(!srcR->Mrh.Imm.syned);
+ p = mkFormI(p, 12, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
+ } else {
+ /* and */
+ p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 36);
+ }
+ break;
+ case Malu_OR:
+ if (immR) {
+ /* ori */
+ vassert(!srcR->Mrh.Imm.syned);
+ p = mkFormI(p, 13, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
+ } else {
+ /* or */
+ if (r_srcL == 33)
+ //MFHI
+ p = mkFormR(p, 0, 0, 0, r_dst, 0, 16);
+ else if (r_srcL == 34)
+ //MFLO
+ p = mkFormR(p, 0, 0, 0, r_dst, 0, 18);
+ else if (r_dst == 33)
+ //MTHI
+ p = mkFormR(p, 0, r_srcL, 0, 0, 0, 17);
+ else if (r_dst == 34)
+ //MTLO
+ p = mkFormR(p, 0, r_srcL, 0, 0, 0, 19);
+ else
+ p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 37);
+ }
+ break;
+ case Malu_NOR:
+ /* nor */
+ vassert(!immR);
+ p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 39);
+ break;
+ case Malu_XOR:
+ if (immR) {
+ /* xori */
+ vassert(!srcR->Mrh.Imm.syned);
+ p = mkFormI(p, 14, r_srcL, r_dst, srcR->Mrh.Imm.imm16);
+ } else {
+ /* xor */
+ p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 38);
+ }
+ break;
+
+ default:
+ goto bad;
+ }
+ goto done;
+ }
+
+ case Min_Shft: {
+ MIPSRH *srcR = i->Min.Shft.srcR;
+ Bool sz32 = i->Min.Shft.sz32;
+ Bool immR = toBool(srcR->tag == Mrh_Imm);
+ UInt r_dst = iregNo(i->Min.Shft.dst, mode64);
+ UInt r_srcL = iregNo(i->Min.Shft.srcL, mode64);
+ UInt r_srcR = immR ? (-1) /*bogus */ : iregNo(srcR->Mrh.Reg.reg,
+ mode64);
+ if (!mode64)
+ vassert(sz32);
+ switch (i->Min.Shft.op) {
+ case Mshft_SLL:
+ if (sz32) {
+ if (immR) {
+ UInt n = srcR->Mrh.Imm.imm16;
+ vassert(n >= 0 && n < 32);
+ p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 0);
+ } else {
+ /* shift variable */
+ p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 4);
+ }
+ } else {
+ if (immR) {
+ UInt n = srcR->Mrh.Imm.imm16;
+ vassert((n >= 0 && n < 32) || (n > 31 && n < 64));
+ if (n >= 0 && n < 32) {
+ p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 56);
+ } else {
+ p = mkFormS(p, 0, r_dst, 0, r_srcL, n - 32, 60);
+ }
+ } else {
+ p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 20);
+ }
+ }
+ break;
+
+ case Mshft_SRL:
+ if (sz32) {
+ // SRL, SRLV
+ if (immR) {
+ UInt n = srcR->Mrh.Imm.imm16;
+ vassert(n >= 0 && n < 32);
+ p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 2);
+ } else {
+ /* shift variable */
+ p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 6);
+ }
+ } else {
+ // DSRL, DSRL32, DSRLV
+ if (immR) {
+ UInt n = srcR->Mrh.Imm.imm16;
+ vassert((n >= 0 && n < 32) || (n > 31 && n < 64));
+ if (n >= 0 && n < 32) {
+ p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 58);
+ } else {
+ p = mkFormS(p, 0, r_dst, 0, r_srcL, n - 32, 62);
+ }
+ } else {
+ p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 22);
+ }
+ }
+ break;
+
+ case Mshft_SRA:
+ if (sz32) {
+ // SRA, SRAV
+ if (immR) {
+ UInt n = srcR->Mrh.Imm.imm16;
+ vassert(n >= 0 && n < 32);
+ p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 3);
+ } else {
+ /* shift variable */
+ p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 7);
+ }
+ } else {
+ // DSRA, DSRA32, DSRAV
+ if (immR) {
+ UInt n = srcR->Mrh.Imm.imm16;
+ vassert((n >= 0 && n < 32) || (n > 31 && n < 64));
+ if (n >= 0 && n < 32) {
+ p = mkFormS(p, 0, r_dst, 0, r_srcL, n, 59);
+ } else {
+ p = mkFormS(p, 0, r_dst, 0, r_srcL, n - 32, 63);
+ }
+ } else {
+ p = mkFormS(p, 0, r_dst, r_srcR, r_srcL, 0, 23);
+ }
+ }
+ break;
+
+ default:
+ goto bad;
+ }
+
+ goto done;
+ }
+
+ case Min_Unary: {
+ UInt r_dst = iregNo(i->Min.Unary.dst, mode64);
+ UInt r_src = iregNo(i->Min.Unary.src, mode64);
+
+ switch (i->Min.Unary.op) {
+ /*Mun_CLO, Mun_CLZ, Mun_NOP */
+ case Mun_CLO: //clo
+ p = mkFormR(p, 28, r_src, 0 /*whatever */ , r_dst, 0, 33);
+ break;
+ case Mun_CLZ: //clz
+ p = mkFormR(p, 28, r_src, 0 /*whatever */ , r_dst, 0, 32);
+ break;
+ case Mun_NOP: //nop (sll r0,r0,0)
+ p = mkFormR(p, 0, 0, 0, 0, 0, 0);
+ break;
+ }
+ goto done;
+ }
+
+ case Min_Cmp: {
+ UInt r_srcL = iregNo(i->Min.Cmp.srcL, mode64);
+ UInt r_srcR = iregNo(i->Min.Cmp.srcR, mode64);
+ UInt r_dst = iregNo(i->Min.Cmp.dst, mode64);
+
+ switch (i->Min.Cmp.cond) {
+ case MIPScc_EQ:
+ /* addiu r_dst, r0, 1
+ beq r_srcL, r_srcR, 2
+ nop
+ addiu r_dst, r0, 0
+ */
+ p = mkFormI(p, 9, 0, r_dst, 1);
+ p = mkFormI(p, 4, r_srcL, r_srcR, 2);
+ p = mkFormR(p, 0, 0, 0, 0, 0, 0);
+ p = mkFormI(p, 9, 0, r_dst, 0);
+ break;
+ case MIPScc_NE:
+ /* addiu r_dst, r0, 1
+ bne r_srcL, r_srcR, 2
+ nop
+ addiu r_dst, r0, 0
+ */
+ p = mkFormI(p, 9, 0, r_dst, 1);
+ p = mkFormI(p, 5, r_srcL, r_srcR, 2);
+ p = mkFormR(p, 0, 0, 0, 0, 0, 0);
+ p = mkFormI(p, 9, 0, r_dst, 0);
+ break;
+ case MIPScc_LT:
+ /* slt r_dst, r_srcL, r_srcR */
+ p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 42);
+ break;
+ case MIPScc_LO:
+ /* sltu r_dst, r_srcL, r_srcR */
+ p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 43);
+ break;
+ case MIPScc_LE:
+ /* addiu r_dst, r0, 1
+ beq r_srcL, r_srcR, 2
+ nop
+ slt r_dst, r_srcL, r_srcR */
+ p = mkFormI(p, 9, 0, r_dst, 1);
+ p = mkFormI(p, 4, r_srcL, r_srcR, 2);
+ p = mkFormR(p, 0, 0, 0, 0, 0, 0);
+ p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 42);
+ break;
+ case MIPScc_LS:
+ /* addiu r_dst, r0, 1
+ beq r_srcL, r_srcR, 2
+ nop
+ sltu r_dst, r_srcL, r_srcR */
+ p = mkFormI(p, 9, 0, r_dst, 1);
+ p = mkFormI(p, 4, r_srcL, r_srcR, 2);
+ p = mkFormR(p, 0, 0, 0, 0, 0, 0);
+ p = mkFormR(p, 0, r_srcL, r_srcR, r_dst, 0, 43);
+ break;
+ default:
+ goto bad;
+ }
+ goto done;
+ }
+
+ case Min_Mul: {
+ Bool syned = i->Min.Mul.syned;
+ Bool widening = i->Min.Mul.widening;
+ Bool sz32 = i->Min.Mul.sz32;
+ UInt r_srcL = iregNo(i->Min.Mul.srcL, mode64);
+ UInt r_srcR = iregNo(i->Min.Mul.srcR, mode64);
+ UInt r_dst = iregNo(i->Min.Mul.dst, mode64);
+
+ if (widening) {
+ if (sz32) {
+ if (syned)
+ /* mult */
+ p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 24);
+ else
+ /* multu */
+ p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 25);
+ } else {
+ if (syned) /* DMULT r_dst,r_srcL,r_srcR */
+ p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 28);
+ else /* DMULTU r_dst,r_srcL,r_srcR */
+ p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 29);
+ }
+ } else {
+ if (sz32)
+ /* mul */
+ p = mkFormR(p, 28, r_srcL, r_srcR, r_dst, 0, 2);
+ else if (mode64 && !sz32)
+ p = mkFormR(p, 28, r_srcL, r_srcR, r_dst, 0, 2);
+ else
+ goto bad;
+ }
+ goto done;
+ }
+
+ case Min_Macc: {
+ Bool syned = i->Min.Macc.syned;
+ UInt r_srcL = iregNo(i->Min.Macc.srcL, mode64);
+ UInt r_srcR = iregNo(i->Min.Macc.srcR, mode64);
+
+ if (syned) {
+ switch (i->Min.Macc.op) {
+ case Macc_ADD:
+ //madd
+ p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0, 0);
+ break;
+ case Macc_SUB:
+ //msub
+ p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0,
+ 4);
+ break;
+ default:
+ goto bad;
+ }
+ } else {
+ switch (i->Min.Macc.op) {
+ case Macc_ADD:
+ //maddu
+ p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0,
+ 1);
+ break;
+ case Macc_SUB:
+ //msubu
+ p = mkFormR(p, 28, r_srcL, r_srcR, 0, 0,
+ 5);
+ break;
+ default:
+ goto bad;
+ }
+ }
+
+ goto done;
+ }
+
+ case Min_Div: {
+ Bool syned = i->Min.Div.syned;
+ Bool sz32 = i->Min.Div.sz32;
+ UInt r_srcL = iregNo(i->Min.Div.srcL, mode64);
+ UInt r_srcR = iregNo(i->Min.Div.srcR, mode64);
+ if (sz32) {
+ if (syned) {
+ /* div */
+ p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 26);
+ } else
+ /* divu */
+ p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 27);
+ goto done;
+ } else {
+ if (syned) {
+ /* ddiv */
+ p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 30);
+ } else
+ /* ddivu */
+ p = mkFormR(p, 0, r_srcL, r_srcR, 0, 0, 31);
+ goto done;
+ }
+ }
+
+ case Min_Mthi: {
+ UInt r_src = iregNo(i->Min.MtHL.src, mode64);
+ p = mkFormR(p, 0, r_src, 0, 0, 0, 17);
+ goto done;
+ }
+
+ case Min_Mtlo: {
+ UInt r_src = iregNo(i->Min.MtHL.src, mode64);
+ p = mkFormR(p, 0, r_src, 0, 0, 0, 19);
+ goto done;
+ }
+
+ case Min_Mfhi: {
+ UInt r_dst = iregNo(i->Min.MfHL.dst, mode64);
+ p = mkFormR(p, 0, 0, 0, r_dst, 0, 16);
+ goto done;
+ }
+
+ case Min_Mflo: {
+ UInt r_dst = iregNo(i->Min.MfHL.dst, mode64);
+ p = mkFormR(p, 0, 0, 0, r_dst, 0, 18);
+ goto done;
+ }
+
+ case Min_MtFCSR: {
+ UInt r_src = iregNo(i->Min.MtFCSR.src, mode64);
+ /* ctc1 */
+ p = mkFormR(p, 17, 6, r_src, 31, 0, 0);
+ goto done;
+ }
+
+ case Min_MfFCSR: {
+ UInt r_dst = iregNo(i->Min.MfFCSR.dst, mode64);
+ /* cfc1 */
+ p = mkFormR(p, 17, 2, r_dst, 31, 0, 0);
+ goto done;
+ }
+
+ case Min_Call: {
+ MIPSCondCode cond = i->Min.Call.cond;
+ UInt r_dst = 25; /* using %r25 as address temporary -
+ see getRegUsage_MIPSInstr */
+
+ /* jump over the following insns if condition does not hold */
+ if (cond != MIPScc_AL) {
+ /* jmp fwds if !condition */
+ /* don't know how many bytes to jump over yet...
+ make space for a jump instruction + nop!!! and fill in later. */
+ ptmp = p; /* fill in this bit later */
+ p += 8; // p += 8
+ }
+
+ /* load target to r_dst */// p += 4|8
+ p = mkLoadImm(p, r_dst, i->Min.Call.target, mode64);
+
+ /* jalr %r_dst */
+ p = mkFormR(p, 0, r_dst, 0, 31, 0, 9); // p += 4
+ p = mkFormR(p, 0, 0, 0, 0, 0, 0); // p += 4
+
+ /* Fix up the conditional jump, if there was one. */
+ if (cond != MIPScc_AL) {
+ UInt r_src = iregNo(i->Min.Call.src, mode64);
+ Int delta = p - ptmp;
+
+ vassert(delta >= 20 && delta <= 32);
+ /* bc !ct,cf,delta/4 */
+ /* blez r_src, delta/4-1 */
+ vassert(cond == MIPScc_EQ);
+ ptmp = mkFormI(ptmp, 6, r_src, 0, delta / 4 - 1);
+ ptmp = mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
+ }
+ goto done;
+ }
+
+ case Min_XDirect: {
+ /* NB: what goes on here has to be very closely coordinated
+ with the chainXDirect_MIPS and unchainXDirect_MIPS below. */
+ /* We're generating chain-me requests here, so we need to be
+ sure this is actually allowed -- no-redir translations
+ can't use chain-me's. Hence: */
+ vassert(disp_cp_chain_me_to_slowEP != NULL);
+ vassert(disp_cp_chain_me_to_fastEP != NULL);
+
+ /* Use ptmp for backpatching conditional jumps. */
+ ptmp = NULL;
+
+ /* First off, if this is conditional, create a conditional
+ jump over the rest of it. Or at least, leave a space for
+ it that we will shortly fill in. */
+ if (i->Min.XDirect.cond != MIPScc_AL) {
+ vassert(i->Min.XDirect.cond != MIPScc_NV);
+ ptmp = p;
+ p += 12;
+ }
+
+ /* Update the guest PC. */
+ /* move r9, dstGA */
+ /* sw r9, amPC */
+ p = mkLoadImm_EXACTLY2or5(p, /*r*/9,
+ (ULong)i->Min.XDirect.dstGA, mode64);
+ p = do_load_or_store_machine_word(p, False/*!isLoad*/,
+ /*r*/9, i->Min.XDirect.amPC, mode64);
+
+ /* --- FIRST PATCHABLE BYTE follows --- */
+ /* VG_(disp_cp_chain_me_to_{slowEP,fastEP}) (where we're
+ calling to) backs up the return address, so as to find the
+ address of the first patchable byte. So: don't change the
+ number of instructions (3) below. */
+ /* move r9, VG_(disp_cp_chain_me_to_{slowEP,fastEP}) */
+ /* jr r9 */
+ void* disp_cp_chain_me
+ = i->Min.XDirect.toFastEP ? disp_cp_chain_me_to_fastEP
+ : disp_cp_chain_me_to_slowEP;
+ p = mkLoadImm_EXACTLY2or5(p, /*r*/9,
+ Ptr_to_ULong(disp_cp_chain_me), mode64);
+ /* jalr $9 */
+ /* nop */
+ p = mkFormR(p, 0, 9, 0, 31, 0, 9); // p += 4
+ p = mkFormR(p, 0, 0, 0, 0, 0, 0); // p += 4
+ /* --- END of PATCHABLE BYTES --- */
+
+ /* Fix up the conditional jump, if there was one. */
+ if (i->Min.XDirect.cond != MIPScc_AL) {
+ Int delta = p - ptmp;
+ delta = delta / 4 - 3;
+ vassert(delta > 0 && delta < 40);
+ /* lw $9, 316($10) // guest_COND
+ beq $9, $0, 2
+ nop*/
+ ptmp = mkFormI(ptmp, 35, 10, 9, 316);
+ ptmp = mkFormI(ptmp, 4, 0, 9, (delta));
+ ptmp = mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
+ }
+ goto done;
+ }
+
+ case Min_XIndir: {
+ /* We're generating transfers that could lead indirectly to a
+ chain-me, so we need to be sure this is actually allowed --
+ no-redir translations are not allowed to reach normal
+ translations without going through the scheduler. That means
+ no XDirects or XIndirs out from no-redir translations.
+ Hence: */
+ vassert(disp_cp_xindir != NULL);
+
+ /* Use ptmp for backpatching conditional jumps. */
+ ptmp = NULL;
+
+ /* First off, if this is conditional, create a conditional
+ jump over the rest of it. */
+ if (i->Min.XIndir.cond != MIPScc_AL) {
+ vassert(i->Min.XIndir.cond != MIPScc_NV);
+ ptmp = p;
+ p += 12;
+ }
+
+ /* Update the guest PC. */
+ /* sw r-dstGA, amPC */
+ p = do_load_or_store_machine_word(p, False/*!isLoad*/,
+ iregNo(i->Min.XIndir.dstGA, mode64),
+ i->Min.XIndir.amPC, mode64);
+
+ /* move r9, VG_(disp_cp_xindir) */
+ /* jalr r9 */
+ /* nop */
+ p = mkLoadImm_EXACTLY2or5 ( p, /*r*/9,
+ Ptr_to_ULong(disp_cp_xindir), mode64);
+ p = mkFormR(p, 0, 9, 0, 31, 0, 9); // p += 4
+ p = mkFormR(p, 0, 0, 0, 0, 0, 0); // p += 4
+
+ /* Fix up the conditional jump, if there was one. */
+ if (i->Min.XIndir.cond != MIPScc_AL) {
+ Int delta = p - ptmp;
+ delta = delta / 4 - 3;
+ vassert(delta > 0 && delta < 40);
+ /* lw $9, 316($10) // guest_COND
+ beq $9, $0, 2
+ nop*/
+ ptmp = mkFormI(ptmp, 35, 10, 9, 316);
+ ptmp = mkFormI(ptmp, 4, 0, 9, (delta));
+ ptmp = mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
+ }
+ goto done;
+ }
+
+ case Min_XAssisted: {
+ /* First off, if this is conditional, create a conditional jump
+ over the rest of it. Or at least, leave a space for it that
+ we will shortly fill in. */
+ ptmp = NULL;
+ if (i->Min.XAssisted.cond != MIPScc_AL) {
+ vassert(i->Min.XAssisted.cond != MIPScc_NV);
+ ptmp = p;
+ p += 12;
+ }
+
+ /* Update the guest PC. */
+ /* sw r-dstGA, amPC */
+ p = do_load_or_store_machine_word(p, False/*!isLoad*/,
+ iregNo(i->Min.XIndir.dstGA, mode64),
+ i->Min.XIndir.amPC, mode64);
+
+ /* imm32/64 r31, $magic_number */
+ UInt trcval = 0;
+ switch (i->Min.XAssisted.jk) {
+ case Ijk_ClientReq: trcval = VEX_TRC_JMP_CLIENTREQ; break;
+ case Ijk_Sys_syscall: trcval = VEX_TRC_JMP_SYS_SYSCALL; break;
+ //case Ijk_Sys_int128: trcval = VEX_TRC_JMP_SYS_INT128; break;
+ //case Ijk_Yield: trcval = VEX_TRC_JMP_YIELD; break;
+ case Ijk_EmWarn: trcval = VEX_TRC_JMP_EMWARN; break;
+ case Ijk_EmFail: trcval = VEX_TRC_JMP_EMFAIL; break;
+ //case Ijk_MapFail: trcval = VEX_TRC_JMP_MAPFAIL; break;
+ case Ijk_NoDecode: trcval = VEX_TRC_JMP_NODECODE; break;
+ case Ijk_TInval: trcval = VEX_TRC_JMP_TINVAL; break;
+ case Ijk_NoRedir: trcval = VEX_TRC_JMP_NOREDIR; break;
+ case Ijk_SigTRAP: trcval = VEX_TRC_JMP_SIGTRAP; break;
+ //case Ijk_SigSEGV: trcval = VEX_TRC_JMP_SIGSEGV; break;
+ case Ijk_SigBUS: trcval = VEX_TRC_JMP_SIGBUS; break;
+ case Ijk_Boring: trcval = VEX_TRC_JMP_BORING; break;
+ /* We don't expect to see the following being assisted. */
+ //case Ijk_Ret:
+ //case Ijk_Call:
+ /* fallthrough */
+ default:
+ ppIRJumpKind(i->Min.XAssisted.jk);
+ vpanic("emit_MIPSInstr.Min_XAssisted: unexpected jump kind");
+ }
+ vassert(trcval != 0);
+ p = mkLoadImm_EXACTLY2or5(p, /*r*/10, trcval, mode64);
+
+ /* move r9, VG_(disp_cp_xassisted) */
+ p = mkLoadImm_EXACTLY2or5(p, /*r*/9,
+ (ULong)Ptr_to_ULong(disp_cp_xassisted), mode64);
+ /* jalr $9
+ nop */
+ p = mkFormR(p, 0, 9, 0, 31, 0, 9); // p += 4
+ p = mkFormR(p, 0, 0, 0, 0, 0, 0); // p += 4
+
+ /* Fix up the conditional jump, if there was one. */
+ if (i->Min.XAssisted.cond != MIPScc_AL) {
+ Int delta = p - ptmp;
+ delta = delta / 4 - 3;
+ vassert(delta > 0 && delta < 40);
+ /* lw $9, 316($10) // guest_COND
+ beq $9, $0, 2
+ nop*/
+ ptmp = mkFormI(ptmp, 35, 10, 9, 316);
+ ptmp = mkFormI(ptmp, 4, 0, 9, (delta));
+ ptmp = mkFormR(ptmp, 0, 0, 0, 0, 0, 0);
+ }
+ goto done;
+ }
+
+ case Min_Load: {
+ MIPSAMode *am_addr = i->Min.Load.src;
+ if (am_addr->tag == Mam_IR) {
+ UInt r_dst = iregNo(i->Min.Load.dst, mode64);
+ UInt opc, sz = i->Min.Load.sz;
+ if (mode64 && (sz == 4 || sz == 8)) {
+ /* should be guaranteed to us by iselWordExpr_AMode */
+ vassert(0 == (am_addr->Mam.IR.index & 3));
+ }
+ switch (sz) {
+ case 1:
+ opc = 32;
+ break;
+ case 2:
+ opc = 33;
+ break;
+ case 4:
+ opc = 35;
+ break;
+ case 8:
+ opc = 55;
+ vassert(mode64);
+ break;
+ break;
+ default:
+ goto bad;
+ }
+
+ p = doAMode_IR(p, opc, r_dst, am_addr, mode64);
+ goto done;
+ } else if (am_addr->tag == Mam_RR) {
+ UInt r_dst = iregNo(i->Min.Load.dst, mode64);
+ UInt opc, sz = i->Min.Load.sz;
+
+ switch (sz) {
+ case 1:
+ opc = 32;
+ break;
+ case 2:
+ opc = 33;
+ break;
+ case 4:
+ opc = 35;
+ break;
+ case 8:
+ opc = 55;
+ vassert(mode64);
+ break;
+ break;
+ default:
+ goto bad;
+ }
+
+ p = doAMode_RR(p, opc, r_dst, am_addr, mode64);
+ goto done;
+ }
+ break;
+ }
+
+ case Min_Store: {
+ MIPSAMode *am_addr = i->Min.Store.dst;
+ if (am_addr->tag == Mam_IR) {
+ UInt r_src = iregNo(i->Min.Store.src, mode64);
+ UInt opc, sz = i->Min.Store.sz;
+ if (mode64 && (sz == 4 || sz == 8)) {
+ /* should be guaranteed to us by iselWordExpr_AMode */
+ vassert(0 == (am_addr->Mam.IR.index & 3));
+ }
+ switch (sz) {
+ case 1:
+ opc = 40;
+ break;
+ case 2:
+ opc = 41;
+ break;
+ case 4:
+ opc = 43;
+ break;
+ case 8:
+ vassert(mode64);
+ opc = 63;
+ break;
+ default:
+ goto bad;
+ }
+
+ p = doAMode_IR(p, opc, r_src, am_addr, mode64);
+ goto done;
+ } else if (am_addr->tag == Mam_RR) {
+ UInt r_src = iregNo(i->Min.Store.src, mode64);
+ UInt opc, sz = i->Min.Store.sz;
+
+ switch (sz) {
+ case 1:
+ opc = 40;
+ break;
+ case 2:
+ opc = 41;
+ break;
+ case 4:
+ opc = 43;
+ break;
+ case 8:
+ vassert(mode64);
+ opc = 63;
+ break;
+ default:
+ goto bad;
+ }
+
+ p = doAMode_RR(p, opc, r_src, am_addr, mode64);
+ goto done;
+ }
+ break;
+ }
+ case Min_LoadL: {
+ MIPSAMode *am_addr = i->Min.LoadL.src;
+ UInt r_src = iregNo(am_addr->Mam.IR.base, mode64);
+ UInt idx = am_addr->Mam.IR.index;
+ UInt r_dst = iregNo(i->Min.LoadL.dst, mode64);
+
+ p = mkFormI(p, 0x30, r_src, r_dst, idx);
+ goto done;
+ }
+ case Min_StoreC: {
+ MIPSAMode *am_addr = i->Min.StoreC.dst;
+ UInt r_src = iregNo(i->Min.StoreC.src, mode64);
+ UInt idx = am_addr->Mam.IR.index;
+ UInt r_dst = iregNo(am_addr->Mam.IR.base, mode64);
+
+ p = mkFormI(p, 0x38, r_dst, r_src, idx);
+ goto done;
+ }
+ case Min_RdWrLR: {
+ UInt reg = iregNo(i->Min.RdWrLR.gpr, mode64);
+ Bool wrLR = i->Min.RdWrLR.wrLR;
+ if (wrLR)
+ p = mkMoveReg(p, 31, reg);
+ else
+ p = mkMoveReg(p, reg, 31);
+ goto done;
+ }
+
+ // Floating point
+
+ case Min_FpLdSt: {
+ MIPSAMode *am_addr = i->Min.FpLdSt.addr;
+ UChar sz = i->Min.FpLdSt.sz;
+ vassert(sz == 4 || sz == 8);
+ if (sz == 4) {
+ UInt f_reg = fregNo(i->Min.FpLdSt.reg, mode64);
+ if (i->Min.FpLdSt.isLoad) {
+ if (am_addr->tag == Mam_IR)
+ p = doAMode_IR(p, 0x31, f_reg, am_addr, mode64);
+ else if (am_addr->tag == Mam_RR)
+ p = doAMode_RR(p, 0x31, f_reg, am_addr, mode64);
+ } else {
+ if (am_addr->tag == Mam_IR)
+ p = doAMode_IR(p, 0x39, f_reg, am_addr, mode64);
+ else if (am_addr->tag == Mam_RR)
+ p = doAMode_RR(p, 0x39, f_reg, am_addr, mode64);
+ }
+ } else if (sz == 8) {
+ UInt f_reg = dregNo(i->Min.FpLdSt.reg);
+ if (i->Min.FpLdSt.isLoad) {
+ if (am_addr->tag == Mam_IR) {
+ if (mode64) {
+ p = doAMode_IR(p, 0x35, f_reg, am_addr, mode64);
+ } else {
+ p = doAMode_IR(p, 0x31, f_reg, am_addr, mode64);
+ p = doAMode_IR(p, 0x31, f_reg + 1,
+ nextMIPSAModeFloat(am_addr), mode64);
+ }
+ } else if (am_addr->tag == Mam_RR) {
+ if (mode64) {
+ p = doAMode_RR(p, 0x35, f_reg, am_addr, mode64);
+ } else {
+ p = doAMode_RR(p, 0x31, f_reg, am_addr, mode64);
+ p = doAMode_RR(p, 0x31, f_reg + 1,
+ nextMIPSAModeFloat(am_addr), mode64);
+ }
+ }
+ } else {
+ if (am_addr->tag == Mam_IR) {
+ if (mode64) {
+ p = doAMode_IR(p, 0x3d, f_reg, am_addr, mode64);
+ } else {
+ p = doAMode_IR(p, 0x39, f_reg, am_addr, mode64);
+ p = doAMode_IR(p, 0x39, f_reg + 1,
+ nextMIPSAModeFloat(am_addr), mode64);
+ }
+ } else if (am_addr->tag == Mam_RR) {
+ if (mode64) {
+ p = doAMode_RR(p, 0x3d, f_reg, am_addr, mode64);
+ } else {
+ p = doAMode_RR(p, 0x39, f_reg, am_addr, mode64);
+ p = doAMode_RR(p, 0x39, f_reg + 1,
+ nextMIPSAModeFloat(am_addr), mode64);
+ }
+ }
+ }
+ }
+ goto done;
+ }
+
+ case Min_FpUnary: {
+ switch (i->Min.FpUnary.op) {
+ case Mfp_MOVS: { // FP move
+ UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
+ UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
+ p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x6);
+ break;
+ }
+ case Mfp_MOVD: { // FP move
+ UInt fr_dst = dregNo(i->Min.FpUnary.dst);
+ UInt fr_src = dregNo(i->Min.FpUnary.src);
+ p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x6);
+ break;
+ }
+ case Mfp_ABSS: { // ABSS
+ UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
+ UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
+ p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x5);
+ break;
+ }
+ case Mfp_ABSD: { // ABSD
+ UInt fr_dst = dregNo(i->Min.FpUnary.dst);
+ UInt fr_src = dregNo(i->Min.FpUnary.src);
+ p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x5);
+ break;
+ }
+ case Mfp_NEGS: { // ABSS
+ UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
+ UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
+ p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x7);
+ break;
+ }
+ case Mfp_NEGD: { // ABSD
+ UInt fr_dst = dregNo(i->Min.FpUnary.dst);
+ UInt fr_src = dregNo(i->Min.FpUnary.src);
+ p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x7);
+ break;
+ }
+ case Mfp_CVTD: { //CVT.D
+ UInt fr_dst = dregNo(i->Min.FpUnary.dst);
+ UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
+ p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x21);
+ break;
+ }
+ case Mfp_SQRTS: { //SQRT.S
+ UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
+ UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
+ p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x04);
+ break;
+ }
+ case Mfp_SQRTD: { //SQRT.D
+ UInt fr_dst = dregNo(i->Min.FpUnary.dst);
+ UInt fr_src = dregNo(i->Min.FpUnary.src);
+ p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x04);
+ break;
+ }
+ case Mfp_RSQRTS: { //RSQRT.S
+ UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
+ UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
+ p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x16);
+ break;
+ }
+ case Mfp_RSQRTD: { //RSQRT.D
+ UInt fr_dst = dregNo(i->Min.FpUnary.dst);
+ UInt fr_src = dregNo(i->Min.FpUnary.src);
+ p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x16);
+ break;
+ }
+ case Mfp_RECIPS: { //RECIP.S
+ UInt fr_dst = fregNo(i->Min.FpUnary.dst, mode64);
+ UInt fr_src = fregNo(i->Min.FpUnary.src, mode64);
+ p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x15);
+ break;
+ }
+ case Mfp_RECIPD: { //RECIP.D
+ UInt fr_dst = dregNo(i->Min.FpUnary.dst);
+ UInt fr_src = dregNo(i->Min.FpUnary.src);
+ p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x15);
+ break;
+ }
+ default:
+ goto bad;
+ }
+ goto done;
+ }
+
+ case Min_FpBinary: {
+ switch (i->Min.FpBinary.op) {
+ case Mfp_ADDS: {
+ UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
+ UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
+ UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
+ p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 0);
+ break;
+ }
+ case Mfp_SUBS: {
+ UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
+ UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
+ UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
+ p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 1);
+ break;
+ }
+ case Mfp_MULS: {
+ UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
+ UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
+ UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
+ p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 2);
+ break;
+ }
+ case Mfp_DIVS: {
+ UInt fr_dst = fregNo(i->Min.FpBinary.dst, mode64);
+ UInt fr_srcL = fregNo(i->Min.FpBinary.srcL, mode64);
+ UInt fr_srcR = fregNo(i->Min.FpBinary.srcR, mode64);
+ p = mkFormR(p, 0x11, 0x10, fr_srcR, fr_srcL, fr_dst, 3);
+ break;
+ }
+ case Mfp_ADDD: {
+ UInt fr_dst = dregNo(i->Min.FpBinary.dst);
+ UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
+ UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
+ p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 0);
+ break;
+ }
+ case Mfp_SUBD: {
+ UInt fr_dst = dregNo(i->Min.FpBinary.dst);
+ UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
+ UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
+ p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 1);
+ break;
+ }
+ case Mfp_MULD: {
+ UInt fr_dst = dregNo(i->Min.FpBinary.dst);
+ UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
+ UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
+ p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 2);
+ break;
+ }
+ case Mfp_DIVD: {
+ UInt fr_dst = dregNo(i->Min.FpBinary.dst);
+ UInt fr_srcL = dregNo(i->Min.FpBinary.srcL);
+ UInt fr_srcR = dregNo(i->Min.FpBinary.srcR);
+ p = mkFormR(p, 0x11, 0x11, fr_srcR, fr_srcL, fr_dst, 3);
+ break;
+ }
+ default:
+ goto bad;
+ }
+ goto done;
+ }
+
+ case Min_FpConvert: {
+ switch (i->Min.FpConvert.op) {
+ UInt fr_dst, fr_src;
+ case Mfp_CVTSD:
+ fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
+ fr_src = dregNo(i->Min.FpConvert.src);
+ p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x20);
+ break;
+ case Mfp_CVTSW:
+ fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
+ fr_src = fregNo(i->Min.FpConvert.src, mode64);
+ p = mkFormR(p, 0x11, 0x14, 0, fr_src, fr_dst, 0x20);
+ break;
+ case Mfp_CVTWD:
+ fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
+ fr_src = dregNo(i->Min.FpConvert.src);
+ p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x24);
+ break;
+ case Mfp_CVTWS:
+ fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
+ fr_src = fregNo(i->Min.FpConvert.src, mode64);
+ p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x24);
+ break;
+ case Mfp_CVTDW:
+ fr_dst = dregNo(i->Min.FpConvert.dst);
+ fr_src = fregNo(i->Min.FpConvert.src, mode64);
+ p = mkFormR(p, 0x11, 0x14, 0, fr_src, fr_dst, 0x21);
+ break;
+ case Mfp_TRUWS:
+ fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
+ fr_src = fregNo(i->Min.FpConvert.src, mode64);
+ p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0D);
+ break;
+ case Mfp_TRUWD:
+ fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
+ fr_src = dregNo(i->Min.FpConvert.src);
+ p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0D);
+ break;
+ case Mfp_TRULS:
+ fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
+ fr_src = dregNo(i->Min.FpConvert.src);
+ p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x09);
+ break;
+ case Mfp_TRULD:
+ fr_dst = dregNo(i->Min.FpConvert.dst);
+ fr_src = dregNo(i->Min.FpConvert.src);
+ p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x09);
+ break;
+ case Mfp_CEILWS:
+ fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
+ fr_src = fregNo(i->Min.FpConvert.src, mode64);
+ p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0E);
+ break;
+ case Mfp_CEILWD:
+ fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
+ fr_src = dregNo(i->Min.FpConvert.src);
+ p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0E);
+ break;
+ case Mfp_CEILLS:
+ fr_dst = dregNo(i->Min.FpConvert.dst);
+ fr_src = fregNo(i->Min.FpConvert.src, mode64);
+ p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0A);
+ break;
+ case Mfp_CEILLD:
+ fr_dst = dregNo(i->Min.FpConvert.dst);
+ fr_src = dregNo(i->Min.FpConvert.src);
+ p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0A);
+ break;
+ case Mfp_ROUNDWS:
+ fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
+ fr_src = fregNo(i->Min.FpConvert.src, mode64);
+ p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0C);
+ break;
+ case Mfp_ROUNDWD:
+ fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
+ fr_src = dregNo(i->Min.FpConvert.src);
+ p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0C);
+ break;
+ case Mfp_FLOORWS:
+ fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
+ fr_src = fregNo(i->Min.FpConvert.src, mode64);
+ p = mkFormR(p, 0x11, 0x10, 0, fr_src, fr_dst, 0x0F);
+ break;
+ case Mfp_FLOORWD:
+ fr_dst = fregNo(i->Min.FpConvert.dst, mode64);
+ fr_src = dregNo(i->Min.FpConvert.src);
+ p = mkFormR(p, 0x11, 0x11, 0, fr_src, fr_dst, 0x0F);
+ break;
+
+ default:
+ goto bad;
+ }
+ goto done;
+ }
+
+ case Min_FpCompare: {
+ UInt r_dst = iregNo(i->Min.FpCompare.dst, mode64);
+ UInt fr_srcL = dregNo(i->Min.FpCompare.srcL);
+ UInt fr_srcR = dregNo(i->Min.FpCompare.srcR);
+
+ switch (i->Min.FpConvert.op) {
+ case Mfp_CMP:
+ p = mkFormR(p, 0x11, 0x11, fr_srcL, fr_srcR, 0,
+ (i->Min.FpCompare.cond1 + 48));
+ p = mkFormR(p, 0x11, 0x2, r_dst, 31, 0, 0);
+ break;
+ default:
+ goto bad;
+ }
+ goto done;
+ }
+ case Min_EvCheck: {
+ /* This requires a 32-bit dec/test in 32 mode. */
+ /* We generate:
+ lw r9, amCounter
+ addiu r9, r9, -1
+ sw r9, amCounter
+ bgez r9, nofail
+ lw r9, amFailAddr
+ jalr r9
+ nop
+ nofail:
+ */
+ UChar* p0 = p;
+ /* lw r9, amCounter */
+ p = do_load_or_store_machine_word(p, True/*isLoad*/, /*r*/9,
+ i->Min.EvCheck.amCounter, mode64);
+ /* addiu r9,r9,-1 */
+ p = mkFormI(p, 9, 9, 9, 0xFFFF);
+ /* sw r30, amCounter */
+ p = do_load_or_store_machine_word(p, False/*!isLoad*/, /*r*/9,
+ i->Min.EvCheck.amCounter, mode64);
+ /* bgez t9, nofail */
+ p = mkFormI(p, 1, 9, 1, 3);
+ /* lw r9, amFailAddr */
+ p = do_load_or_store_machine_word(p, True/*isLoad*/, /*r*/9,
+ i->Min.EvCheck.amFailAddr, mode64);
+ /* jalr $9 */
+ p = mkFormR(p, 0, 9, 0, 31, 0, 9); // p += 4
+ p = mkFormR(p, 0, 0, 0, 0, 0, 0); // p += 4
+ /* nofail: */
+
+ /* Crosscheck */
+ vassert(evCheckSzB_MIPS() == (UChar*)p - (UChar*)p0);
+ goto done;
+ }
+
+ case Min_ProfInc: {
+ /* Generate a code template to increment a memory location whose
+ address will be known later as an immediate value. This code
+ template will be patched once the memory location is known.
+ For now we do this with address == 0x65556555.
+ 32-bit:
+
+ move r9, 0x65556555
+ lw r8, 0(r9)
+ addiu r8, r8, 1 # add least significant word
+ sw r8, 0(r9)
+ sltiu r1, r8, 1 # set carry-in bit
+ lw r8, 4(r9)
+ addu r8, r8, r1
+ sw r8, 4(r9) */
+
+ if (mode64) {
+ vassert(0);
+ } else {
+ // move r9, 0x65556555
+ p = mkLoadImm_EXACTLY2or5(p, /*r*/9, 0x65556555ULL,
+ False/*!mode64*/);
+ // lw r8, 0(r9)
+ p = mkFormI(p, 35, 9, 8, 0);
+
+ // addiu r8, r8, 1 # add least significant word
+ p = mkFormI(p, 9, 8, 8, 1);
+
+ // sw r8, 0(r9)
+ p = mkFormI(p, 43, 9, 8, 0);
+
+ // sltiu r1, r8, 1 # set carry-in bit
+ p = mkFormI(p, 11, 8, 1, 1);
+
+ // lw r8, 4(r9)
+ p = mkFormI(p, 35, 9, 8, 4);
+
+ // addu r8, r8, r1
+ p = mkFormR(p, 0, 8, 1, 8, 0, 33);
+
+ // sw r8, 4(r9)
+ p = mkFormI(p, 43, 9, 8, 4);
+
+ }
+ /* Tell the caller .. */
+ vassert(!(*is_profInc));
+ *is_profInc = True;
+ goto done;
+ }
+
+ default:
+ goto bad;
+
+ }
+
+ bad:
+ vex_printf("\n=> ");
+ ppMIPSInstr(i, mode64);
+ vpanic("emit_MIPSInstr");
+ /*NOTREACHED*/ done:
+ //vassert(p - &buf[0] <= 32);
+ return p - &buf[0];
+}
+
+/* How big is an event check? See case for Min_EvCheck in
+ emit_MIPSInstr just above. That crosschecks what this returns, so
+ we can tell if we're inconsistent. */
+Int evCheckSzB_MIPS ( void )
+{
+ UInt kInstrSize = 4;
+ return 7*kInstrSize;
+}
+
+/* NB: what goes on here has to be very closely coordinated with the
+ emitInstr case for XDirect, above. */
+VexInvalRange chainXDirect_MIPS ( void* place_to_chain,
+ void* disp_cp_chain_me_EXPECTED,
+ void* place_to_jump_to,
+ Bool mode64 )
+{
+ /* What we're expecting to see is:
+ move r9, disp_cp_chain_me_to_EXPECTED
+ jalr r9
+ nop
+ viz
+ <8 or 20 bytes generated by mkLoadImm_EXACTLY2or5>
+ 0x120F809 // jalr r9
+ 0x00000000 // nop
+ */
+ UChar* p = (UChar*)place_to_chain;
+ vassert(0 == (3 & (HWord)p));
+ vassert(isLoadImm_EXACTLY2or5(p, /*r*/9,
+ (UInt)Ptr_to_ULong(disp_cp_chain_me_EXPECTED),
+ mode64));
+ vassert(fetch32(p + (mode64 ? 20 : 8) + 0) == 0x120F809);
+ vassert(fetch32(p + (mode64 ? 20 : 8) + 4) == 0x00000000);
+ /* And what we want to change it to is either:
+ move r9, place_to_jump_to
+ jalr r9
+ nop
+ viz
+ <8 bytes generated by mkLoadImm_EXACTLY2or5>
+ 0x120F809 // jalr r9
+ 0x00000000 // nop
+
+ The replacement has the same length as the original.
+ */
+
+ p = mkLoadImm_EXACTLY2or5(p, /*r*/9,
+ Ptr_to_ULong(place_to_jump_to), mode64);
+ p = emit32(p, 0x120F809);
+ p = emit32(p, 0x00000000);
+
+ Int len = p - (UChar*)place_to_chain;
+ vassert(len == (mode64 ? 28 : 16)); /* stay sane */
+ VexInvalRange vir = {(HWord)place_to_chain, len};
+ return vir;
+}
+
+/* NB: what goes on here has to be very closely coordinated with the
+ emitInstr case for XDirect, above. */
+VexInvalRange unchainXDirect_MIPS ( void* place_to_unchain,
+ void* place_to_jump_to_EXPECTED,
+ void* disp_cp_chain_me,
+ Bool mode64 )
+{
+ /* What we're expecting to see is:
+ move r9, place_to_jump_to_EXPECTED
+ jalr r9
+ nop
+ viz
+ <8 or 20 bytes generated by mkLoadImm_EXACTLY2or5>
+ 0x120F809 // jalr r9
+ 0x00000000 // nop
+ */
+ UChar* p = (UChar*)place_to_unchain;
+ vassert(0 == (3 & (HWord)p));
+ vassert(isLoadImm_EXACTLY2or5(p, /*r*/9,
+ Ptr_to_ULong(place_to_jump_to_EXPECTED),
+ mode64));
+ vassert(fetch32(p + (mode64 ? 20 : 8) + 0) == 0x120F809);
+ vassert(fetch32(p + (mode64 ? 20 : 8) + 4) == 0x00000000);
+ /* And what we want to change it to is:
+ move r9, disp_cp_chain_me
+ jalr r9
+ nop
+ viz
+ <8 or 20 bytes generated by mkLoadImm_EXACTLY2or5>
+ 0x120F809 // jalr r9
+ 0x00000000 // nop
+ The replacement has the same length as the original.
+ */
+ p = mkLoadImm_EXACTLY2or5(p, /*r*/9,
+ Ptr_to_ULong(disp_cp_chain_me), mode64);
+ p = emit32(p, 0x120F809);
+ p = emit32(p, 0x00000000);
+
+ Int len = p - (UChar*)place_to_unchain;
+ vassert(len == (mode64 ? 28 : 16)); /* stay sane */
+ VexInvalRange vir = {(HWord)place_to_unchain, len};
+ return vir;
+}
+
+/* Patch the counter address into a profile inc point, as previously
+ created by the Min_ProfInc case for emit_MIPSInstr. */
+VexInvalRange patchProfInc_MIPS ( void* place_to_patch,
+ ULong* location_of_counter, Bool mode64 )
+{
+ vassert(sizeof(ULong*) == 4);
+ UChar* p = (UChar*)place_to_patch;
+ vassert(0 == (3 & (HWord)p));
+ vassert(isLoadImm_EXACTLY2or5((UChar *)p, /*r*/9, 0x65556555, mode64));
+
+ vassert(fetch32(p + (mode64 ? 20 : 8) + 0) == 0x8D280000);
+ vassert(fetch32(p + (mode64 ? 20 : 8) + 4) == 0x25080001);
+ vassert(fetch32(p + (mode64 ? 20 : 8) + 8) == 0xAD280000);
+ vassert(fetch32(p + (mode64 ? 20 : 8) + 12) == 0x2d010001);
+ vassert(fetch32(p + (mode64 ? 20 : 8) + 16) == 0x8d280004);
+ vassert(fetch32(p + (mode64 ? 20 : 8) + 20) == 0x01014021);
+ vassert(fetch32(p + (mode64 ? 20 : 8) + 24) == 0xad280004);
+
+ p = mkLoadImm_EXACTLY2or5(p, /*r*/9,
+ Ptr_to_ULong(location_of_counter), mode64);
+
+ VexInvalRange vir = {(HWord)p, 8};
+ return vir;
+}
+
+
+/*---------------------------------------------------------------*/
+/*--- end host_mips_defs.c ---*/
+/*---------------------------------------------------------------*/
diff --git a/priv/host_mips_defs.h b/priv/host_mips_defs.h
new file mode 100644
index 0000000..1431ff5
--- /dev/null
+++ b/priv/host_mips_defs.h
@@ -0,0 +1,753 @@
+
+/*---------------------------------------------------------------*/
+/*--- begin host_mips_defs.h ---*/
+/*---------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2010-2012 RT-RK
+ mips-valgrind@rt-rk.com
+
+ 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.
+*/
+
+#ifndef __VEX_HOST_MIPS_DEFS_H
+#define __VEX_HOST_MIPS_DEFS_H
+
+/* Num registers used for function calls */
+#define MIPS_N_REGPARMS 4
+
+/* --------- Registers. --------- */
+
+/* The usual HReg abstraction.
+ There are 32 general purpose regs.
+*/
+
+extern void ppHRegMIPS(HReg, Bool);
+
+extern HReg hregMIPS_GPR0(Bool mode64); // scratch reg / zero reg
+extern HReg hregMIPS_GPR1(Bool mode64); // reserved for trap handling
+extern HReg hregMIPS_GPR2(Bool mode64); // reserved for trap handling
+extern HReg hregMIPS_GPR3(Bool mode64);
+extern HReg hregMIPS_GPR4(Bool mode64);
+extern HReg hregMIPS_GPR5(Bool mode64);
+extern HReg hregMIPS_GPR6(Bool mode64);
+extern HReg hregMIPS_GPR7(Bool mode64);
+extern HReg hregMIPS_GPR8(Bool mode64);
+extern HReg hregMIPS_GPR9(Bool mode64);
+extern HReg hregMIPS_GPR10(Bool mode64);
+extern HReg hregMIPS_GPR11(Bool mode64);
+extern HReg hregMIPS_GPR12(Bool mode64);
+extern HReg hregMIPS_GPR13(Bool mode64);
+extern HReg hregMIPS_GPR14(Bool mode64);
+extern HReg hregMIPS_GPR15(Bool mode64);
+extern HReg hregMIPS_GPR16(Bool mode64);
+extern HReg hregMIPS_GPR17(Bool mode64);
+extern HReg hregMIPS_GPR18(Bool mode64);
+extern HReg hregMIPS_GPR19(Bool mode64);
+extern HReg hregMIPS_GPR20(Bool mode64);
+extern HReg hregMIPS_GPR21(Bool mode64);
+extern HReg hregMIPS_GPR22(Bool mode64);
+extern HReg hregMIPS_GPR23(Bool mode64); // GuestStatePtr
+extern HReg hregMIPS_GPR24(Bool mode64); // reserved for dispatcher
+extern HReg hregMIPS_GPR25(Bool mode64);
+extern HReg hregMIPS_GPR26(Bool mode64);
+extern HReg hregMIPS_GPR27(Bool mode64);
+extern HReg hregMIPS_GPR28(Bool mode64);
+extern HReg hregMIPS_GPR29(Bool mode64);
+extern HReg hregMIPS_GPR30(Bool mode64);
+extern HReg hregMIPS_GPR31(Bool mode64);
+extern HReg hregMIPS_PC(Bool mode64);
+
+extern HReg hregMIPS_HI(Bool mode64);
+extern HReg hregMIPS_LO(Bool mode64);
+
+extern HReg hregMIPS_F0(Bool mode64);
+extern HReg hregMIPS_F1(Bool mode64);
+extern HReg hregMIPS_F2(Bool mode64);
+extern HReg hregMIPS_F3(Bool mode64);
+extern HReg hregMIPS_F4(Bool mode64);
+extern HReg hregMIPS_F5(Bool mode64);
+extern HReg hregMIPS_F6(Bool mode64);
+extern HReg hregMIPS_F7(Bool mode64);
+extern HReg hregMIPS_F8(Bool mode64);
+extern HReg hregMIPS_F9(Bool mode64);
+extern HReg hregMIPS_F10(Bool mode64);
+extern HReg hregMIPS_F11(Bool mode64);
+extern HReg hregMIPS_F12(Bool mode64);
+extern HReg hregMIPS_F13(Bool mode64);
+extern HReg hregMIPS_F14(Bool mode64);
+extern HReg hregMIPS_F15(Bool mode64);
+extern HReg hregMIPS_F16(Bool mode64);
+extern HReg hregMIPS_F17(Bool mode64);
+extern HReg hregMIPS_F18(Bool mode64);
+extern HReg hregMIPS_F19(Bool mode64);
+extern HReg hregMIPS_F20(Bool mode64);
+extern HReg hregMIPS_F21(Bool mode64);
+extern HReg hregMIPS_F22(Bool mode64);
+extern HReg hregMIPS_F23(Bool mode64);
+extern HReg hregMIPS_F24(Bool mode64);
+extern HReg hregMIPS_F25(Bool mode64);
+extern HReg hregMIPS_F26(Bool mode64);
+extern HReg hregMIPS_F27(Bool mode64);
+extern HReg hregMIPS_F28(Bool mode64);
+extern HReg hregMIPS_F29(Bool mode64);
+extern HReg hregMIPS_F30(Bool mode64);
+extern HReg hregMIPS_F31(Bool mode64);
+extern HReg hregMIPS_FIR(void);
+extern HReg hregMIPS_FCCR(void);
+extern HReg hregMIPS_FEXR(void);
+extern HReg hregMIPS_FENR(void);
+extern HReg hregMIPS_FCSR(void);
+extern HReg hregMIPS_COND(void);
+
+extern HReg hregMIPS_D0(void);
+extern HReg hregMIPS_D1(void);
+extern HReg hregMIPS_D2(void);
+extern HReg hregMIPS_D3(void);
+extern HReg hregMIPS_D4(void);
+extern HReg hregMIPS_D5(void);
+extern HReg hregMIPS_D6(void);
+extern HReg hregMIPS_D7(void);
+extern HReg hregMIPS_D8(void);
+extern HReg hregMIPS_D9(void);
+extern HReg hregMIPS_D10(void);
+extern HReg hregMIPS_D11(void);
+extern HReg hregMIPS_D12(void);
+extern HReg hregMIPS_D13(void);
+extern HReg hregMIPS_D14(void);
+extern HReg hregMIPS_D15(void);
+
+#define GuestStatePointer(_mode64) hregMIPS_GPR10(_mode64)
+
+#define StackFramePointer(_mode64) hregMIPS_GPR30(_mode64)
+#define LinkRegister(_mode64) hregMIPS_GPR31(_mode64)
+#define StackPointer(_mode64) hregMIPS_GPR29(_mode64)
+#define FCSR() hregMIPS_FCSR()
+#define COND() hregMIPS_COND()
+
+#define HIRegister(_mode64) hregMIPS_HI(_mode64)
+#define LORegister(_mode64) hregMIPS_LO(_mode64)
+
+/* a0, a1, a2, a3 */
+#define MIPS_N_ARGREGS 4
+
+/* --------- Condition codes, Intel encoding. --------- */
+typedef enum {
+ MIPScc_EQ = 0, /* equal */
+ MIPScc_NE = 1, /* not equal */
+
+ MIPScc_HS = 2, /* >=u (higher or same) */
+ MIPScc_LO = 3, /* <u (lower) */
+
+ MIPScc_MI = 4, /* minus (negative) */
+ MIPScc_PL = 5, /* plus (zero or +ve) */
+
+ MIPScc_VS = 6, /* overflow */
+ MIPScc_VC = 7, /* no overflow */
+
+ MIPScc_HI = 8, /* >u (higher) */
+ MIPScc_LS = 9, /* <=u (lower or same) */
+
+ MIPScc_GE = 10, /* >=s (signed greater or equal) */
+ MIPScc_LT = 11, /* <s (signed less than) */
+
+ MIPScc_GT = 12, /* >s (signed greater) */
+ MIPScc_LE = 13, /* <=s (signed less or equal) */
+
+ MIPScc_AL = 14, /* always (unconditional) */
+ MIPScc_NV = 15 /* never (unconditional): */
+} MIPSCondCode;
+
+extern HChar *showMIPSCondCode(MIPSCondCode);
+
+/* --------- Memory address expressions (amodes). --------- */
+typedef enum {
+ Mam_IR, /* Immediate (signed 16-bit) + Reg */
+ Mam_RR /* Reg1 + Reg2 */
+} MIPSAModeTag;
+
+typedef struct {
+ MIPSAModeTag tag;
+ union {
+ struct {
+ HReg base;
+ Int index;
+ } IR;
+ struct {
+ HReg base;
+ HReg index;
+ } RR;
+ } Mam;
+} MIPSAMode;
+
+extern MIPSAMode *MIPSAMode_IR(Int, HReg);
+extern MIPSAMode *MIPSAMode_RR(HReg, HReg);
+
+extern MIPSAMode *dopyMIPSAMode(MIPSAMode *);
+extern MIPSAMode *nextMIPSAModeFloat(MIPSAMode *);
+extern MIPSAMode *nextMIPSAModeInt(MIPSAMode *);
+
+extern void ppMIPSAMode(MIPSAMode *, Bool);
+
+/* --------- Operand, which can be a reg or a u16/s16. --------- */
+/* ("RH" == "Register or Halfword immediate") */
+typedef enum {
+ Mrh_Imm,
+ Mrh_Reg
+} MIPSRHTag;
+
+typedef struct {
+ MIPSRHTag tag;
+ union {
+ struct {
+ Bool syned;
+ UShort imm16;
+ } Imm;
+ struct {
+ HReg reg;
+ } Reg;
+ } Mrh;
+} MIPSRH;
+
+extern void ppMIPSRH(MIPSRH *, Bool);
+
+extern MIPSRH *MIPSRH_Imm(Bool, UShort);
+extern MIPSRH *MIPSRH_Reg(HReg);
+
+/* --- Addressing Mode suitable for VFP --- */
+typedef struct {
+ HReg reg;
+ Int simm11;
+} MIPSAModeV;
+
+extern MIPSAModeV *mkMIPSAModeV(HReg reg, Int simm11);
+
+extern void ppMIPSAModeV(MIPSAModeV *);
+
+/* --------- Reg or imm-8x4 operands --------- */
+/* a.k.a (a very restricted form of) Shifter Operand,
+ in the MIPS parlance. */
+
+typedef enum {
+ MIPSri84_I84 = 5, /* imm8 `ror` (2 * imm4) */
+ MIPSri84_R /* reg */
+} MIPSRI84Tag;
+
+typedef struct {
+ MIPSRI84Tag tag;
+ union {
+ struct {
+ UShort imm8;
+ UShort imm4;
+ } I84;
+ struct {
+ HReg reg;
+ } R;
+ } MIPSri84;
+} MIPSRI84;
+
+extern MIPSRI84 *MIPSRI84_I84(UShort imm8, UShort imm4);
+extern MIPSRI84 *MIPSRI84_R(HReg);
+
+extern void ppMIPSRI84(MIPSRI84 *);
+
+/* --------- Reg or imm5 operands --------- */
+typedef enum {
+ MIPSri5_I5 = 7, /* imm5, 1 .. 31 only (no zero!) */
+ MIPSri5_R /* reg */
+} MIPSRI5Tag;
+
+typedef struct {
+ MIPSRI5Tag tag;
+ union {
+ struct {
+ UInt imm5;
+ } I5;
+ struct {
+ HReg reg;
+ } R;
+ } MIPSri5;
+} MIPSRI5;
+
+extern MIPSRI5 *MIPSRI5_I5(UInt imm5);
+extern MIPSRI5 *MIPSRI5_R(HReg);
+
+extern void ppMIPSRI5(MIPSRI5 *);
+
+/* --------- Instructions. --------- */
+
+/*Tags for operations*/
+
+/* --------- */
+typedef enum {
+ Mun_CLO,
+ Mun_CLZ,
+ Mun_NOP,
+} MIPSUnaryOp;
+
+extern HChar *showMIPSUnaryOp(MIPSUnaryOp);
+/* --------- */
+
+/* --------- */
+
+typedef enum {
+ Malu_INVALID,
+ Malu_ADD, Malu_SUB,
+ Malu_AND, Malu_OR, Malu_NOR, Malu_XOR,
+} MIPSAluOp;
+
+extern HChar *showMIPSAluOp(MIPSAluOp,
+ Bool /* is the 2nd operand an immediate? */ );
+
+/* --------- */
+typedef enum {
+ Mshft_INVALID,
+ Mshft_SLL, Mshft_SRL,
+ Mshft_SRA
+} MIPSShftOp;
+
+extern HChar *showMIPSShftOp(MIPSShftOp,
+ Bool /* is the 2nd operand an immediate? */ ,
+ Bool /* is this a 32bit or 64bit op? */ );
+
+/* --------- */
+typedef enum {
+ Macc_ADD,
+ Macc_SUB
+} MIPSMaccOp;
+
+extern HChar *showMIPSMaccOp(MIPSMaccOp, Bool);
+/* --------- */
+
+/* ----- Instruction tags ----- */
+typedef enum {
+ Min_LI, /* load word (32/64-bit) immediate (fake insn) */
+ Min_Alu, /* word add/sub/and/or/xor/nor/others? */
+ Min_Shft, /* word sll/srl/sra */
+ Min_Unary, /* clo, clz, nop, neg */
+
+ Min_Cmp, /* word compare (fake insn) */
+
+ Min_Mul, /* widening/non-widening multiply */
+ Min_Div, /* div */
+
+ Min_Call, /* call to address in register */
+
+ /* The following 5 insns are mandated by translation chaining */
+ Min_XDirect, /* direct transfer to GA */
+ Min_XIndir, /* indirect transfer to GA */
+ Min_XAssisted, /* assisted transfer to GA */
+ Min_EvCheck, /* Event check */
+ Min_ProfInc, /* 64-bit profile counter increment */
+
+ Min_RdWrLR, /* Read/Write Link Register */
+ Min_Mthi, /* Move to HI from GP register */
+ Min_Mtlo, /* Move to LO from GP register */
+ Min_Mfhi, /* Move from HI to GP register */
+ Min_Mflo, /* Move from LO to GP register */
+ Min_Macc, /* Multiply and accumulate */
+
+ Min_Load, /* zero-extending load a 8|16|32 bit value from mem */
+ Min_Store, /* store a 8|16|32 bit value to mem */
+ Min_LoadL, /* mips Load Linked Word */
+ Min_StoreC, /* mips Store Conditional Word */
+
+ Min_FpUnary, /* FP unary op */
+ Min_FpBinary, /* FP binary op */
+ Min_FpConvert, /* FP conversion op */
+ Min_FpMulAcc, /* FP multipy-accumulate style op */
+ Min_FpLdSt, /* FP load/store */
+ Min_FpSTFIW, /* stfiwx */
+ Min_FpRSP, /* FP round IEEE754 double to IEEE754 single */
+ Min_FpCftI, /* fcfid/fctid/fctiw */
+ Min_FpCMov, /* FP floating point conditional move */
+ Min_MtFCSR, /* set FCSR register */
+ Min_MfFCSR, /* get FCSR register */
+ Min_FpCompare, /* FP compare, generating value into int reg */
+ Min_MovCond
+} MIPSInstrTag;
+
+/* --------- */
+typedef enum {
+ Mfp_INVALID,
+
+ /* Ternary */
+ Mfp_MADDD, Mfp_MSUBD,
+ Mfp_MADDS, Mfp_MSUBS,
+
+ /* Binary */
+ Mfp_ADDD, Mfp_SUBD, Mfp_MULD, Mfp_DIVD,
+ Mfp_ADDS, Mfp_SUBS, Mfp_MULS, Mfp_DIVS, Mfp_CVTSD, Mfp_CVTSW, Mfp_CVTWD,
+ Mfp_CVTWS, Mfp_TRULS, Mfp_TRULD, Mfp_TRUWS, Mfp_TRUWD, Mfp_FLOORWS,
+ Mfp_FLOORWD, Mfp_ROUNDWS, Mfp_ROUNDWD, Mfp_CVTDW, Mfp_CMP,
+ Mfp_CEILWS, Mfp_CEILWD, Mfp_CEILLS, Mfp_CEILLD,
+
+ /* Unary */
+ Mfp_SQRTS, Mfp_SQRTD, Mfp_RSQRTS, Mfp_RSQRTD, Mfp_RECIPS, Mfp_RECIPD,
+ Mfp_ABSS, Mfp_ABSD, Mfp_NEGS, Mfp_NEGD, Mfp_MOVS, Mfp_MOVD,
+ Mfp_RES, Mfp_RSQRTE, Mfp_FRIN, Mfp_FRIM, Mfp_FRIP, Mfp_FRIZ, Mfp_CVTD
+} MIPSFpOp;
+
+extern HChar *showMIPSFpOp(MIPSFpOp);
+
+/*--------- Structure for instructions ----------*/
+/* Destinations are on the LEFT (first operand) */
+
+typedef struct {
+ MIPSInstrTag tag;
+ union {
+ /* Get a 32/64-bit literal into a register.
+ May turn into a number of real insns. */
+ struct {
+ HReg dst;
+ ULong imm;
+ } LI;
+ /* Integer add/sub/and/or/xor. Limitations:
+ - For add, the immediate, if it exists, is a signed 16.
+ - For sub, the immediate, if it exists, is a signed 16
+ which may not be -32768, since no such instruction
+ exists, and so we have to emit addi with +32768, but
+ that is not possible.
+ - For and/or/xor, the immediate, if it exists,
+ is an unsigned 16.
+ */
+ struct {
+ MIPSAluOp op;
+ HReg dst;
+ HReg srcL;
+ MIPSRH *srcR;
+ } Alu;
+ /* Integer shl/shr/sar.
+ Limitations: the immediate, if it exists,
+ is a signed 5-bit value between 1 and 31 inclusive.
+ */
+ struct {
+ MIPSShftOp op;
+ Bool sz32; /* mode64 has both 32 and 64bit shft */
+ HReg dst;
+ HReg srcL;
+ MIPSRH *srcR;
+ } Shft;
+ /* Clz, Clo, nop */
+ struct {
+ MIPSUnaryOp op;
+ HReg dst;
+ HReg src;
+ } Unary;
+ /* Word compare. Fake instruction, used for basic block ending */
+ struct {
+ Bool syned;
+ Bool sz32;
+ HReg dst;
+ HReg srcL;
+ HReg srcR;
+
+ MIPSCondCode cond;
+ } Cmp;
+ struct {
+ Bool widening; //True => widening, False => non-widening
+ Bool syned; //signed/unsigned - meaningless if widenind = False
+ Bool sz32;
+ HReg dst;
+ HReg srcL;
+ HReg srcR;
+ } Mul;
+ struct {
+ Bool syned; //signed/unsigned - meaningless if widenind = False
+ Bool sz32;
+ HReg srcL;
+ HReg srcR;
+ } Div;
+ /* Pseudo-insn. Call target (an absolute address), on given
+ condition (which could be Mcc_ALWAYS). argiregs indicates
+ which of r3 .. r10
+ carries argument values for this call,
+ using a bit mask (1<<N is set if rN holds an arg, for N in
+ 3 .. 10 inclusive).
+ If cond is != Mcc_ALWAYS, src is checked.
+ Otherwise, unconditional call */
+ struct {
+ MIPSCondCode cond;
+ Addr32 target;
+ UInt argiregs;
+ HReg src;
+ } Call;
+ /* Update the guest EIP value, then exit requesting to chain
+ to it. May be conditional. Urr, use of Addr32 implicitly
+ assumes that wordsize(guest) == wordsize(host). */
+ struct {
+ Addr32 dstGA; /* next guest address */
+ MIPSAMode* amPC; /* amode in guest state for PC */
+ MIPSCondCode cond; /* can be MIPScc_AL */
+ Bool toFastEP; /* chain to the slow or fast point? */
+ } XDirect;
+ /* Boring transfer to a guest address not known at JIT time.
+ Not chainable. May be conditional. */
+ struct {
+ HReg dstGA;
+ MIPSAMode* amPC;
+ MIPSCondCode cond; /* can be MIPScc_AL */
+ } XIndir;
+ /* Assisted transfer to a guest address, most general case.
+ Not chainable. May be conditional. */
+ struct {
+ HReg dstGA;
+ MIPSAMode* amPC;
+ MIPSCondCode cond; /* can be MIPScc_AL */
+ IRJumpKind jk;
+ } XAssisted;
+ /* Zero extending loads. Dst size is host word size */
+ struct {
+ UChar sz; /* 1|2|4|8 */
+ HReg dst;
+ MIPSAMode *src;
+ } Load;
+ /* 64/32/16/8 bit stores */
+ struct {
+ UChar sz; /* 1|2|4|8 */
+ MIPSAMode *dst;
+ HReg src;
+ } Store;
+ struct {
+ UChar sz; /* 4|8 */
+ HReg dst;
+ MIPSAMode *src;
+ } LoadL;
+ struct {
+ UChar sz; /* 4|8 */
+ MIPSAMode *dst;
+ HReg src;
+ } StoreC;
+ /* Move from HI/LO register to GP register. */
+ struct {
+ HReg dst;
+ } MfHL;
+
+ /* Move to HI/LO register from GP register. */
+ struct {
+ HReg src;
+ } MtHL;
+
+ /* Read/Write Link Register */
+ struct {
+ Bool wrLR;
+ HReg gpr;
+ } RdWrLR;
+
+ /* MIPS Multiply and accumulate instructions. */
+ struct {
+ MIPSMaccOp op;
+ Bool syned;
+
+ HReg srcL;
+ HReg srcR;
+ } Macc;
+
+ /* MIPS Floating point */
+ struct {
+ MIPSFpOp op;
+ HReg dst;
+ HReg src;
+ } FpUnary;
+ struct {
+ MIPSFpOp op;
+ HReg dst;
+ HReg srcL;
+ HReg srcR;
+ } FpBinary;
+ struct {
+ MIPSFpOp op;
+ HReg dst;
+ HReg srcML;
+ HReg srcMR;
+ HReg srcAcc;
+ } FpMulAcc;
+ struct {
+ Bool isLoad;
+ UChar sz; /* only 4 (IEEE single) or 8 (IEEE double) */
+ HReg reg;
+ MIPSAMode *addr;
+ } FpLdSt;
+
+ struct {
+ MIPSFpOp op;
+ HReg dst;
+ HReg src;
+ } FpConvert;
+ struct {
+ MIPSFpOp op;
+ HReg dst;
+ HReg srcL;
+ HReg srcR;
+ UChar cond1;
+ } FpCompare;
+ struct {
+ MIPSFpOp op;
+ HReg dst;
+ HReg srcL;
+ MIPSRH *srcR;
+ HReg condR;
+ MIPSCondCode cond;
+ } MovCond;
+ /* Move from GP register to FCSR register. */
+ struct {
+ HReg src;
+ } MtFCSR;
+ /* Move from FCSR register to GP register. */
+ struct {
+ HReg dst;
+ } MfFCSR;
+ struct {
+ MIPSAMode* amCounter;
+ MIPSAMode* amFailAddr;
+ } EvCheck;
+ struct {
+ /* No fields. The address of the counter to inc is
+ installed later, post-translation, by patching it in,
+ as it is not known at translation time. */
+ } ProfInc;
+
+ } Min;
+} MIPSInstr;
+
+extern MIPSInstr *MIPSInstr_LI(HReg, ULong);
+extern MIPSInstr *MIPSInstr_Alu(MIPSAluOp, HReg, HReg, MIPSRH *);
+extern MIPSInstr *MIPSInstr_Shft(MIPSShftOp, Bool sz32, HReg, HReg, MIPSRH *);
+extern MIPSInstr *MIPSInstr_Unary(MIPSUnaryOp op, HReg dst, HReg src);
+extern MIPSInstr *MIPSInstr_Cmp(Bool, Bool, HReg, HReg, HReg, MIPSCondCode);
+
+extern MIPSInstr *MIPSInstr_Mul(Bool syned, Bool hi32, Bool sz32, HReg,
+ HReg, HReg);
+extern MIPSInstr *MIPSInstr_Div(Bool syned, Bool sz32, HReg, HReg);
+extern MIPSInstr *MIPSInstr_Madd(Bool, HReg, HReg);
+extern MIPSInstr *MIPSInstr_Msub(Bool, HReg, HReg);
+
+extern MIPSInstr *MIPSInstr_Load(UChar sz, HReg dst, MIPSAMode * src,
+ Bool mode64);
+extern MIPSInstr *MIPSInstr_Store(UChar sz, MIPSAMode * dst, HReg src,
+ Bool mode64);
+
+extern MIPSInstr *MIPSInstr_LoadL(UChar sz, HReg dst, MIPSAMode * src,
+ Bool mode64);
+extern MIPSInstr *MIPSInstr_StoreC(UChar sz, MIPSAMode * dst, HReg src,
+ Bool mode64);
+
+extern MIPSInstr *MIPSInstr_Call(MIPSCondCode, Addr32, UInt, HReg);
+extern MIPSInstr *MIPSInstr_CallAlways(MIPSCondCode, Addr32, UInt);
+
+extern MIPSInstr *MIPSInstr_XDirect(Addr32 dstGA, MIPSAMode* amPC,
+ MIPSCondCode cond, Bool toFastEP);
+extern MIPSInstr *MIPSInstr_XIndir(HReg dstGA, MIPSAMode* amPC,
+ MIPSCondCode cond);
+extern MIPSInstr *MIPSInstr_XAssisted(HReg dstGA, MIPSAMode* amPC,
+ MIPSCondCode cond, IRJumpKind jk);
+
+extern MIPSInstr *MIPSInstr_FpUnary(MIPSFpOp op, HReg dst, HReg src);
+extern MIPSInstr *MIPSInstr_FpBinary(MIPSFpOp op, HReg dst, HReg srcL,
+ HReg srcR);
+extern MIPSInstr *MIPSInstr_FpConvert(MIPSFpOp op, HReg dst, HReg src);
+extern MIPSInstr *MIPSInstr_FpCompare(MIPSFpOp op, HReg dst, HReg srcL,
+ HReg srcR, UChar cond1);
+extern MIPSInstr *MIPSInstr_FpMulAcc(MIPSFpOp op, HReg dst, HReg srcML,
+ HReg srcMR, HReg srcAcc);
+extern MIPSInstr *MIPSInstr_FpLdSt(Bool isLoad, UChar sz, HReg, MIPSAMode *);
+extern MIPSInstr *MIPSInstr_FpSTFIW(HReg addr, HReg data);
+extern MIPSInstr *MIPSInstr_FpRSP(HReg dst, HReg src);
+extern MIPSInstr *MIPSInstr_FpCftI(Bool fromI, Bool int32, HReg dst, HReg src);
+extern MIPSInstr *MIPSInstr_FpCMov(MIPSCondCode, HReg dst, HReg src);
+extern MIPSInstr *MIPSInstr_MtFCSR(HReg src);
+extern MIPSInstr *MIPSInstr_MfFCSR(HReg dst);
+extern MIPSInstr *MIPSInstr_FpCmp(HReg dst, HReg srcL, HReg srcR);
+
+extern MIPSInstr *MIPSInstr_Mfhi(HReg dst);
+extern MIPSInstr *MIPSInstr_Mflo(HReg dst);
+extern MIPSInstr *MIPSInstr_Mthi(HReg src);
+extern MIPSInstr *MIPSInstr_Mtlo(HReg src);
+
+extern MIPSInstr *MIPSInstr_RdWrLR(Bool wrLR, HReg gpr);
+
+// srcL will be copied if !condR
+extern MIPSInstr *MIPSInstr_MovCond(HReg dst, HReg srcL, MIPSRH * src,
+ HReg condR, MIPSCondCode cond);
+
+extern MIPSInstr *MIPSInstr_EvCheck(MIPSAMode* amCounter,
+ MIPSAMode* amFailAddr );
+extern MIPSInstr *MIPSInstr_ProfInc( void );
+
+extern void ppMIPSInstr(MIPSInstr *, Bool mode64);
+
+/* Some functions that insulate the register allocator from details
+ of the underlying instruction set. */
+extern void getRegUsage_MIPSInstr (HRegUsage *, MIPSInstr *, Bool);
+extern void mapRegs_MIPSInstr (HRegRemap *, MIPSInstr *, Bool mode64);
+extern Bool isMove_MIPSInstr (MIPSInstr *, HReg *, HReg *);
+extern Int emit_MIPSInstr (/*MB_MOD*/Bool* is_profInc,
+ UChar* buf, Int nbuf, MIPSInstr* i,
+ Bool mode64,
+ void* disp_cp_chain_me_to_slowEP,
+ void* disp_cp_chain_me_to_fastEP,
+ void* disp_cp_xindir,
+ void* disp_cp_xassisted );
+
+extern void genSpill_MIPS ( /*OUT*/ HInstr ** i1, /*OUT*/ HInstr ** i2,
+ HReg rreg, Int offset, Bool);
+extern void genReload_MIPS( /*OUT*/ HInstr ** i1, /*OUT*/ HInstr ** i2,
+ HReg rreg, Int offset, Bool);
+
+extern void getAllocableRegs_MIPS (Int *, HReg **, Bool mode64);
+extern HInstrArray *iselSB_MIPS ( IRSB*,
+ VexArch,
+ VexArchInfo*,
+ VexAbiInfo*,
+ Int offs_Host_EvC_Counter,
+ Int offs_Host_EvC_FailAddr,
+ Bool chainingAllowed,
+ Bool addProfInc,
+ Addr64 max_ga );
+
+/* How big is an event check? This is kind of a kludge because it
+ depends on the offsets of host_EvC_FAILADDR and host_EvC_COUNTER,
+ and so assumes that they are both <= 128, and so can use the short
+ offset encoding. This is all checked with assertions, so in the
+ worst case we will merely assert at startup. */
+extern Int evCheckSzB_MIPS ( void );
+
+/* Perform a chaining and unchaining of an XDirect jump. */
+extern VexInvalRange chainXDirect_MIPS ( void* place_to_chain,
+ void* disp_cp_chain_me_EXPECTED,
+ void* place_to_jump_to,
+ Bool mode64 );
+
+extern VexInvalRange unchainXDirect_MIPS ( void* place_to_unchain,
+ void* place_to_jump_to_EXPECTED,
+ void* disp_cp_chain_me,
+ Bool mode64 );
+
+/* Patch the counter location into an existing ProfInc point. */
+extern VexInvalRange patchProfInc_MIPS ( void* place_to_patch,
+ ULong* location_of_counter,
+ Bool mode64 );
+
+#endif /* ndef __LIBVEX_HOST_MIPS_HDEFS_H */
+
+/*---------------------------------------------------------------*/
+/*--- end host-mips_defs.h ---*/
+/*---------------------------------------------------------------*/
diff --git a/priv/host_mips_isel.c b/priv/host_mips_isel.c
new file mode 100644
index 0000000..ebda3df
--- /dev/null
+++ b/priv/host_mips_isel.c
@@ -0,0 +1,3262 @@
+
+/*---------------------------------------------------------------*/
+/*--- begin host_mips_isel.c ---*/
+/*---------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2010-2012 RT-RK
+ mips-valgrind@rt-rk.com
+
+ 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "libvex_basictypes.h"
+#include "libvex_ir.h"
+#include "libvex.h"
+
+#include "main_util.h"
+#include "main_globals.h"
+#include "host_generic_regs.h"
+#include "host_mips_defs.h"
+
+/*---------------------------------------------------------*/
+/*--- Register Usage Conventions ---*/
+/*---------------------------------------------------------*/
+/*
+
+Integer Regs
+------------
+ZERO0 Reserved
+GPR1:9 Allocateable
+10 GuestStatePointer
+GPR1:9 Allocateable
+SP StackFramePointer
+RA LinkRegister
+
+*/
+
+static Bool mode64 = False;
+
+/* GPR register class for mips32/64 */
+#define HRcGPR(__mode64) (__mode64 ? HRcInt64 : HRcInt32)
+
+/* FPR register class for mips32/64 */
+#define HRcFPR(__mode64) (__mode64 ? HRcFlt64 : HRcFlt32)
+
+/*---------------------------------------------------------*/
+/*--- ISelEnv ---*/
+/*---------------------------------------------------------*/
+
+/* This carries around:
+
+ - A mapping from IRTemp to IRType, giving the type of any IRTemp we
+ might encounter. This is computed before insn selection starts,
+ and does not change.
+
+ - A mapping from IRTemp to HReg. This tells the insn selector
+ which virtual register(s) are associated with each IRTemp
+ temporary. This is computed before insn selection starts, and
+ does not change. We expect this mapping to map precisely the
+ same set of IRTemps as the type mapping does.
+
+ - vregmap holds the primary register for the IRTemp.
+ - vregmapHI is only used for 64-bit integer-typed
+ IRTemps. It holds the identity of a second
+ 32-bit virtual HReg, which holds the high half
+ of the value.
+
+ - The code array, that is, the insns selected so far.
+
+ - A counter, for generating new virtual registers.
+
+ - The host subarchitecture we are selecting insns for.
+ This is set at the start and does not change.
+
+ - A Bool for indicating whether we may generate chain-me
+ instructions for control flow transfers, or whether we must use
+ XAssisted.
+
+ - The maximum guest address of any guest insn in this block.
+ Actually, the address of the highest-addressed byte from any insn
+ in this block. Is set at the start and does not change. This is
+ used for detecting jumps which are definitely forward-edges from
+ this block, and therefore can be made (chained) to the fast entry
+ point of the destination, thereby avoiding the destination's
+ event check.
+
+ Note, this is all (well, mostly) host-independent.
+*/
+
+typedef
+ struct {
+ /* Constant -- are set at the start and do not change. */
+ IRTypeEnv* type_env;
+
+ HReg* vregmap;
+ HReg* vregmapHI;
+ Int n_vregmap;
+
+ UInt hwcaps;
+ Bool mode64;
+
+ Bool chainingAllowed;
+ Addr64 max_ga;
+
+ /* These are modified as we go along. */
+ HInstrArray* code;
+ Int vreg_ctr;
+ }
+ ISelEnv;
+
+static HReg lookupIRTemp(ISelEnv * env, IRTemp tmp)
+{
+ vassert(tmp >= 0);
+ vassert(tmp < env->n_vregmap);
+ return env->vregmap[tmp];
+}
+
+static void lookupIRTemp64(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp)
+{
+ vassert(tmp >= 0);
+ vassert(tmp < env->n_vregmap);
+ vassert(env->vregmapHI[tmp] != INVALID_HREG);
+ *vrLO = env->vregmap[tmp];
+ *vrHI = env->vregmapHI[tmp];
+}
+
+static void
+lookupIRTempPair(HReg * vrHI, HReg * vrLO, ISelEnv * env, IRTemp tmp)
+{
+ vassert(env->mode64);
+ vassert(tmp >= 0);
+ vassert(tmp < env->n_vregmap);
+ vassert(env->vregmapHI[tmp] != INVALID_HREG);
+ *vrLO = env->vregmap[tmp];
+ *vrHI = env->vregmapHI[tmp];
+}
+
+static void addInstr(ISelEnv * env, MIPSInstr * instr)
+{
+ addHInstr(env->code, instr);
+ if (vex_traceflags & VEX_TRACE_VCODE) {
+ ppMIPSInstr(instr, mode64);
+ vex_printf("\n");
+ }
+}
+
+static HReg newVRegI(ISelEnv * env)
+{
+ HReg reg = mkHReg(env->vreg_ctr, HRcGPR(env->mode64),
+ True /*virtual reg */ );
+ env->vreg_ctr++;
+ return reg;
+}
+
+static HReg newVRegD(ISelEnv * env)
+{
+ HReg reg = mkHReg(env->vreg_ctr, HRcFlt64, True /*virtual reg */ );
+ env->vreg_ctr++;
+ return reg;
+}
+
+static HReg newVRegF(ISelEnv * env)
+{
+ HReg reg = mkHReg(env->vreg_ctr, HRcFPR(env->mode64),
+ True /*virtual reg */ );
+ env->vreg_ctr++;
+ return reg;
+}
+
+static void add_to_sp(ISelEnv * env, UInt n)
+{
+ HReg sp = StackPointer(mode64);
+ vassert(n < 256 && (n % 8) == 0);
+ addInstr(env, MIPSInstr_Alu(Malu_ADD, sp, sp, MIPSRH_Imm(True,
+ toUShort(n))));
+}
+
+static void sub_from_sp(ISelEnv * env, UInt n)
+{
+ HReg sp = StackPointer(mode64);
+ vassert(n < 256 && (n % 8) == 0);
+ addInstr(env, MIPSInstr_Alu(Malu_SUB, sp, sp,
+ MIPSRH_Imm(True, toUShort(n))));
+}
+
+/*---------------------------------------------------------*/
+/*--- ISEL: Forward declarations ---*/
+/*---------------------------------------------------------*/
+
+/* These are organised as iselXXX and iselXXX_wrk pairs. The
+ iselXXX_wrk do the real work, but are not to be called directly.
+ For each XXX, iselXXX calls its iselXXX_wrk counterpart, then
+ checks that all returned registers are virtual. You should not
+ call the _wrk version directly.
+*/
+/* 32-bit mode: Compute an I8/I16/I32 into a RH
+ (reg-or-halfword-immediate).
+ It's important to specify whether the immediate is to be regarded
+ 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 MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e);
+static MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e);
+
+/* 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 MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e);
+static MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e);
+
+/* compute an I8/I16/I32 into a GPR*/
+static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e);
+static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e);
+
+/* compute an I32 into an AMode. */
+static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e,
+ IRType xferTy);
+static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy);
+
+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 MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e);
+static MIPSCondCode 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 void set_MIPS_rounding_mode(ISelEnv * env, IRExpr * mode)
+{
+ /*
+ rounding mode | MIPS | IR
+ ------------------------
+ to nearest | 00 | 00
+ to zero | 01 | 11
+ to +infinity | 10 | 10
+ to -infinity | 11 | 01
+ */
+ // rm_MIPS32 = XOR(rm_IR , (rm_IR << 1)) & 2
+ HReg irrm = iselWordExpr_R(env, mode);
+ HReg tmp = newVRegI(env);
+ HReg fcsr_old = newVRegI(env);
+ MIPSAMode *am_addr;
+
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm,
+ MIPSRH_Imm(False, 1)));
+ addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp)));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, irrm, tmp, MIPSRH_Imm(False, 3)));
+ /* save old value of FCSR */
+ addInstr(env, MIPSInstr_MfFCSR(fcsr_old));
+ sub_from_sp(env, 8); // Move SP down 4 bytes
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ //store old FCSR to stack
+ addInstr(env, MIPSInstr_Store(4, am_addr, fcsr_old, mode64));
+
+ //set new value of FCSR
+ addInstr(env, MIPSInstr_MtFCSR(irrm));
+}
+
+static void set_MIPS_rounding_default(ISelEnv * env)
+{
+ HReg fcsr = newVRegI(env);
+ // load as float
+ MIPSAMode *am_addr;
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ addInstr(env, MIPSInstr_Load(4, fcsr, am_addr, mode64));
+
+ add_to_sp(env, 8); // Reset SP
+
+ //set new value of FCSR
+ addInstr(env, MIPSInstr_MtFCSR(fcsr));
+}
+
+/*---------------------------------------------------------*/
+/*--- ISEL: Misc helpers ---*/
+/*---------------------------------------------------------*/
+
+/* Make an int reg-reg move. */
+static MIPSInstr *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 MIPSInstr_Alu(Malu_OR, r_dst, r_src, MIPSRH_Reg(r_src));
+}
+
+/*---------------------------------------------------------*/
+/*--- 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).
+*/
+static Bool mightRequireFixedRegs(IRExpr * e)
+{
+ switch (e->tag) {
+ case Iex_RdTmp:
+ case Iex_Const:
+ case Iex_Get:
+ return False;
+ default:
+ return True;
+ }
+}
+
+/* Load 2*I32 regs to fp reg */
+static HReg mk_LoadRR32toFPR(ISelEnv * env, HReg r_srcHi, HReg r_srcLo)
+{
+ HReg fr_dst = newVRegD(env);
+ MIPSAMode *am_addr0, *am_addr1;
+
+ vassert(hregClass(r_srcHi) == HRcInt32);
+ vassert(hregClass(r_srcLo) == HRcInt32);
+
+ sub_from_sp(env, 16); // Move SP down 16 bytes
+ am_addr0 = MIPSAMode_IR(0, StackPointer(mode64));
+ am_addr1 = MIPSAMode_IR(8, StackPointer(mode64));
+
+ // store hi,lo as Ity_I32's
+ addInstr(env, MIPSInstr_Store(4, am_addr0, r_srcLo, mode64));
+ addInstr(env, MIPSInstr_Store(4, am_addr1, r_srcHi, mode64));
+
+ // load as float
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, fr_dst, am_addr0));
+
+ add_to_sp(env, 16); // Reset SP
+ return fr_dst;
+}
+
+/* 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. */
+
+static void doHelperCall(ISelEnv * env, Bool passBBP, IRExpr * guard,
+ IRCallee * cee, IRExpr ** args)
+{
+ MIPSCondCode cc;
+ HReg argregs[MIPS_N_REGPARMS];
+ HReg tmpregs[MIPS_N_REGPARMS];
+ Bool go_fast;
+ Int n_args, i, argreg;
+ UInt argiregs;
+ ULong target;
+ HReg src = 0;
+
+ /* MIPS O32 calling convention: up to four registers ($a0 ... $a3)
+ are allowed to be used for passing integer arguments. They correspond
+ to regs GPR4 ... GPR7. Note that the cee->regparms field is meaningless
+ on MIPS host (since we only implement one calling convention) and so we
+ always ignore it. */
+
+ /* MIPS 64 calling convention: up to four registers ($a0 ... $a7)
+ are allowed to be used for passing integer arguments. They correspond
+ to regs GPR4 ... GPR11. Note that the cee->regparms field is meaningless
+ on MIPS host (since we only implement one calling convention) and so we
+ always ignore it. */
+ n_args = 0;
+ for (i = 0; args[i]; i++)
+ n_args++;
+
+ if (MIPS_N_REGPARMS < n_args + (passBBP ? 1 : 0)) {
+ vpanic("doHelperCall(MIPS): cannot currently handle > 4 args");
+ }
+ argregs[0] = hregMIPS_GPR4(mode64);
+ argregs[1] = hregMIPS_GPR5(mode64);
+ argregs[2] = hregMIPS_GPR6(mode64);
+ argregs[3] = hregMIPS_GPR7(mode64);
+ argiregs = 0;
+
+ tmpregs[0] = tmpregs[1] = tmpregs[2] = tmpregs[3] = 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;
+
+ 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;
+ }
+ }
+ }
+
+ /* save GuestStatePointer on the stack */
+ sub_from_sp(env, 8); // Move SP down 4 bytes
+ addInstr(env, MIPSInstr_Store(4, MIPSAMode_IR(0, StackPointer(mode64)),
+ GuestStatePointer(mode64), mode64));
+
+ /* 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 + 4));
+ addInstr(env, mk_iMOVds_RR(argregs[argreg],
+ GuestStatePointer(mode64)));
+ argreg++;
+ }
+
+ for (i = 0; i < n_args; i++) {
+ vassert(argreg < MIPS_N_REGPARMS);
+ vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32
+ || typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
+ if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) {
+ argiregs |= (1 << (argreg + 4));
+ addInstr(env, mk_iMOVds_RR(argregs[argreg], iselWordExpr_R(env,
+ args[i])));
+ } else { // Ity_I64
+ vassert(mode64);
+ argiregs |= (1 << (argreg + 4));
+ addInstr(env, mk_iMOVds_RR(argregs[argreg], iselWordExpr_R(env,
+ args[i])));
+ }
+ argreg++;
+ }
+ /* Fast scheme only applies for unconditional calls. Hence: */
+ cc = MIPScc_AL;
+ } 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],
+ GuestStatePointer(mode64)));
+ argreg++;
+ }
+ for (i = 0; i < n_args; i++) {
+ vassert(argreg < MIPS_N_REGPARMS);
+ vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32
+ || typeOfIRExpr(env->type_env, args[i]) == Ity_I64);
+ if (typeOfIRExpr(env->type_env, args[i]) == Ity_I32) {
+ tmpregs[argreg] = iselWordExpr_R(env, args[i]);
+ } else { // Ity_I64
+ vassert(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 = MIPScc_AL;
+ 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);
+ src = iselWordExpr_R(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 + 4));
+ addInstr(env, mk_iMOVds_RR(argregs[i], tmpregs[i]));
+ }
+ }
+
+ target = toUInt(Ptr_to_ULong(cee->addr));
+
+ /* Finally, the call itself. */
+ if (mode64)
+ if (cc == MIPScc_AL) {
+ addInstr(env, MIPSInstr_CallAlways(cc, target, argiregs));
+ } else {
+ addInstr(env, MIPSInstr_Call(cc, target, argiregs, src));
+ } else if (cc == MIPScc_AL) {
+ addInstr(env, MIPSInstr_CallAlways(cc, (Addr32) target, argiregs));
+ } else {
+ addInstr(env, MIPSInstr_Call(cc, (Addr32) target, argiregs, src));
+ }
+ /* restore GuestStatePointer */
+ addInstr(env, MIPSInstr_Load(4, GuestStatePointer(mode64),
+ MIPSAMode_IR(0, StackPointer(mode64)), mode64));
+ add_to_sp(env, 8); // Reset SP
+}
+
+/*---------------------------------------------------------*/
+/*--- ISEL: Integer expression auxiliaries ---*/
+/*---------------------------------------------------------*/
+
+/* --------------------- AMODEs --------------------- */
+
+/* Return an AMode which computes the value of the specified
+ expression, possibly also adding insns to the code list as a
+ result. The expression may only be a word-size one.
+*/
+
+static Bool uInt_fits_in_16_bits(UInt u)
+{
+ Int i = u & 0xFFFF;
+ i <<= 16;
+ i >>= 16;
+ return toBool(u == (UInt) i);
+}
+
+static Bool sane_AMode(ISelEnv * env, MIPSAMode * am)
+{
+ switch (am->tag) {
+ case Mam_IR:
+ return toBool(hregClass(am->Mam.IR.base) == HRcGPR(mode64) &&
+ hregIsVirtual(am->Mam.IR.base) &&
+ uInt_fits_in_16_bits(am->Mam.IR.index));
+ case Mam_RR:
+ return toBool(hregClass(am->Mam.RR.base) == HRcGPR(mode64) &&
+ hregIsVirtual(am->Mam.RR.base) &&
+ hregClass(am->Mam.RR.index) == HRcGPR(mode64) &&
+ hregIsVirtual(am->Mam.IR.index));
+ default:
+ vpanic("sane_AMode: unknown mips amode tag");
+ }
+}
+
+static MIPSAMode *iselWordExpr_AMode(ISelEnv * env, IRExpr * e, IRType xferTy)
+{
+ MIPSAMode *am = iselWordExpr_AMode_wrk(env, e, xferTy);
+ vassert(sane_AMode(env, am));
+ return am;
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static MIPSAMode *iselWordExpr_AMode_wrk(ISelEnv * env, IRExpr * e,
+ IRType xferTy)
+{
+ IRType ty = typeOfIRExpr(env->type_env, e);
+ {
+ vassert(ty == Ity_I32);
+
+ /* Add32(expr,i), where i == sign-extend of (i & 0xFFFF) */
+ if (e->tag == Iex_Binop
+ && e->Iex.Binop.op == Iop_Add32
+ && e->Iex.Binop.arg2->tag == Iex_Const
+ && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32
+ && uInt_fits_in_16_bits(e->Iex.Binop.arg2->Iex.Const.con-> Ico.U32)) {
+ return MIPSAMode_IR((Int) e->Iex.Binop.arg2->Iex.Const.con->Ico.U32,
+ iselWordExpr_R(env, e->Iex.Binop.arg1));
+ }
+
+ /* Add32(expr,expr) */
+ if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Add32) {
+ HReg r_base = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ HReg r_idx = iselWordExpr_R(env, e->Iex.Binop.arg2);
+
+ return MIPSAMode_RR(r_idx, r_base);
+ }
+ }
+
+ /* Doesn't match anything in particular. Generate it into
+ a register and use that. */
+ return MIPSAMode_IR(0, iselWordExpr_R(env, e));
+}
+
+/*---------------------------------------------------------*/
+/*--- ISEL: Integer expressions (64/32/16/8 bit) ---*/
+/*---------------------------------------------------------*/
+
+/* Select insns for an integer-typed expression, and add them to the
+ code list. Return a reg holding the result. This reg will be a
+ virtual register. THE RETURNED REG MUST NOT BE MODIFIED. If you
+ want to modify it, ask for a new vreg, copy it in there, and modify
+ the copy. The register allocator will do its best to map both
+ vregs to the same real register, so the copies will often disappear
+ later in the game.
+
+ This should handle expressions of 64, 32, 16 and 8-bit type.
+ All results are returned in a (mode64 ? 64bit : 32bit) register.
+ For 16- and 8-bit expressions, the upper (32/48/56 : 16/24) bits
+ are arbitrary, so you should mask or sign extend partial values
+ if necessary.
+*/
+static HReg iselWordExpr_R(ISelEnv * env, IRExpr * e)
+{
+ HReg r = iselWordExpr_R_wrk(env, e);
+ /* sanity checks ... */
+
+ vassert(hregClass(r) == HRcGPR(env->mode64));
+ vassert(hregIsVirtual(r));
+ return r;
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static HReg iselWordExpr_R_wrk(ISelEnv * env, IRExpr * e)
+{
+ IRType ty = typeOfIRExpr(env->type_env, e);
+ vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1
+ || ty == Ity_F32 || (ty == Ity_I64 && mode64)
+ || (ty == Ity_I128 && mode64));
+
+ switch (e->tag) {
+ /* --------- TEMP --------- */
+ case Iex_RdTmp:
+ return lookupIRTemp(env, e->Iex.RdTmp.tmp);
+
+ /* --------- LOAD --------- */
+ case Iex_Load: {
+ HReg r_dst = newVRegI(env);
+ MIPSAMode *am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
+
+ if (e->Iex.Load.end != Iend_LE
+ && e->Iex.Load.end != Iend_BE)
+ goto irreducible;
+
+ addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)),
+ r_dst, am_addr, mode64));
+ return r_dst;
+ break;
+ }
+ /* --------- BINARY OP --------- */
+ case Iex_Binop: {
+ MIPSAluOp aluOp;
+ MIPSShftOp shftOp;
+
+ /* Is it an addition or logical style op? */
+ switch (e->Iex.Binop.op) {
+ case Iop_Add32:
+ aluOp = Malu_ADD;
+ break;
+
+ case Iop_Sub8:
+ case Iop_Sub16:
+ case Iop_Sub32:
+ aluOp = Malu_SUB;
+ break;
+
+ case Iop_And32:
+ case Iop_And64:
+ aluOp = Malu_AND;
+ break;
+
+ case Iop_Or32:
+ case Iop_Or64:
+ aluOp = Malu_OR;
+ break;
+
+ case Iop_Xor32:
+ case Iop_Xor64:
+ aluOp = Malu_XOR;
+ break;
+
+ default:
+ aluOp = Malu_INVALID;
+ break;
+ }
+
+ /* For commutative ops we assume any literal
+ values are on the second operand. */
+ if (aluOp != Malu_INVALID) {
+ HReg r_dst = newVRegI(env);
+ HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ MIPSRH *ri_srcR = NULL;
+ /* get right arg into an RH, in the appropriate way */
+ switch (aluOp) {
+ case Malu_ADD:
+ case Malu_SUB:
+ ri_srcR = iselWordExpr_RH(env, True /*signed */ ,
+ e->Iex.Binop.arg2);
+ break;
+ case Malu_AND:
+ case Malu_OR:
+ case Malu_XOR:
+ ri_srcR = iselWordExpr_RH(env, False /*unsigned */,
+ e->Iex.Binop.arg2);
+ break;
+ default:
+ vpanic("iselWordExpr_R_wrk-aluOp-arg2");
+ }
+ addInstr(env, MIPSInstr_Alu(aluOp, r_dst, r_srcL, ri_srcR));
+ return r_dst;
+ }
+
+ /* a shift? */
+ switch (e->Iex.Binop.op) {
+ case Iop_Shl32:
+ case Iop_Shl64:
+ shftOp = Mshft_SLL;
+ break;
+ case Iop_Shr32:
+ case Iop_Shr64:
+ shftOp = Mshft_SRL;
+ break;
+ case Iop_Sar32:
+ case Iop_Sar64:
+ shftOp = Mshft_SRA;
+ break;
+ default:
+ shftOp = Mshft_INVALID;
+ break;
+ }
+
+ /* we assume any literal values are on the second operand. */
+ if (shftOp != Mshft_INVALID) {
+ HReg r_dst = newVRegI(env);
+ HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ MIPSRH *ri_srcR = NULL;
+ /* get right arg into an RH, in the appropriate way */
+ switch (shftOp) {
+ case Mshft_SLL:
+ case Mshft_SRL:
+ case Mshft_SRA:
+ ri_srcR = iselWordExpr_RH5u(env, e->Iex.Binop. arg2);
+ break;
+ default:
+ vpanic("iselIntExpr_R_wrk-shftOp-arg2");
+ }
+ /* widen the left arg if needed */
+ /*TODO do we need this? */
+ if (ty == Ity_I8 || ty == Ity_I16)
+ goto irreducible;
+ if (ty == Ity_I64) {
+ vassert(mode64);
+ addInstr(env, MIPSInstr_Shft(shftOp, False/*64bit shift */,
+ r_dst, r_srcL, ri_srcR));
+ } else {
+ addInstr(env, MIPSInstr_Shft(shftOp, True /*32bit shift */,
+ r_dst, r_srcL, ri_srcR));
+ }
+ return r_dst;
+ }
+
+ /* Cmp*32*(x,y) ? */
+ if (e->Iex.Binop.op == Iop_CmpEQ32
+ || e->Iex.Binop.op == Iop_CmpNE32
+ || e->Iex.Binop.op == Iop_CmpNE64
+ || e->Iex.Binop.op == Iop_CmpLT32S
+ || e->Iex.Binop.op == Iop_CmpLT32U
+ || e->Iex.Binop.op == Iop_CmpLT64U
+ || e->Iex.Binop.op == Iop_CmpLE32S
+ || e->Iex.Binop.op == Iop_CmpLE64S
+ || e->Iex.Binop.op == Iop_CmpLT64S
+ || e->Iex.Binop.op == Iop_CmpEQ64) {
+
+ Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
+ || e->Iex.Binop.op == Iop_CmpLE32S
+ || e->Iex.Binop.op == Iop_CmpLT64S
+ || e->Iex.Binop.op == Iop_CmpLE64S);
+ Bool size32;
+ HReg dst = newVRegI(env);
+ HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
+
+ MIPSCondCode cc;
+
+ switch (e->Iex.Binop.op) {
+ case Iop_CmpEQ32:
+ cc = MIPScc_EQ;
+ size32 = True;
+ break;
+ case Iop_CmpNE32:
+ cc = MIPScc_NE;
+ size32 = True;
+ break;
+ case Iop_CmpNE64:
+ cc = MIPScc_NE;
+ size32 = True;
+ break;
+ case Iop_CmpLT32S:
+ cc = MIPScc_LT;
+ size32 = True;
+ break;
+ case Iop_CmpLT32U:
+ cc = MIPScc_LO;
+ size32 = True;
+ break;
+ case Iop_CmpLT64U:
+ cc = MIPScc_LO;
+ size32 = False;
+ break;
+ case Iop_CmpLE32S:
+ cc = MIPScc_LE;
+ size32 = True;
+ break;
+ case Iop_CmpLE64S:
+ cc = MIPScc_LE;
+ size32 = False;
+ break;
+ case Iop_CmpLT64S:
+ cc = MIPScc_LT;
+ size32 = False;
+ break;
+ case Iop_CmpEQ64:
+ cc = MIPScc_EQ;
+ size32 = False;
+ break;
+ default:
+ vpanic
+ ("iselCondCode(mips): CmpXX32 or CmpXX64");
+ }
+
+ addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc));
+ return dst;
+
+ break;
+
+ }
+
+ if (e->Iex.Binop.op == Iop_Max32U) {
+ /*
+ tmp = argR - argL;
+ dst = argL;
+ bltz tmp,2;
+ dst = argR;
+
+ */
+ HReg argL = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ MIPSRH *argR = iselWordExpr_RH(env, False /*signed */ ,
+ e->Iex.Binop.arg2);
+ HReg dst = newVRegI(env);
+ HReg tmp = newVRegI(env);
+ addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp, argL, argR));
+ addInstr(env, MIPSInstr_MovCond(dst, argL, argR, tmp, MIPScc_MI));
+
+ return dst;
+ }
+
+ if (e->Iex.Binop.op == Iop_Mul32 || e->Iex.Binop.op == Iop_Mul64) {
+ Bool sz32 = (e->Iex.Binop.op == Iop_Mul32);
+ HReg r_dst = newVRegI(env);
+ HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ addInstr(env, MIPSInstr_Mul(False/*Unsigned or Signed */ ,
+ False /*widen */ ,
+ sz32 /*32bit or 64bit */,
+ r_dst, r_srcL, r_srcR));
+ return r_dst;
+ }
+
+ if (e->Iex.Binop.op == Iop_MullU32 || e->Iex.Binop.op == Iop_MullS32) {
+ HReg r_dst = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ HReg tLo = newVRegI(env);
+ HReg tLo_1 = newVRegI(env);
+ HReg tHi_1 = newVRegI(env);
+ HReg mask = newVRegI(env);
+
+ Bool syned = toBool(e->Iex.Binop.op == Iop_MullS32);
+ Bool size = toBool(e->Iex.Binop.op == Iop_MullS32)
+ || toBool(e->Iex.Binop.op == Iop_MullU32);
+ HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ addInstr(env, MIPSInstr_Mul(syned /*Unsigned or Signed */ ,
+ True /*widen */ ,
+ size /*32bit or 64bit mul */ ,
+ r_dst, r_srcL, r_srcR));
+
+ addInstr(env, MIPSInstr_Mfhi(tHi));
+ addInstr(env, MIPSInstr_Mflo(tLo));
+
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1,
+ tHi, MIPSRH_Imm(False, 32)));
+
+ addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
+ MIPSRH_Reg(mask)));
+
+ addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
+ MIPSRH_Reg(tLo_1)));
+
+ return r_dst;
+ }
+
+ if (e->Iex.Binop.op == Iop_CmpF64) {
+ HReg r_srcL, r_srcR;
+ {
+ r_srcL = iselDblExpr(env, e->Iex.Binop.arg1);
+ r_srcR = iselDblExpr(env, e->Iex.Binop.arg2);
+ }
+ HReg tmp = newVRegI(env);
+ HReg r_ccMIPS = newVRegI(env);
+ HReg r_ccIR = newVRegI(env);
+ HReg r_ccIR_b0 = newVRegI(env);
+ HReg r_ccIR_b2 = newVRegI(env);
+ HReg r_ccIR_b6 = newVRegI(env);
+
+ /* Create in dst, the IRCmpF64Result encoded result. */
+ // chech for EQ
+ addInstr(env, MIPSInstr_FpCompare(Mfp_CMP, tmp, r_srcL, r_srcR,
+ toUChar(2)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, r_ccMIPS, tmp,
+ MIPSRH_Imm(False, 22)));
+ // chech for UN
+ addInstr(env, MIPSInstr_FpCompare(Mfp_CMP, tmp, r_srcL, r_srcR,
+ toUChar(1)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp, tmp,
+ MIPSRH_Imm(False, 23)));
+ addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
+ MIPSRH_Reg(tmp)));
+ // chech for LT
+ addInstr(env, MIPSInstr_FpCompare(Mfp_CMP, tmp, r_srcL, r_srcR,
+ toUChar(12)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp,
+ tmp, MIPSRH_Imm(False, 21)));
+ addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
+ MIPSRH_Reg(tmp)));
+ // chech for GT
+ addInstr(env, MIPSInstr_FpCompare(Mfp_CMP, tmp, r_srcL, r_srcR,
+ toUChar(15)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp, tmp,
+ MIPSRH_Imm(False, 20)));
+
+ addInstr(env, MIPSInstr_Alu(Malu_NOR, tmp, tmp, MIPSRH_Reg(tmp)));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, tmp,
+ MIPSRH_Imm(False, 8)));
+ addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccMIPS, r_ccMIPS,
+ MIPSRH_Reg(tmp)));
+ /* Map compare result from PPC to IR,
+ conforming to CmpF64 definition. */
+ /*
+ FP cmp result | MIPS | IR
+ --------------------------
+ UN | 0x1 | 0x45
+ EQ | 0x2 | 0x40
+ GT | 0x4 | 0x00
+ LT | 0x8 | 0x01
+ */
+
+ // r_ccIR_b0 = r_ccPPC[0] | r_ccPPC[3]
+ addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b0, r_ccMIPS,
+ MIPSRH_Imm(False, 0x3)));
+ addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b0, r_ccMIPS,
+ MIPSRH_Reg(r_ccIR_b0)));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b0, r_ccIR_b0,
+ MIPSRH_Imm(False, 0x1)));
+
+ // r_ccIR_b2 = r_ccPPC[0]
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b2, r_ccMIPS,
+ MIPSRH_Imm(False, 0x2)));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b2, r_ccIR_b2,
+ MIPSRH_Imm(False, 0x4)));
+
+ // r_ccIR_b6 = r_ccPPC[0] | r_ccPPC[1]
+ addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_ccIR_b6,
+ r_ccMIPS, MIPSRH_Imm(False, 0x1)));
+ addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR_b6, r_ccMIPS,
+ MIPSRH_Reg(r_ccIR_b6)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_ccIR_b6, r_ccIR_b6,
+ MIPSRH_Imm(False, 0x6)));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, r_ccIR_b6, r_ccIR_b6,
+ MIPSRH_Imm(False, 0x40)));
+
+ // r_ccIR = r_ccIR_b0 | r_ccIR_b2 | r_ccIR_b6
+ addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR_b0,
+ MIPSRH_Reg(r_ccIR_b2)));
+ addInstr(env, MIPSInstr_Alu(Malu_OR, r_ccIR, r_ccIR,
+ MIPSRH_Reg(r_ccIR_b6)));
+ return r_ccIR;
+ }
+
+ if (e->Iex.Binop.op == Iop_DivModU64to32 ||
+ e->Iex.Binop.op == Iop_DivModS64to32) {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ HReg mask = newVRegI(env);
+ HReg tLo_1 = newVRegI(env);
+ HReg tHi_1 = newVRegI(env);
+ HReg r_dst = newVRegI(env);
+ Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to32);
+
+ HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
+
+ addInstr(env, MIPSInstr_Div(syned, True, r_srcL, r_srcR));
+ addInstr(env, MIPSInstr_Mfhi(tHi));
+ addInstr(env, MIPSInstr_Mflo(tLo));
+
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi,
+ MIPSRH_Imm(False, 32)));
+
+ addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
+ MIPSRH_Reg(mask)));
+
+ addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
+ MIPSRH_Reg(tLo_1)));
+
+ return r_dst;
+ }
+
+ if (e->Iex.Binop.op == Iop_32HLto64) {
+ vassert(mode64);
+ HReg tHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ HReg tLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ HReg tLo_1 = newVRegI(env);
+ HReg tHi_1 = newVRegI(env);
+ HReg r_dst = newVRegI(env);
+ HReg mask = newVRegI(env);
+
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, False, tHi_1, tHi,
+ MIPSRH_Imm(False, 32)));
+
+ addInstr(env, MIPSInstr_LI(mask, 0xffffffff));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, tLo_1, tLo,
+ MIPSRH_Reg(mask)));
+ addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, tHi_1,
+ MIPSRH_Reg(tLo_1)));
+
+ return r_dst;
+ }
+ }
+
+ /* --------- UNARY OP --------- */
+ case Iex_Unop: {
+ IROp op_unop = e->Iex.Unop.op;
+
+ switch (op_unop) {
+ case Iop_1Sto32:
+ case Iop_8Sto32:
+ case Iop_16Sto32:
+ case Iop_16Sto64:
+ case Iop_8Sto64:
+ case Iop_1Sto64: {
+ HReg r_dst = newVRegI(env);
+ HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ Bool sz32;
+ UShort amt;
+ switch (op_unop) {
+ case Iop_1Sto32:
+ amt = 31;
+ sz32 = True;
+ break;
+ case Iop_16Sto32:
+ amt = 16;
+ sz32 = True;
+ break;
+ case Iop_16Sto64:
+ amt = 48;
+ sz32 = False;
+ break;
+ case Iop_8Sto32:
+ amt = 24;
+ sz32 = True;
+ break;
+ case Iop_8Sto64:
+ amt = 56;
+ sz32 = False;
+ break;
+ case Iop_1Sto64:
+ amt = 63;
+ sz32 = False;
+ break;
+ default:
+ vassert(0);
+ }
+
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, sz32, r_dst, r_src,
+ MIPSRH_Imm(False, amt)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRA, sz32, r_dst, r_dst,
+ MIPSRH_Imm(False, amt)));
+ return r_dst;
+ }
+
+ /*not(x) = nor(x,x) */
+ case Iop_Not1: {
+ HReg r_dst = newVRegI(env);
+ HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
+ MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
+
+ addInstr(env, MIPSInstr_LI(r_dst, 0x1));
+ addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR));
+ return r_dst;
+ }
+
+ case Iop_Not32:
+ case Iop_Not64: {
+ HReg r_dst = newVRegI(env);
+ HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
+ MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
+
+ addInstr(env, MIPSInstr_Alu(Malu_NOR, r_dst, r_srcL, r_srcR));
+ return r_dst;
+ }
+
+ case Iop_ReinterpF32asI32: {
+ MIPSAMode *am_addr;
+ HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg);
+ HReg r_dst = newVRegI(env);
+
+ sub_from_sp(env, 16); // Move SP down 16 bytes
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ // store as F32
+ addInstr(env, MIPSInstr_FpLdSt(False/*store */ , 4, fr_src,
+ am_addr));
+ // load as Ity_I32
+ addInstr(env, MIPSInstr_Load(4, r_dst, am_addr, mode64));
+
+ add_to_sp(env, 16); // Reset SP
+ return r_dst;
+ }
+
+ case Iop_ReinterpF64asI64: {
+ vassert(mode64);
+ MIPSAMode *am_addr;
+ HReg fr_src = iselFltExpr(env, e->Iex.Unop.arg);
+ HReg r_dst = newVRegI(env);
+
+ sub_from_sp(env, 16); // Move SP down 16 bytes
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ // store as F64
+ addInstr(env, MIPSInstr_FpLdSt(False/*store */ , 8, fr_src,
+ am_addr));
+ // load as Ity_I64
+ addInstr(env, MIPSInstr_Load(8, r_dst, am_addr, mode64));
+
+ add_to_sp(env, 16); // Reset SP
+ return r_dst;
+ }
+
+ case Iop_F64toI32S: {
+ HReg valD = iselDblExpr(env, e->Iex.Binop.arg2);
+ HReg valS = newVRegF(env);
+ HReg r_dst = newVRegI(env);
+ MIPSAMode *am_addr;
+
+ set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWD, valS, valD));
+ set_MIPS_rounding_default(env);
+
+ sub_from_sp(env, 16); // Move SP down 16 bytes
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ // store as F32
+ addInstr(env, MIPSInstr_FpLdSt(False/*store */ , 4, valS, am_addr));
+ // load as I32
+ addInstr(env, MIPSInstr_Load(4, r_dst, am_addr, mode64));
+
+ add_to_sp(env, 16); // Reset SP
+
+ return r_dst;
+ }
+
+ case Iop_32to8:
+ case Iop_32to16:
+ return iselWordExpr_R(env, e->Iex.Unop.arg);
+
+ case Iop_64to8: {
+ vassert(mode64);
+ HReg r_src, r_dst;
+ r_dst = newVRegI(env);
+ r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src,
+ MIPSRH_Imm(False, 0xFF)));
+ return r_dst;
+ }
+
+ case Iop_16Uto32:
+ case Iop_8Uto32:
+ case Iop_1Uto32: {
+ HReg r_dst = newVRegI(env);
+ HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ UShort amt;
+ switch (op_unop) {
+ case Iop_1Uto32:
+ case Iop_1Uto8:
+ amt = 31;
+ break;
+
+ case Iop_16Uto32:
+ amt = 16;
+ break;
+
+ default:
+ amt = 24;
+ break;
+ }
+
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, r_dst, r_src,
+ MIPSRH_Imm(False, amt)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRL, True, r_dst, r_dst,
+ MIPSRH_Imm(False, amt)));
+ return r_dst;
+ }
+
+ case Iop_8Uto16:
+ case Iop_8Uto64:
+ case Iop_16Uto64: {
+ vassert(mode64);
+ HReg r_dst = newVRegI(env);
+ HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ UShort mask = toUShort(op_unop == Iop_16Uto64 ? 0xFFFF :
+ op_unop == Iop_16Uto32 ? 0xFFFF : 0xFF);
+ addInstr(env, MIPSInstr_Alu(Malu_AND, r_dst, r_src,
+ MIPSRH_Imm(False, mask)));
+ return r_dst;
+ }
+
+ case Iop_32Uto64: {
+ HReg r_dst = newVRegI(env);
+ HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ vassert(mode64);
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, False/*!32bit shift */,
+ r_dst, r_src, MIPSRH_Imm(False, 32)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRL, False/*!32bit shift */,
+ r_dst, r_dst, MIPSRH_Imm(False, 32)));
+ return r_dst;
+ }
+
+ case Iop_1Uto64:
+ vassert(mode64);
+ return iselWordExpr_R(env, e->Iex.Unop.arg);
+
+ case Iop_64HIto32: {
+ HReg rHi, rLo;
+ iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
+ return rHi;
+ }
+
+ case Iop_64to32: {
+ HReg rHi, rLo;
+ iselInt64Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
+ return rLo;
+ }
+
+ case Iop_64to16: {
+ vassert(env->mode64);
+ HReg r_dst = newVRegI(env);
+ r_dst = iselWordExpr_R(env, e->Iex.Unop.arg);
+ return r_dst;
+ }
+
+ case Iop_32Sto64: {
+ HReg r_dst = newVRegI(env);
+ HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ vassert(mode64);
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True/*!32bit shift */,
+ r_dst, r_src, MIPSRH_Imm(True, 0)));
+ return r_dst;
+ }
+
+ case Iop_CmpNEZ8: {
+ HReg r_dst = newVRegI(env);
+ HReg tmp = newVRegI(env);
+ HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+
+ MIPSCondCode cc;
+
+ cc = MIPScc_NE;
+ addInstr(env, MIPSInstr_Alu(Malu_AND, tmp, r_src,
+ MIPSRH_Imm(False, 0xFF)));
+ addInstr(env, MIPSInstr_Cmp(False, True, r_dst, tmp,
+ hregMIPS_GPR0(mode64), cc));
+ return r_dst;
+ }
+
+ case Iop_CmpNEZ32: {
+ HReg r_dst = newVRegI(env);
+ HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+
+ MIPSCondCode cc;
+
+ cc = MIPScc_NE;
+
+ addInstr(env, MIPSInstr_Cmp(False, True, r_dst, r_src,
+ hregMIPS_GPR0(mode64), cc));
+ return r_dst;
+ }
+
+ case Iop_CmpwNEZ32: {
+ HReg r_dst = newVRegI(env);
+ HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+
+ addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, hregMIPS_GPR0(mode64),
+ MIPSRH_Reg(r_src)));
+
+ addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst,
+ MIPSRH_Reg(r_src)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, r_dst, r_dst,
+ MIPSRH_Imm(False, 31)));
+ return r_dst;
+ }
+
+ case Iop_Left8:
+ case Iop_Left32:
+ case Iop_Left64: {
+ if (op_unop == Iop_Left64 && !mode64)
+ goto irreducible;
+ HReg r_dst = newVRegI(env);
+ HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, hregMIPS_GPR0(mode64),
+ MIPSRH_Reg(r_src)));
+ addInstr(env, MIPSInstr_Alu(Malu_OR, r_dst, r_dst,
+ MIPSRH_Reg(r_src)));
+ return r_dst;
+ }
+
+ case Iop_Clz32: {
+ HReg r_dst = newVRegI(env);
+ HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env, MIPSInstr_Unary(Mun_CLZ, r_dst, r_src));
+ return r_dst;
+ }
+
+ case Iop_CmpNEZ64: {
+ HReg hi, lo;
+ HReg r_dst = newVRegI(env);
+ HReg r_src;
+ r_src = newVRegI(env);
+ iselInt64Expr(&hi, &lo, env, e->Iex.Unop.arg);
+ addInstr(env, MIPSInstr_Alu(Malu_OR, r_src, lo, MIPSRH_Reg(hi)));
+ MIPSCondCode cc;
+
+ cc = MIPScc_NE;
+
+ addInstr(env, MIPSInstr_Cmp(False, !(env->mode64), r_dst, r_src,
+ hregMIPS_GPR0(mode64), cc));
+ return r_dst;
+ }
+
+ case Iop_CmpwNEZ64: {
+ HReg tmp1;
+ HReg tmp2 = newVRegI(env);
+ vassert(env->mode64);
+ tmp1 = iselWordExpr_R(env, e->Iex.Unop.arg);
+
+ addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, hregMIPS_GPR0(mode64),
+ MIPSRH_Reg(tmp1)));
+
+ addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRA, False, tmp2, tmp2,
+ MIPSRH_Imm (False, 63)));
+ return tmp2;
+ }
+
+ case Iop_128HIto64: {
+ vassert(mode64);
+ HReg rHi, rLo;
+ iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
+ return rHi; /* and abandon rLo .. poor wee thing :-) */
+ }
+
+ case Iop_128to64: {
+ vassert(mode64);
+ HReg rHi, rLo;
+ iselInt128Expr(&rHi, &rLo, env, e->Iex.Unop.arg);
+ return rLo; /* and abandon rLo .. poor wee thing :-) */
+ }
+
+ default:
+ break;
+ }
+ break;
+ }
+
+ /* --------- GET --------- */
+ case Iex_Get: {
+ if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32
+ || ((ty == Ity_I64) && mode64)) {
+ HReg r_dst = newVRegI(env);
+
+ MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
+ GuestStatePointer(mode64));
+ addInstr(env, MIPSInstr_Load(toUChar(sizeofIRType(ty)), r_dst, am_addr,
+ mode64));
+ return r_dst;
+ }
+ }
+
+ /* --------- MULTIPLEX --------- */
+ case Iex_Mux0X: {
+ if ((ty == Ity_I8 || ty == Ity_I16 ||
+ ty == Ity_I32 || ((ty == Ity_I64))) &&
+ typeOfIRExpr(env->type_env, e->Iex.Mux0X.cond) == Ity_I8) {
+ /*
+ * r_dst = cond && rX
+ * cond = not(cond)
+ * tmp = cond && r0
+ * r_dst = tmp + r_dst
+ */
+ HReg r0 = iselWordExpr_R(env, e->Iex.Mux0X.expr0);
+ HReg rX = iselWordExpr_R(env, e->Iex.Mux0X.exprX);
+ HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond);
+ HReg r_dst = newVRegI(env);
+ HReg r_tmp = newVRegI(env);
+ HReg r_tmp1 = newVRegI(env);
+ HReg r_cond_neg = newVRegI(env);
+
+ addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp, r_cond, MIPSRH_Reg(rX)));
+ addInstr(env, MIPSInstr_Alu(Malu_NOR, r_cond_neg, r_cond,
+ MIPSRH_Reg(r_cond)));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp1, r_cond_neg,
+ MIPSRH_Reg(r0)));
+ addInstr(env, MIPSInstr_Alu(Malu_ADD, r_dst, r_tmp,
+ MIPSRH_Reg(r_tmp1)));
+
+ return r_dst;
+ }
+ }
+
+ /* --------- LITERAL --------- */
+ /* 32/16/8-bit literals */
+ case Iex_Const: {
+ Long l;
+ HReg r_dst = newVRegI(env);
+ IRConst *con = e->Iex.Const.con;
+ switch (con->tag) {
+ case Ico_U64:
+ if (!mode64)
+ goto irreducible;
+ l = (Long) con->Ico.U64;
+ break;
+ case Ico_U32:
+ l = (Long) (Int) con->Ico.U32;
+ break;
+ case Ico_U16:
+ l = (Long) (Int) (Short) con->Ico.U16;
+ break;
+ case Ico_U8:
+ l = (Long) (Int) (Char) con->Ico.U8;
+ break;
+ default:
+ vpanic("iselIntExpr_R.const(mips)");
+ }
+ addInstr(env, MIPSInstr_LI(r_dst, (ULong) l));
+ return r_dst;
+ }
+
+ /* --------- CCALL --------- */
+ case Iex_CCall: {
+ HReg r_dst = newVRegI(env);
+ vassert(ty == e->Iex.CCall.retty);
+
+ /* be very restrictive for now. Only 32/64-bit ints allowed
+ for args, and 32 bits for return type. */
+ if (e->Iex.CCall.retty != Ity_I32 && !mode64)
+ goto irreducible;
+
+ /* Marshal args, do the call, clear stack. */
+ doHelperCall(env, False, NULL, e->Iex.CCall.cee, e->Iex.CCall.args);
+ addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
+ return r_dst;
+ }
+
+ default:
+ break;
+ } /* end switch(e->tag) */
+
+ /* We get here if no pattern matched. */
+ irreducible:
+ vex_printf("--------------->\n");
+ if (e->tag == Iex_RdTmp)
+ vex_printf("Iex_RdTmp \n");
+ ppIRExpr(e);
+
+ vpanic("iselWordExpr_R(mips): cannot reduce tree");
+}
+
+/* --------------------- RH --------------------- */
+
+/* Compute an I8/I16/I32 (and I64, in 64-bit mode) into a RH
+ (reg-or-halfword-immediate). It's important to specify whether the
+ immediate is to be regarded 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 MIPSRH *iselWordExpr_RH(ISelEnv * env, Bool syned, IRExpr * e)
+{
+ MIPSRH *ri = iselWordExpr_RH_wrk(env, syned, e);
+ /* sanity checks ... */
+ switch (ri->tag) {
+ case Mrh_Imm:
+ vassert(ri->Mrh.Imm.syned == syned);
+ if (syned)
+ vassert(ri->Mrh.Imm.imm16 != 0x8000);
+ return ri;
+ case Mrh_Reg:
+ vassert(hregClass(ri->Mrh.Reg.reg) == HRcGPR(env->mode64));
+ vassert(hregIsVirtual(ri->Mrh.Reg.reg));
+ return ri;
+ default:
+ vpanic("iselIntExpr_RH: unknown mips RH tag");
+ }
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static MIPSRH *iselWordExpr_RH_wrk(ISelEnv * env, Bool syned, IRExpr * e)
+{
+ ULong u;
+ Long l;
+ IRType ty = typeOfIRExpr(env->type_env, e);
+ vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
+ ((ty == Ity_I64) && env->mode64));
+
+ /* special case: immediate */
+ if (e->tag == Iex_Const) {
+ IRConst *con = e->Iex.Const.con;
+ /* What value are we aiming to generate? */
+ switch (con->tag) {
+ /* Note: Not sign-extending - we carry 'syned' around */
+ case Ico_U64:
+ vassert(env->mode64);
+ u = con->Ico.U64;
+ break;
+ case Ico_U32:
+ u = 0xFFFFFFFF & con->Ico.U32;
+ break;
+ case Ico_U16:
+ u = 0x0000FFFF & con->Ico.U16;
+ break;
+ case Ico_U8:
+ u = 0x000000FF & con->Ico.U8;
+ break;
+ default:
+ vpanic("iselIntExpr_RH.Iex_Const(mips)");
+ }
+ l = (Long) u;
+ /* Now figure out if it's representable. */
+ if (!syned && u <= 65535) {
+ return MIPSRH_Imm(False /*unsigned */ , toUShort(u & 0xFFFF));
+ }
+ if (syned && l >= -32767 && l <= 32767) {
+ return MIPSRH_Imm(True /*signed */ , toUShort(u & 0xFFFF));
+ }
+ /* no luck; use the Slow Way. */
+ }
+ /* default case: calculate into a register and return that */
+ return MIPSRH_Reg(iselWordExpr_R(env, e));
+}
+
+/* --------------------- RH5u --------------------- */
+
+/* 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 MIPSRH *iselWordExpr_RH5u(ISelEnv * env, IRExpr * e)
+{
+ MIPSRH *ri;
+ ri = iselWordExpr_RH5u_wrk(env, e);
+ /* sanity checks ... */
+ switch (ri->tag) {
+ case Mrh_Imm:
+ vassert(ri->Mrh.Imm.imm16 >= 1 && ri->Mrh.Imm.imm16 <= 31);
+ vassert(!ri->Mrh.Imm.syned);
+ return ri;
+ case Mrh_Reg:
+ vassert(hregClass(ri->Mrh.Reg.reg) == HRcInt32);
+ vassert(hregIsVirtual(ri->Mrh.Reg.reg));
+ return ri;
+ default:
+ vpanic("iselIntExpr_RH5u: unknown mips RH tag");
+ }
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static MIPSRH *iselWordExpr_RH5u_wrk(ISelEnv * env, IRExpr * e)
+{
+ IRType ty = typeOfIRExpr(env->type_env, e);
+ vassert(ty == Ity_I8);
+
+ /* special case: immediate */
+ if (e->tag == Iex_Const
+ && e->Iex.Const.con->tag == Ico_U8
+ && e->Iex.Const.con->Ico.U8 >= 1 && e->Iex.Const.con->Ico.U8 <= 31) {
+ return MIPSRH_Imm(False /*unsigned */ , e->Iex.Const.con->Ico.U8);
+ }
+
+ /* default case: calculate into a register and return that */
+ return MIPSRH_Reg(iselWordExpr_R(env, e));
+}
+
+/* --------------------- CONDCODE --------------------- */
+
+/* Generate code to evaluated a bit-typed expression, returning the
+ condition code which would correspond when the expression would
+ notionally have returned 1. */
+
+static MIPSCondCode iselCondCode(ISelEnv * env, IRExpr * e)
+{
+ MIPSCondCode cc = iselCondCode_wrk(env,e);
+ vassert(cc != MIPScc_NV);
+ return cc;
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static MIPSCondCode iselCondCode_wrk(ISelEnv * env, IRExpr * e)
+{
+ vassert(e);
+ vassert(typeOfIRExpr(env->type_env, e) == Ity_I1);
+ /* Cmp*32*(x,y) ? */
+ if (e->Iex.Binop.op == Iop_CmpEQ32
+ || e->Iex.Binop.op == Iop_CmpNE32
+ || e->Iex.Binop.op == Iop_CmpNE64
+ || e->Iex.Binop.op == Iop_CmpLT32S
+ || e->Iex.Binop.op == Iop_CmpLT32U
+ || e->Iex.Binop.op == Iop_CmpLT64U
+ || e->Iex.Binop.op == Iop_CmpLE32S
+ || e->Iex.Binop.op == Iop_CmpLE64S
+ || e->Iex.Binop.op == Iop_CmpLT64S
+ || e->Iex.Binop.op == Iop_CmpEQ64) {
+
+ Bool syned = (e->Iex.Binop.op == Iop_CmpLT32S
+ || e->Iex.Binop.op == Iop_CmpLE32S
+ || e->Iex.Binop.op == Iop_CmpLT64S
+ || e->Iex.Binop.op == Iop_CmpLE64S);
+ Bool size32;
+ HReg dst = newVRegI(env);
+ HReg r1 = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ HReg r2 = iselWordExpr_R(env, e->Iex.Binop.arg2);
+
+ MIPSCondCode cc;
+
+ switch (e->Iex.Binop.op) {
+ case Iop_CmpEQ32:
+ cc = MIPScc_EQ;
+ size32 = True;
+ break;
+ case Iop_CmpNE32:
+ cc = MIPScc_NE;
+ size32 = True;
+ break;
+ case Iop_CmpNE64:
+ cc = MIPScc_NE;
+ size32 = True;
+ break;
+ case Iop_CmpLT32S:
+ cc = MIPScc_LT;
+ size32 = True;
+ break;
+ case Iop_CmpLT32U:
+ cc = MIPScc_LO;
+ size32 = True;
+ break;
+ case Iop_CmpLT64U:
+ cc = MIPScc_LO;
+ size32 = False;
+ break;
+ case Iop_CmpLE32S:
+ cc = MIPScc_LE;
+ size32 = True;
+ break;
+ case Iop_CmpLE64S:
+ cc = MIPScc_LE;
+ size32 = False;
+ break;
+ case Iop_CmpLT64S:
+ cc = MIPScc_LT;
+ size32 = False;
+ break;
+ case Iop_CmpEQ64:
+ cc = MIPScc_EQ;
+ size32 = False;
+ break;
+ default:
+ vpanic
+ ("iselCondCode(mips): CmpXX32 or CmpXX64");
+ }
+
+ addInstr(env, MIPSInstr_Cmp(syned, size32, dst, r1, r2, cc));
+ // Store result to guest_COND
+ MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
+
+ addInstr(env, MIPSInstr_Store(4,
+ MIPSAMode_IR(am_addr->Mam.IR.index + 316, am_addr->Mam.IR.base),
+ dst, mode64));
+ return cc;
+ }
+ if (e->Iex.Binop.op == Iop_Not1) {
+ HReg r_dst = newVRegI(env);
+ HReg r_srcL = iselWordExpr_R(env, e->Iex.Unop.arg);
+ MIPSRH *r_srcR = MIPSRH_Reg(r_srcL);
+
+ addInstr(env, MIPSInstr_LI(r_dst, 0x1));
+ addInstr(env, MIPSInstr_Alu(Malu_SUB, r_dst, r_dst, r_srcR));
+ // Store result to guest_COND
+ MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
+
+ addInstr(env, MIPSInstr_Store(4,
+ MIPSAMode_IR(am_addr->Mam.IR.index + 316, am_addr->Mam.IR.base),
+ r_dst, mode64));
+ return MIPScc_NE;
+ }
+ if (e->tag == Iex_RdTmp || e->tag == Iex_Unop) {
+ HReg r_dst = iselWordExpr_R_wrk(env, e);
+ // Store result to guest_COND
+ MIPSAMode *am_addr = MIPSAMode_IR(0, GuestStatePointer(mode64));
+
+ addInstr(env, MIPSInstr_Store(4,
+ MIPSAMode_IR(am_addr->Mam.IR.index + 316, am_addr->Mam.IR.base),
+ r_dst, mode64));
+ return MIPScc_EQ;
+ }
+
+ vex_printf("iselCondCode(mips): No such tag(%u)\n", e->tag);
+ ppIRExpr(e);
+ vpanic("iselCondCode(mips)");
+}
+
+/*---------------------------------------------------------*/
+/*--- ISEL: Integer expressions (128 bit) ---*/
+/*---------------------------------------------------------*/
+
+/* 64-bit mode ONLY: compute a 128-bit value into a register pair,
+ which is returned as the first two parameters. As with
+ iselWordExpr_R, these may be either real or virtual regs; in any
+ case they must not be changed by subsequent code emitted by the
+ caller. */
+
+static void iselInt128Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
+{
+ vassert(env->mode64);
+ iselInt128Expr_wrk(rHi, rLo, env, e);
+# if 0
+ vex_printf("\n");
+ ppIRExpr(e);
+ vex_printf("\n");
+# endif
+ vassert(hregClass(*rHi) == HRcGPR(env->mode64));
+ vassert(hregIsVirtual(*rHi));
+ vassert(hregClass(*rLo) == HRcGPR(env->mode64));
+ vassert(hregIsVirtual(*rLo));
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static void iselInt128Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env,
+ IRExpr * e)
+{
+ vassert(e);
+ vassert(typeOfIRExpr(env->type_env, e) == Ity_I128);
+
+ /* read 128-bit IRTemp */
+ if (e->tag == Iex_RdTmp) {
+ lookupIRTempPair(rHi, rLo, env, e->Iex.RdTmp.tmp);
+ return;
+ }
+
+ /* --------- BINARY ops --------- */
+ if (e->tag == Iex_Binop) {
+ switch (e->Iex.Binop.op) {
+ /* 64 x 64 -> 128 multiply */
+ case Iop_MullU64:
+ case Iop_MullS64:
+ {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ Bool syned = toBool(e->Iex.Binop.op == Iop_MullS64);
+ HReg r_dst = newVRegI(env);
+ HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ addInstr(env, MIPSInstr_Mul(syned, True, False /*64bit mul */ ,
+ r_dst, r_srcL, r_srcR));
+ addInstr(env, MIPSInstr_Mfhi(tHi));
+ addInstr(env, MIPSInstr_Mflo(tLo));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
+ /* 64HLto128(e1,e2) */
+ case Iop_64HLto128:
+ *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ return;
+
+ case Iop_DivModS64to64: {
+ HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS64to64);
+
+ addInstr(env, MIPSInstr_Div(syned, False, r_srcL, r_srcR));
+ addInstr(env, MIPSInstr_Mfhi(tHi));
+ addInstr(env, MIPSInstr_Mflo(tLo));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
+ case Iop_DivModU128to64: {
+ vassert(mode64);
+ HReg rHi1, rLo1;
+ iselInt128Expr(&rHi1, &rLo1, env, e->Iex.Binop.arg1);
+
+ HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ Bool syned = toBool(e->Iex.Binop.op == Iop_DivModS128to64);
+
+ addInstr(env, MIPSInstr_Div(syned, False, rLo1, r_srcR));
+ addInstr(env, MIPSInstr_Mfhi(tHi));
+ addInstr(env, MIPSInstr_Mflo(tLo));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
+ default:
+ break;
+ }
+ }
+ vex_printf("iselInt128Expr(mips64): No such tag(%u)\n", e->tag);
+ ppIRExpr(e);
+ vpanic("iselInt128Expr(mips64)");
+}
+
+/*---------------------------------------------------------*/
+/*--- ISEL: Integer expressions (64 bit) ---*/
+/*---------------------------------------------------------*/
+
+/* 32-bit mode ONLY. Compute a 64-bit value into the register
+ * pair HI, LO. HI and LO must not be changed by subsequent
+ * code emitted by the caller. */
+
+static void iselInt64Expr(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
+{
+ vassert(!env->mode64);
+ iselInt64Expr_wrk(rHi, rLo, env, e);
+ vassert(hregClass(*rHi) == HRcInt32);
+ vassert(hregIsVirtual(*rHi));
+ vassert(hregClass(*rLo) == HRcInt32);
+ vassert(hregIsVirtual(*rLo));
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static void iselInt64Expr_wrk(HReg * rHi, HReg * rLo, ISelEnv * env, IRExpr * e)
+{
+ vassert(e);
+ vassert(typeOfIRExpr(env->type_env, e) == Ity_I64);
+
+ /* read 64-bit IRTemp */
+ if (e->tag == Iex_RdTmp) {
+ lookupIRTemp64(rHi, rLo, env, e->Iex.RdTmp.tmp);
+ return;
+ }
+ /* 64-bit load */
+ if (e->tag == Iex_Load) {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ HReg r_addr = iselWordExpr_R(env, e->Iex.Load.addr);
+ addInstr(env, MIPSInstr_Load(4, tHi, MIPSAMode_IR(0, r_addr), mode64));
+ addInstr(env, MIPSInstr_Load(4, tLo, MIPSAMode_IR(4, r_addr), mode64));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
+ /* 64-bit literal */
+ if (e->tag == Iex_Const) {
+ ULong w64 = e->Iex.Const.con->Ico.U64;
+ UInt wHi = toUInt(w64 >> 32);
+ UInt wLo = toUInt(w64);
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ vassert(e->Iex.Const.con->tag == Ico_U64);
+
+ if (wLo == wHi) {
+ /* Save a precious Int register in this special case. */
+ addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo));
+ *rHi = tLo;
+ *rLo = tLo;
+ } else {
+ addInstr(env, MIPSInstr_LI(tHi, (ULong) wHi));
+ addInstr(env, MIPSInstr_LI(tLo, (ULong) wLo));
+ *rHi = tHi;
+ *rLo = tLo;
+ }
+
+ return;
+ }
+
+ /* 64-bit GET */
+ if (e->tag == Iex_Get) {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+
+ MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
+ GuestStatePointer(mode64));
+ addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
+ addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeInt(am_addr), mode64));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
+ /* 64-bit Mux0X */
+ if (e->tag == Iex_Mux0X) {
+ HReg expr0Lo, expr0Hi;
+ HReg exprXLo, exprXHi;
+ HReg tmpHi = newVRegI(env);
+ HReg tmpLo = newVRegI(env);
+ HReg tmp1Hi = newVRegI(env);
+ HReg tmp1Lo = newVRegI(env);
+ HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond);
+ HReg r_cond_neg = newVRegI(env);
+ HReg desLo = newVRegI(env);
+ HReg desHi = newVRegI(env);
+
+ /* expr0Hi:expr0Lo = expr0 */
+ /* exprXHi:exprXLo = exprX */
+ iselInt64Expr(&expr0Hi, &expr0Lo, env, e->Iex.Mux0X.expr0);
+ iselInt64Expr(&exprXHi, &exprXLo, env, e->Iex.Mux0X.exprX);
+
+ addInstr(env, MIPSInstr_Alu(Malu_AND, tmpLo, r_cond,
+ MIPSRH_Reg(exprXLo)));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, tmpHi, r_cond,
+ MIPSRH_Reg(exprXHi)));
+ addInstr(env, MIPSInstr_Alu(Malu_NOR, r_cond_neg, r_cond,
+ MIPSRH_Reg(r_cond)));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, tmp1Lo, r_cond_neg,
+ MIPSRH_Reg(exprXLo)));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, tmp1Hi, r_cond_neg,
+ MIPSRH_Reg(exprXHi)));
+ addInstr(env, MIPSInstr_Alu(Malu_ADD, desLo, tmpLo,
+ MIPSRH_Reg(tmp1Lo)));
+ addInstr(env, MIPSInstr_Alu(Malu_ADD, desHi, tmpHi,
+ MIPSRH_Reg(tmp1Hi)));
+ *rHi = desHi;
+ *rLo = desLo;
+ return;
+ }
+
+ /* --------- BINARY ops --------- */
+ if (e->tag == Iex_Binop) {
+ IROp op_binop = e->Iex.Binop.op;
+ switch (op_binop) {
+ /* 32 x 32 -> 64 multiply */
+ /* Add64 */
+ case Iop_Add64: {
+ HReg xLo, xHi, yLo, yHi;
+ HReg tHi = newVRegI(env);
+ HReg tLo = newVRegI(env);
+ iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
+ iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
+ addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, xHi, MIPSRH_Reg(yHi)));
+ addInstr(env, MIPSInstr_Alu(Malu_ADD, tLo, xLo, MIPSRH_Reg(yLo)));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+ case Iop_MullU32:
+ case Iop_MullS32: {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ HReg r_dst = newVRegI(env);
+ Bool syned = toBool(op_binop == Iop_MullS32);
+ HReg r_srcL = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
+
+ addInstr(env, MIPSInstr_Mul(syned/*Unsigned or Signed */ ,
+ True /*widen */ , True,
+ r_dst, r_srcL, r_srcR));
+ addInstr(env, MIPSInstr_Mfhi(tHi));
+ addInstr(env, MIPSInstr_Mflo(tLo));
+ *rHi = tHi;
+ *rLo = tLo;
+
+ return;
+ }
+ case Iop_DivModS64to32:
+ case Iop_DivModU64to32: {
+ HReg r_sHi, r_sLo;
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ Bool syned = toBool(op_binop == Iop_DivModS64to32);
+ HReg r_srcR = iselWordExpr_R(env, e->Iex.Binop.arg2);
+
+ iselInt64Expr(&r_sHi, &r_sLo, env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_Div(syned, True, r_sLo, r_srcR));
+ addInstr(env, MIPSInstr_Mfhi(tHi));
+ addInstr(env, MIPSInstr_Mflo(tLo));
+ *rHi = tHi;
+ *rLo = tLo;
+
+ return;
+ }
+
+ /* 32HLto64(e1,e2) */
+ case Iop_32HLto64:
+ *rHi = iselWordExpr_R(env, e->Iex.Binop.arg1);
+ *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
+
+ return;
+ /* Or64/And64/Xor64 */
+ case Iop_Or64:
+ case Iop_And64:
+ case Iop_Xor64: {
+ HReg xLo, xHi, yLo, yHi;
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ MIPSAluOp op = (op_binop == Iop_Or64) ? Malu_OR :
+ (op_binop == Iop_And64) ? Malu_AND : Malu_XOR;
+ iselInt64Expr(&xHi, &xLo, env, e->Iex.Binop.arg1);
+ iselInt64Expr(&yHi, &yLo, env, e->Iex.Binop.arg2);
+ addInstr(env, MIPSInstr_Alu(op, tHi, xHi, MIPSRH_Reg(yHi)));
+ addInstr(env, MIPSInstr_Alu(op, tLo, xLo, MIPSRH_Reg(yLo)));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ /* --------- UNARY ops --------- */
+ if (e->tag == Iex_Unop) {
+
+ switch (e->Iex.Unop.op) {
+ case Iop_1Sto64: {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ HReg tmp = newVRegI(env);
+
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, src,
+ MIPSRH_Imm(False, 31)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp, src,
+ MIPSRH_Imm(False, 31)));
+
+ addInstr(env, mk_iMOVds_RR(tHi, tmp));
+ addInstr(env, mk_iMOVds_RR(tLo, tmp));
+
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
+ /* 32Sto64(e) */
+ case Iop_32Sto64: {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env, mk_iMOVds_RR(tHi, src));
+ addInstr(env, mk_iMOVds_RR(tLo, src));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tHi, tHi,
+ MIPSRH_Imm(False, 31)));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
+ /* 32Uto64(e) */
+ case Iop_32Uto64: {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ HReg src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ addInstr(env, mk_iMOVds_RR(tLo, src));
+ addInstr(env, MIPSInstr_Alu(Malu_ADD, tHi, hregMIPS_GPR0(mode64),
+ MIPSRH_Reg(hregMIPS_GPR0(mode64))));
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
+ case Iop_CmpwNEZ64: {
+ HReg srcLo, srcHi;
+ HReg tmp1 = newVRegI(env);
+ HReg tmp2 = newVRegI(env);
+ /* srcHi:srcLo = arg */
+ iselInt64Expr(&srcHi, &srcLo, env, e->Iex.Unop.arg);
+ /* tmp1 = srcHi | srcLo */
+ addInstr(env, MIPSInstr_Alu(Malu_OR, tmp1, srcLo,
+ MIPSRH_Reg(srcHi)));
+ /* tmp2 = (tmp1 | -tmp1) >>s 31 */
+
+ addInstr(env, MIPSInstr_Alu(Malu_SUB, tmp2, hregMIPS_GPR0(mode64),
+ MIPSRH_Reg(tmp1)));
+
+ addInstr(env, MIPSInstr_Alu(Malu_OR, tmp2, tmp2, MIPSRH_Reg(tmp1)));
+ addInstr(env, MIPSInstr_Shft(Mshft_SRA, True, tmp2, tmp2,
+ MIPSRH_Imm(False, 31)));
+ *rHi = tmp2;
+ *rLo = tmp2;
+ return;
+
+ }
+ case Iop_ReinterpF64asI64: {
+ HReg tLo = newVRegI(env);
+ HReg tHi = newVRegI(env);
+ MIPSAMode *am_addr;
+ HReg fr_src = iselDblExpr(env, e->Iex.Unop.arg);
+
+ sub_from_sp(env, 16); // Move SP down 16 bytes
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ // store as F64
+ addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
+ am_addr));
+ // load as 2xI32
+ addInstr(env, MIPSInstr_Load(4, tLo, am_addr, mode64));
+ addInstr(env, MIPSInstr_Load(4, tHi, nextMIPSAModeFloat(am_addr),
+ mode64));
+
+ add_to_sp(env, 16); // Reset SP
+
+ *rHi = tHi;
+ *rLo = tLo;
+ return;
+ }
+
+ default:
+ vex_printf("UNARY: No such op: ");
+ ppIROp(e->Iex.Unop.op);
+ vex_printf("\n");
+ break;
+ }
+ }
+
+ vex_printf("iselInt64Expr(mips): No such tag(%u)\n", e->tag);
+ ppIRExpr(e);
+ vpanic("iselInt64Expr(mips)");
+}
+
+/*---------------------------------------------------------*/
+/*--- ISEL: Floating point expressions (32 bit) ---*/
+/*---------------------------------------------------------*/
+
+/* Nothing interesting here; really just wrappers for
+ 64-bit stuff. */
+
+static HReg iselFltExpr(ISelEnv * env, IRExpr * e)
+{
+ HReg r = iselFltExpr_wrk(env, e);
+ vassert(hregIsVirtual(r));
+ return r;
+}
+
+/* DO NOT CALL THIS DIRECTLY */
+static HReg iselFltExpr_wrk(ISelEnv * env, IRExpr * e)
+{
+ IRType ty = typeOfIRExpr(env->type_env, e);
+ vassert(ty == Ity_F32 || (ty == Ity_F64 && mode64));
+
+ if (e->tag == Iex_RdTmp) {
+ return lookupIRTemp(env, e->Iex.RdTmp.tmp);
+ }
+
+ if (e->tag == Iex_Load) {
+ MIPSAMode *am_addr;
+ HReg r_dst = newVRegF(env);
+ vassert(e->Iex.Load.ty == Ity_F32
+ || (e->Iex.Load.ty == Ity_F64 && mode64));
+ am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, r_dst, am_addr));
+ return r_dst;
+ }
+
+ if (e->tag == Iex_Get) {
+ HReg r_dst = newVRegF(env);
+ MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
+ GuestStatePointer(mode64));
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, r_dst, am_addr));
+ return r_dst;
+ }
+
+ if (e->tag == Iex_Unop) {
+ switch (e->Iex.Unop.op) {
+ case Iop_ReinterpI32asF32: {
+ MIPSAMode *am_addr;
+ HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ HReg r_dst = newVRegF(env);
+
+ sub_from_sp(env, 16); // Move SP down 16 bytes
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ // store as I32
+ addInstr(env, MIPSInstr_Store(4, am_addr, fr_src, mode64));
+
+ // load as Ity_F32
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, r_dst, am_addr));
+
+ add_to_sp(env, 16); // Reset SP
+ return r_dst;
+
+ }
+ case Iop_F32toF64: {
+ /* first arg is rounding mode; we ignore it. */
+ MIPSAMode *am_addr;
+ HReg src = iselFltExpr(env, e->Iex.Unop.arg);
+ HReg dst = newVRegF(env);
+
+ sub_from_sp(env, 16); // Move SP down 16 bytes
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ addInstr(env, MIPSInstr_Store(4,
+ MIPSAMode_IR(am_addr->Mam.IR.index + 4,
+ am_addr->Mam.IR.base),
+ hregMIPS_GPR0(mode64), mode64));
+ addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, src, am_addr));
+
+ // load as Ity_F32
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, dst, am_addr));
+ add_to_sp(env, 16); // Reset SP
+
+ return dst;
+ }
+ case Iop_ReinterpI64asF64:
+ {
+ vassert(mode64);
+ MIPSAMode *am_addr;
+ HReg fr_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ HReg r_dst = newVRegF(env);
+
+ sub_from_sp(env, 16); // Move SP down 16 bytes
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ // store as I32
+ addInstr(env, MIPSInstr_Store(8, am_addr, fr_src, mode64));
+
+ // load as Ity_F32
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
+
+ add_to_sp(env, 16); // Reset SP
+ return r_dst;
+ }
+ case Iop_AbsF32:
+ case Iop_AbsF64: {
+ Bool sz32 = e->Iex.Unop.op == Iop_AbsF32;
+ HReg src = iselFltExpr(env, e->Iex.Unop.arg);
+ HReg dst = newVRegF(env);
+ addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_ABSS : Mfp_ABSD, dst, src));
+ return dst;
+ }
+ case Iop_NegF32:
+ case Iop_NegF64: {
+ Bool sz32 = e->Iex.Unop.op == Iop_NegF32;
+ HReg src = iselFltExpr(env, e->Iex.Unop.arg);
+ HReg dst = newVRegF(env);
+ addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_NEGS : Mfp_NEGD, dst, src));
+ return dst;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (e->tag == Iex_Triop) {
+ switch (e->Iex.Triop.details->op) {
+ case Iop_DivF32:
+ case Iop_DivF64:
+ case Iop_MulF32:
+ case Iop_MulF64:
+ case Iop_AddF32:
+ case Iop_AddF64:
+ case Iop_SubF32:
+ case Iop_SubF64: {
+ MIPSFpOp op = 0;
+ /*INVALID*/ HReg argL = iselFltExpr(env, e->Iex.Triop.details->arg2);
+ HReg argR = iselFltExpr(env, e->Iex.Triop.details->arg3);
+ HReg dst = newVRegF(env);
+ switch (e->Iex.Triop.details->op) {
+ case Iop_DivF32:
+ op = Mfp_DIVS;
+ break;
+ case Iop_MulF32:
+ op = Mfp_MULS;
+ break;
+ case Iop_AddF32:
+ op = Mfp_ADDS;
+ break;
+ case Iop_SubF32:
+ op = Mfp_SUBS;
+ break;
+ default:
+ vassert(0);
+ }
+ addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR));
+ return dst;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (e->tag == Iex_Binop) {
+ switch (e->Iex.Binop.op) {
+ case Iop_F64toF32: {
+ HReg valD = iselDblExpr(env, e->Iex.Binop.arg2);
+ HReg valS = newVRegF(env);
+
+ set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSD, valS, valD));
+ set_MIPS_rounding_default(env);
+ return valS;
+ }
+
+ case Iop_RoundF32toInt: {
+ HReg valS = newVRegF(env);
+ HReg valF = iselFltExpr(env, e->Iex.Binop.arg2);
+
+ set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_FpConvert(Mfp_CVTWS, valS, valF));
+
+ set_MIPS_rounding_default(env);
+ return valS;
+ }
+
+ case Iop_I32StoF32: {
+ HReg r_dst = newVRegF(env);
+
+ MIPSAMode *am_addr;
+ HReg fr_src = iselWordExpr_R(env, e->Iex.Binop.arg2);
+ HReg tmp = newVRegF(env);
+
+ sub_from_sp(env, 16); // Move SP down 16 bytes
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ // store as I32
+ addInstr(env, MIPSInstr_Store(4, am_addr, fr_src, mode64));
+
+ // load as Ity_F32
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, tmp, am_addr));
+
+ add_to_sp(env, 16); // Reset SP
+
+ set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_FpConvert(Mfp_CVTSW, r_dst, tmp));
+ set_MIPS_rounding_default(env);
+
+ return r_dst;
+ }
+
+ case Iop_SqrtF32:
+ case Iop_SqrtF64: {
+ /* first arg is rounding mode; we ignore it. */
+ Bool sz32 = e->Iex.Binop.op == Iop_SqrtF32;
+ HReg src = iselFltExpr(env, e->Iex.Binop.arg2);
+ HReg dst = newVRegF(env);
+ set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_FpUnary(sz32 ? Mfp_SQRTS : Mfp_SQRTD, dst,
+ src));
+ set_MIPS_rounding_default(env);
+ return dst;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_TruncF64asF32) {
+ /* This is quite subtle. The only way to do the relevant
+ truncation is to do a single-precision store and then a
+ double precision load to get it back into a register. The
+ problem is, if the data is then written to memory a second
+ time, as in
+
+ STbe(...) = TruncF64asF32(...)
+
+ then will the second truncation further alter the value? The
+ answer is no: flds (as generated here) followed by fsts
+ (generated for the STbe) is the identity function on 32-bit
+ floats, so we are safe.
+
+ Another upshot of this is that if iselStmt can see the
+ entirety of
+
+ STbe(...) = TruncF64asF32(arg)
+
+ then it can short circuit having to deal with TruncF64asF32
+ individually; instead just compute arg into a 64-bit FP
+ register and do 'fsts' (since that itself does the
+ truncation).
+
+ We generate pretty poor code here (should be ok both for
+ 32-bit and 64-bit mode); but it is expected that for the most
+ part the latter optimisation will apply and hence this code
+ will not often be used.
+ */
+ HReg fsrc = iselDblExpr(env, e->Iex.Unop.arg);
+ HReg fdst = newVRegF(env);
+ MIPSAMode *zero_r1 = MIPSAMode_IR(0, StackPointer(mode64));
+
+ sub_from_sp(env, 16);
+ // store as F32, hence truncating
+ addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fsrc, zero_r1));
+ // and reload. Good huh?! (sigh)
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, fdst, zero_r1));
+ add_to_sp(env, 16);
+ return fdst;
+ }
+
+ vex_printf("iselFltExpr(mips): No such tag(0x%x)\n", e->tag);
+ ppIRExpr(e);
+ vpanic("iselFltExpr_wrk(mips)");
+}
+
+static HReg iselDblExpr(ISelEnv * env, IRExpr * e)
+{
+ HReg r = iselDblExpr_wrk(env, e);
+ vassert(hregClass(r) == HRcFlt64);
+ vassert(hregIsVirtual(r));
+ return r;
+}
+
+/* DO NOT CALL THIS DIRECTLY */
+static HReg iselDblExpr_wrk(ISelEnv * env, IRExpr * e)
+{
+ IRType ty = typeOfIRExpr(env->type_env, e);
+ vassert(e);
+ vassert(ty == Ity_F64);
+
+ if (e->tag == Iex_RdTmp) {
+ return lookupIRTemp(env, e->Iex.RdTmp.tmp);
+ }
+
+ /* --------- LOAD --------- */
+ if (e->tag == Iex_Load && e->Iex.Load.end == Iend_LE) {
+ HReg r_dst = newVRegD(env);
+ MIPSAMode *am_addr;
+ vassert(e->Iex.Load.ty == Ity_F64);
+ am_addr = iselWordExpr_AMode(env, e->Iex.Load.addr, ty);
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
+ return r_dst;
+ }
+
+ /* --------- GET --------- */
+ if (e->tag == Iex_Get) {
+
+ HReg r_dst = newVRegD(env);
+ MIPSAMode *am_addr = MIPSAMode_IR(e->Iex.Get.offset,
+ GuestStatePointer(mode64));
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
+ return r_dst;
+ }
+
+ if (e->tag == Iex_Unop) {
+ MIPSFpOp fpop = Mfp_INVALID;
+ switch (e->Iex.Unop.op) {
+ case Iop_NegF64:
+ fpop = Mfp_NEGD;
+ break;
+ case Iop_AbsF64:
+ fpop = Mfp_ABSD;
+ break;
+ case Iop_F32toF64: {
+ HReg src = iselFltExpr(env, e->Iex.Unop.arg);
+ HReg dst = newVRegD(env);
+
+ HReg irrm = newVRegI(env);
+
+ MIPSAMode *am_addr1 = MIPSAMode_IR(284, GuestStatePointer(mode64));
+
+ addInstr(env, MIPSInstr_Load(4, irrm, am_addr1, mode64));
+
+ // set new FCSR
+ HReg tmp = newVRegI(env);
+ HReg fcsr_old = newVRegI(env);
+ MIPSAMode *am_addr;
+
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm,
+ MIPSRH_Imm(False, 1)));
+ addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp)));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, irrm, tmp,
+ MIPSRH_Imm(False, 3)));
+ /* save old value of FCSR */
+ addInstr(env, MIPSInstr_MfFCSR(fcsr_old));
+ sub_from_sp(env, 8); // Move SP down 4 bytes
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ //store old FCSR to stack
+ addInstr(env, MIPSInstr_Store(4, am_addr, fcsr_old, mode64));
+
+ //set new value of FCSR
+ addInstr(env, MIPSInstr_MtFCSR(irrm));
+
+ //set_MIPS_rounding_mode(env, e->Iex.Binop.arg1);
+ addInstr(env, MIPSInstr_FpUnary(Mfp_CVTD, dst, src));
+ set_MIPS_rounding_default(env);
+ return dst;
+ }
+ case Iop_ReinterpI64asF64: {
+ HReg Hi;
+ HReg Lo;
+ HReg dst = newVRegD(env);
+
+ iselInt64Expr(&Hi, &Lo, env, e->Iex.Unop.arg);
+
+ dst = mk_LoadRR32toFPR(env, Hi, Lo); // 2*I32 -> F64
+ return dst;
+ }
+ case Iop_I32StoF64: {
+ HReg dst = newVRegD(env);
+ HReg tmp1 = newVRegF(env);
+ HReg r_src = iselWordExpr_R(env, e->Iex.Unop.arg);
+ MIPSAMode *am_addr;
+ sub_from_sp(env, 16); // Move SP down 16 bytes
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ // store as I32
+ addInstr(env, MIPSInstr_Store(4, am_addr, r_src, mode64));
+
+ // load as Ity_F32
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 4, tmp1, am_addr));
+
+ add_to_sp(env, 16); // Reset SP
+
+ HReg irrm = newVRegI(env);
+
+ MIPSAMode *am_addr1 = MIPSAMode_IR(284, GuestStatePointer(mode64));
+
+ addInstr(env, MIPSInstr_Load(4, irrm, am_addr1, mode64));
+
+ //set rounding mode
+ HReg tmp = newVRegI(env);
+ HReg fcsr_old = newVRegI(env);
+
+ addInstr(env, MIPSInstr_Shft(Mshft_SLL, True, tmp, irrm,
+ MIPSRH_Imm(False, 1)));
+ addInstr(env, MIPSInstr_Alu(Malu_XOR, tmp, irrm, MIPSRH_Reg(tmp)));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, irrm, tmp,
+ MIPSRH_Imm(False, 3)));
+ /* save old value of FCSR */
+ addInstr(env, MIPSInstr_MfFCSR(fcsr_old));
+ sub_from_sp(env, 8); // Move SP down 4 bytes
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ //store old FCSR to stack
+ addInstr(env, MIPSInstr_Store(4, am_addr, fcsr_old, mode64));
+
+ //set new value of FCSR
+ addInstr(env, MIPSInstr_MtFCSR(irrm));
+
+ // and do convert
+ addInstr(env, MIPSInstr_FpConvert(Mfp_CVTDW, dst, tmp1));
+ set_MIPS_rounding_default(env);
+
+ return dst;
+ }
+ default:
+ break;
+ }
+
+ if (fpop != Mfp_INVALID) {
+ HReg src = iselDblExpr(env, e->Iex.Unop.arg);
+ HReg dst = newVRegD(env);
+ addInstr(env, MIPSInstr_FpUnary(fpop, dst, src));
+ return dst;
+ }
+ }
+
+ if (e->tag == Iex_Binop) {
+ switch (e->Iex.Binop.op) {
+ case Iop_RoundF64toInt: {
+ HReg valD = iselDblExpr(env, e->Iex.Binop.arg2);
+ MIPSRH *fmt = iselWordExpr_RH(env, False, e->Iex.Binop.arg1);
+ HReg valD1 = newVRegD(env);
+
+ if (fmt->Mrh.Imm.imm16 == 0x3)
+ addInstr(env, MIPSInstr_FpConvert(Mfp_TRULD, valD1, valD));
+ else if (fmt->Mrh.Imm.imm16 == 0x2)
+ addInstr(env, MIPSInstr_FpConvert(Mfp_CEILLD, valD1, valD));
+ else
+ vassert(0);
+ return valD1;
+ }
+
+ case Iop_SqrtF64:{
+ /* first arg is rounding mode; we ignore it. */
+ HReg src = iselDblExpr(env, e->Iex.Binop.arg2);
+ HReg dst = newVRegD(env);
+ addInstr(env, MIPSInstr_FpUnary(Mfp_SQRTD, dst, src));
+ return dst;
+ }
+
+ default:
+ break;
+
+ }
+ }
+
+ if (e->tag == Iex_Triop) {
+ switch (e->Iex.Triop.details->op) {
+ case Iop_DivF64:
+ case Iop_DivF32:
+ case Iop_MulF64:
+ case Iop_AddF64:
+ case Iop_SubF64: {
+ MIPSFpOp op = 0;
+ /*INVALID*/ HReg argL = iselDblExpr(env, e->Iex.Triop.details->arg2);
+ HReg argR = iselDblExpr(env, e->Iex.Triop.details->arg3);
+ HReg dst = newVRegD(env);
+ switch (e->Iex.Triop.details->op) {
+ case Iop_DivF64:
+ op = Mfp_DIVD;
+ break;
+ case Iop_MulF64:
+ op = Mfp_MULD;
+ break;
+ case Iop_AddF64:
+ op = Mfp_ADDD;
+ break;
+ case Iop_SubF64:
+ op = Mfp_SUBD;
+ break;
+ default:
+ vassert(0);
+ }
+ addInstr(env, MIPSInstr_FpBinary(op, dst, argL, argR));
+ return dst;
+ }
+ default:
+ break;
+ }
+ }
+
+ /* --------- MULTIPLEX --------- */
+ if (e->tag == Iex_Mux0X) {
+ if (ty == Ity_F64
+ && typeOfIRExpr(env->type_env, e->Iex.Mux0X.cond) == Ity_I8) {
+ HReg r0 = iselDblExpr(env, e->Iex.Mux0X.expr0);
+ HReg rX = iselDblExpr(env, e->Iex.Mux0X.exprX);
+ HReg r_cond = iselWordExpr_R(env, e->Iex.Mux0X.cond);
+ HReg r_cond_neg = newVRegI(env);
+ HReg r_dst = newVRegD(env);
+ HReg r_tmp_lo = newVRegI(env);
+ HReg r_tmp_hi = newVRegI(env);
+ HReg r_tmp1_lo = newVRegI(env);
+ HReg r_tmp1_hi = newVRegI(env);
+ HReg r_r0_lo = newVRegI(env);
+ HReg r_r0_hi = newVRegI(env);
+ HReg r_rX_lo = newVRegI(env);
+ HReg r_rX_hi = newVRegI(env);
+ HReg r_dst_lo = newVRegI(env);
+ HReg r_dst_hi = newVRegI(env);
+
+ sub_from_sp(env, 16); // Move SP down 16 bytes
+ MIPSAMode *am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ // store as Ity_F64
+ addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, r0, am_addr));
+
+ // load as 2xI32
+ addInstr(env, MIPSInstr_Load(4, r_r0_lo, am_addr, mode64));
+ addInstr(env, MIPSInstr_Load(4, r_r0_hi, nextMIPSAModeFloat(am_addr),
+ mode64));
+
+ add_to_sp(env, 16); // Reset SP
+
+ addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp_lo, r_cond,
+ MIPSRH_Reg(r_r0_lo)));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp_hi, r_cond,
+ MIPSRH_Reg(r_r0_hi)));
+
+ addInstr(env, MIPSInstr_Alu(Malu_NOR, r_cond_neg, r_cond,
+ MIPSRH_Reg(r_cond)));
+
+ sub_from_sp(env, 16); // Move SP down 16 bytes
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ // store as Ity_F64
+ addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, rX, am_addr));
+
+ // load as 2xI32
+ addInstr(env, MIPSInstr_Load(4, r_rX_lo, am_addr, mode64));
+ addInstr(env, MIPSInstr_Load(4, r_rX_hi, nextMIPSAModeFloat(am_addr),
+ mode64));
+
+ add_to_sp(env, 16); // Reset SP
+
+ addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp1_lo, r_cond_neg,
+ MIPSRH_Reg(r_rX_lo)));
+ addInstr(env, MIPSInstr_Alu(Malu_AND, r_tmp1_hi, r_cond_neg,
+ MIPSRH_Reg(r_rX_hi)));
+
+ addInstr(env, MIPSInstr_Alu(Malu_ADD, r_dst_lo, r_tmp_lo,
+ MIPSRH_Reg(r_tmp1_lo)));
+ addInstr(env, MIPSInstr_Alu(Malu_ADD, r_dst_hi, r_tmp_hi,
+ MIPSRH_Reg(r_tmp1_hi)));
+
+ sub_from_sp(env, 16); // Move SP down 16 bytes
+ am_addr = MIPSAMode_IR(0, StackPointer(mode64));
+
+ // store as I32
+ addInstr(env, MIPSInstr_Store(4, am_addr, r_dst_lo, mode64));
+ addInstr(env, MIPSInstr_Store(4, nextMIPSAModeFloat(am_addr),
+ r_dst_hi, mode64));
+
+ // load as Ity_F32
+ addInstr(env, MIPSInstr_FpLdSt(True /*load */ , 8, r_dst, am_addr));
+
+ add_to_sp(env, 16); // Reset SP
+
+ return r_dst;
+ }
+ }
+
+ vex_printf("iselDblExpr(mips): No such tag(%u)\n", e->tag);
+ ppIRExpr(e);
+ vpanic("iselDblExpr_wrk(mips)");
+}
+
+/*---------------------------------------------------------*/
+/*--- ISEL: Statements ---*/
+/*---------------------------------------------------------*/
+
+static void iselStmt(ISelEnv * env, IRStmt * stmt)
+{
+ if (vex_traceflags & VEX_TRACE_VCODE) {
+ vex_printf("\n-- ");
+
+ ppIRStmt(stmt);
+ vex_printf("\n");
+ }
+
+ switch (stmt->tag) {
+ /* --------- STORE --------- */
+ case Ist_Store: {
+ MIPSAMode *am_addr;
+ IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
+
+ /*constructs addressing mode from address provided */
+ am_addr = iselWordExpr_AMode(env, stmt->Ist.Store.addr, tyd);
+
+ if (tyd == Ity_I8 || tyd == Ity_I16 || tyd == Ity_I32 ||
+ (mode64 && (tyd == Ity_I64))) {
+ HReg r_src = iselWordExpr_R(env, stmt->Ist.Store.data);
+ addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(tyd)),
+ am_addr, r_src, mode64));
+ return;
+ }
+ if (!mode64 && (tyd == Ity_I64)) {
+ HReg vHi, vLo;
+ HReg r_addr = iselWordExpr_R(env, stmt->Ist.Store.addr);
+
+ iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Store.data);
+
+ addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
+ MIPSAMode_IR(0, r_addr), vHi, mode64));
+ addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
+ MIPSAMode_IR(4, r_addr), vLo, mode64));
+ return;
+ }
+ if (tyd == Ity_F32) {
+ HReg fr_src = iselFltExpr(env, stmt->Ist.Store.data);
+ addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src,
+ am_addr));
+ return;
+ }
+
+ break;
+ }
+
+ /* --------- PUT --------- */
+ case Ist_Put: {
+ IRType ty = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
+
+ if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 ||
+ (ty == Ity_I64 && mode64)) {
+ HReg r_src = iselWordExpr_R(env, stmt->Ist.Put.data);
+ MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
+ GuestStatePointer(mode64));
+ addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(ty)),
+ am_addr, r_src, mode64));
+ return;
+ }
+
+ if (ty == Ity_I64 && !mode64) {
+ HReg vHi, vLo;
+ MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
+ GuestStatePointer(mode64));
+ MIPSAMode *am_addr4 = MIPSAMode_IR(stmt->Ist.Put.offset + 4,
+ GuestStatePointer(mode64));
+ iselInt64Expr(&vHi, &vLo, env, stmt->Ist.Put.data);
+ addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
+ am_addr, vLo, mode64));
+ addInstr(env, MIPSInstr_Store(toUChar(sizeofIRType(Ity_I32)),
+ am_addr4, vHi, mode64));
+ return;
+
+ }
+
+ if (ty == Ity_F32) {
+ HReg fr_src = iselFltExpr(env, stmt->Ist.Put.data);
+ MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
+ GuestStatePointer(mode64));
+ addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 4, fr_src,
+ am_addr));
+ return;
+ }
+
+ if (ty == Ity_F64) {
+ HReg fr_src;
+ fr_src = iselDblExpr(env, stmt->Ist.Put.data);
+ MIPSAMode *am_addr = MIPSAMode_IR(stmt->Ist.Put.offset,
+ GuestStatePointer(mode64));
+ addInstr(env, MIPSInstr_FpLdSt(False /*store */ , 8, fr_src,
+ am_addr));
+ return;
+ }
+ break;
+ }
+
+ /* --------- TMP --------- */
+ case Ist_WrTmp: {
+ IRTemp tmp = stmt->Ist.WrTmp.tmp;
+ IRType ty = typeOfIRTemp(env->type_env, tmp);
+
+ if (ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32 || ty == Ity_I1) {
+ HReg r_dst = lookupIRTemp(env, tmp);
+ HReg r_src = iselWordExpr_R(env, stmt->Ist.WrTmp.data);
+ addInstr(env, mk_iMOVds_RR(r_dst, r_src));
+ return;
+ }
+
+ if (ty == Ity_I64) {
+ HReg rHi, rLo, dstHi, dstLo;
+ iselInt64Expr(&rHi, &rLo, env, stmt->Ist.WrTmp.data);
+ lookupIRTemp64(&dstHi, &dstLo, env, tmp);
+ addInstr(env, mk_iMOVds_RR(dstHi, rHi));
+ addInstr(env, mk_iMOVds_RR(dstLo, rLo));
+ return;
+ }
+
+ if (ty == Ity_F32) {
+ HReg fr_dst = lookupIRTemp(env, tmp);
+ HReg fr_src = iselFltExpr(env, stmt->Ist.WrTmp.data);
+ addInstr(env, MIPSInstr_FpUnary(Mfp_MOVS, fr_dst, fr_src));
+ return;
+ }
+
+ if (ty == Ity_F64) {
+ HReg src = iselDblExpr(env, stmt->Ist.WrTmp.data);
+ HReg dst = lookupIRTemp(env, tmp);
+ addInstr(env, MIPSInstr_FpUnary(Mfp_MOVD, dst, src));
+ return;
+ }
+ break;
+ }
+
+ /* --------- Call to DIRTY helper --------- */
+ case Ist_Dirty: {
+ IRType retty;
+ IRDirty *d = stmt->Ist.Dirty.details;
+ Bool passBBP = False;
+
+ if (d->nFxState == 0)
+ vassert(!d->needsBBP);
+ passBBP = toBool(d->nFxState > 0 && d->needsBBP);
+
+ /* Marshal args, do the call, clear stack. */
+ doHelperCall(env, passBBP, d->guard, d->cee, d->args);
+
+ /* Now figure out what to do with the returned value, if any. */
+ if (d->tmp == IRTemp_INVALID)
+ /* No return value. Nothing to do. */
+ return;
+
+ retty = typeOfIRTemp(env->type_env, d->tmp);
+ if (retty == Ity_I64 && !mode64) {
+ vex_printf
+ ("Dirty! Return 64 bits. Not implemented (yet!)\n");
+ return;
+ }
+ if (retty == Ity_I8 || retty == Ity_I16 || retty == Ity_I32
+ || (retty == Ity_I64 && mode64)) {
+ /* The returned value is in %r2. Park it in the register
+ associated with tmp. */
+ HReg r_dst = lookupIRTemp(env, d->tmp);
+ addInstr(env, mk_iMOVds_RR(r_dst, hregMIPS_GPR2(mode64)));
+ return;
+ }
+ break;
+ }
+
+ /* --------- Load Linked or Store Conditional --------- */
+ case Ist_LLSC: {
+ //Temporary solution; this need to be rewritten again for MIPS.
+ //On MIPS you can not read from address that is locked with LL before SC.
+ // If you read from address that is locked than SC will fall.
+ IRTemp res = stmt->Ist.LLSC.result;
+ IRType tyRes = typeOfIRTemp(env->type_env, res);
+ IRType tyAddr = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.addr);
+
+ if (!mode64 && (tyAddr != Ity_I32))
+ goto stmt_fail;
+
+ if (stmt->Ist.LLSC.storedata == NULL) {
+ /* LL */
+ MIPSAMode *r_addr;
+ /*constructs addressing mode from address provided */
+ r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr);
+
+ HReg r_dst = lookupIRTemp(env, res);
+ if (tyRes == Ity_I32) {
+ addInstr(env, MIPSInstr_Load(4, r_dst, r_addr, mode64));
+ return;
+ } else if (tyRes == Ity_I64 && mode64) {
+ addInstr(env, MIPSInstr_Load(8, r_dst, r_addr, mode64));
+ return;
+ }
+ /* fallthru */ ;
+ } else {
+ /* SC */
+ MIPSAMode *r_addr;
+ r_addr = iselWordExpr_AMode(env, stmt->Ist.LLSC.addr, tyAddr);
+ HReg r_src = iselWordExpr_R(env, stmt->Ist.LLSC.storedata);
+ HReg r_dst = lookupIRTemp(env, res);
+ IRType tyData = typeOfIRExpr(env->type_env,
+ stmt->Ist.LLSC.storedata);
+
+ if (tyData == Ity_I32) {
+ addInstr(env, MIPSInstr_Store(4, r_addr, r_src, mode64));
+ addInstr(env, MIPSInstr_LI(r_dst, 0x1));
+ return;
+ } else if (tyData == Ity_I64 && mode64) {
+ addInstr(env, MIPSInstr_Store(8, r_addr, r_src, mode64));
+ addInstr(env, MIPSInstr_LI(r_dst, 0x1));
+ return;
+ }
+ /* fallthru */
+ }
+ goto stmt_fail;
+ /*NOTREACHED*/}
+
+ /* --------- INSTR MARK --------- */
+ /* Doesn't generate any executable code ... */
+ case Ist_IMark:
+ return;
+
+ /* --------- ABI HINT --------- */
+ /* These have no meaning (denotation in the IR) and so we ignore
+ them ... if any actually made it this far. */
+ case Ist_AbiHint:
+ return;
+
+ /* --------- NO-OP --------- */
+ /* Fairly self-explanatory, wouldn't you say? */
+ case Ist_NoOp:
+ return;
+
+ /* --------- EXIT --------- */
+ case Ist_Exit: {
+ IRConst* dst = stmt->Ist.Exit.dst;
+ if (!mode64 && dst->tag != Ico_U32)
+ vpanic("iselStmt(mips32): Ist_Exit: dst is not a 32-bit value");
+ if (mode64 && dst->tag != Ico_U64)
+ vpanic("iselStmt(mips64): Ist_Exit: dst is not a 64-bit value");
+
+ MIPSCondCode cc = iselCondCode(env, stmt->Ist.Exit.guard);
+ MIPSAMode* amPC = MIPSAMode_IR(stmt->Ist.Exit.offsIP,
+ hregMIPS_GPR10(mode64));
+
+ /* Case: boring transfer to known address */
+ if (stmt->Ist.Exit.jk == Ijk_Boring
+ || stmt->Ist.Exit.jk == Ijk_Call
+ /* || stmt->Ist.Exit.jk == Ijk_Ret */) {
+ if (env->chainingAllowed) {
+ /* .. almost always true .. */
+ /* Skip the event check at the dst if this is a forwards
+ edge. */
+ Bool toFastEP
+ = mode64
+ ? (((Addr64)stmt->Ist.Exit.dst->Ico.U64) > (Addr64)env->max_ga)
+ : (((Addr32)stmt->Ist.Exit.dst->Ico.U32) > (Addr32)env->max_ga);
+ if (0) vex_printf("%s", toFastEP ? "Y" : ",");
+ addInstr(env, MIPSInstr_XDirect(
+ mode64 ? (Addr64)stmt->Ist.Exit.dst->Ico.U64
+ : (Addr64)stmt->Ist.Exit.dst->Ico.U32,
+ amPC, cc, toFastEP));
+ } else {
+ /* .. very occasionally .. */
+ /* We can't use chaining, so ask for an assisted transfer,
+ as that's the only alternative that is allowable. */
+ HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
+ addInstr(env, MIPSInstr_XAssisted(r, amPC, cc, Ijk_Boring));
+ }
+ return;
+ }
+
+ /* Case: assisted transfer to arbitrary address */
+ switch (stmt->Ist.Exit.jk) {
+ /* Keep this list in sync with that in iselNext below */
+ case Ijk_ClientReq:
+ case Ijk_EmFail:
+ case Ijk_EmWarn:
+ case Ijk_NoDecode:
+ case Ijk_NoRedir:
+ case Ijk_SigBUS:
+ case Ijk_SigTRAP:
+ case Ijk_Sys_syscall:
+ case Ijk_TInval:
+ {
+ HReg r = iselWordExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
+ addInstr(env, MIPSInstr_XAssisted(r, amPC, cc,
+ stmt->Ist.Exit.jk));
+ return;
+ }
+ default:
+ break;
+ }
+
+ /* Do we ever expect to see any other kind? */
+ goto stmt_fail;
+ }
+
+ default:
+ break;
+ }
+
+ stmt_fail:
+ vex_printf("stmt_fail tag: 0x%x\n", stmt->tag);
+ ppIRStmt(stmt);
+ vpanic("iselStmt:\n");
+}
+
+/*---------------------------------------------------------*/
+/*--- ISEL: Basic block terminators (Nexts) ---*/
+/*---------------------------------------------------------*/
+
+static void iselNext ( ISelEnv* env,
+ IRExpr* next, IRJumpKind jk, Int offsIP )
+{
+ if (vex_traceflags & VEX_TRACE_VCODE) {
+ vex_printf( "\n-- PUT(%d) = ", offsIP);
+ ppIRExpr( next );
+ vex_printf( "; exit-");
+ ppIRJumpKind(jk);
+ vex_printf( "\n");
+ }
+
+ /* Case: boring transfer to known address */
+ if (next->tag == Iex_Const) {
+ IRConst* cdst = next->Iex.Const.con;
+ vassert(cdst->tag == (env->mode64 ? Ico_U64 :Ico_U32));
+ if (jk == Ijk_Boring || jk == Ijk_Call) {
+ /* Boring transfer to known address */
+ MIPSAMode* amPC = MIPSAMode_IR(offsIP, hregMIPS_GPR10(env->mode64));
+ if (env->chainingAllowed) {
+ /* .. almost always true .. */
+ /* Skip the event check at the dst if this is a forwards
+ edge. */
+ Bool toFastEP
+ = env->mode64
+ ? (((Addr64)cdst->Ico.U64) > (Addr64)env->max_ga)
+ : (((Addr32)cdst->Ico.U32) > (Addr32)env->max_ga);
+ if (0) vex_printf("%s", toFastEP ? "X" : ".");
+ addInstr(env, MIPSInstr_XDirect(
+ env->mode64 ? (Addr64)cdst->Ico.U64
+ : (Addr64)cdst->Ico.U32,
+ amPC, MIPScc_AL, toFastEP));
+ } else {
+ /* .. very occasionally .. */
+ /* We can't use chaining, so ask for an assisted transfer,
+ as that's the only alternative that is allowable. */
+ HReg r = iselWordExpr_R(env, next);
+ addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL,
+ Ijk_Boring));
+ }
+ return;
+ }
+ }
+
+ /* Case: call/return (==boring) transfer to any address */
+ switch (jk) {
+ case Ijk_Boring: case Ijk_Ret: case Ijk_Call: {
+
+ HReg r = iselWordExpr_R(env, next);
+ MIPSAMode* amPC = MIPSAMode_IR(offsIP, hregMIPS_GPR10(env->mode64));
+ if (env->chainingAllowed) {
+ addInstr(env, MIPSInstr_XIndir(r, amPC, MIPScc_AL));
+ } else {
+ addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL,
+ Ijk_Boring));
+ }
+ return;
+ }
+ default:
+ break;
+ }
+
+ /* Case: assisted transfer to arbitrary address */
+ switch (jk) {
+ /* Keep this list in sync with that for Ist_Exit above */
+ case Ijk_ClientReq:
+ case Ijk_EmFail:
+ case Ijk_EmWarn:
+ case Ijk_NoDecode:
+ case Ijk_NoRedir:
+ case Ijk_SigBUS:
+ case Ijk_SigTRAP:
+ case Ijk_Sys_syscall:
+ case Ijk_TInval: {
+ HReg r = iselWordExpr_R(env, next);
+ MIPSAMode* amPC = MIPSAMode_IR(offsIP, hregMIPS_GPR10(env->mode64));
+ addInstr(env, MIPSInstr_XAssisted(r, amPC, MIPScc_AL, jk));
+ return;
+ }
+ default:
+ break;
+ }
+
+ vex_printf( "\n-- PUT(%d) = ", offsIP);
+ ppIRExpr( next );
+ vex_printf( "; exit-");
+ ppIRJumpKind(jk);
+ vex_printf( "\n");
+ vassert(0); // are we expecting any other kind?
+}
+
+/*---------------------------------------------------------*/
+/*--- Insn selector top-level ---*/
+/*---------------------------------------------------------*/
+
+/* Translate an entire BB to mips code. */
+HInstrArray *iselSB_MIPS ( IRSB* bb,
+ VexArch arch_host,
+ VexArchInfo* archinfo_host,
+ VexAbiInfo* vbi,
+ Int offs_Host_EvC_Counter,
+ Int offs_Host_EvC_FailAddr,
+ Bool chainingAllowed,
+ Bool addProfInc,
+ Addr64 max_ga )
+{
+ Int i, j;
+ HReg hreg, hregHI;
+ ISelEnv* env;
+ UInt hwcaps_host = archinfo_host->hwcaps;
+ MIPSAMode *amCounter, *amFailAddr;
+
+ /* sanity ... */
+ vassert(arch_host == VexArchMIPS32);
+ vassert(VEX_PRID_COMP_MIPS == hwcaps_host
+ || VEX_PRID_COMP_BROADCOM == hwcaps_host);
+
+ mode64 = arch_host != VexArchMIPS32;
+
+ /* Make up an initial environment to use. */
+ env = LibVEX_Alloc(sizeof(ISelEnv));
+ env->vreg_ctr = 0;
+ env->mode64 = mode64;
+
+ /* Set up output code array. */
+ env->code = newHInstrArray();
+
+ /* Copy BB's type env. */
+ env->type_env = bb->tyenv;
+
+ /* Make up an IRTemp -> virtual HReg mapping. This doesn't
+ change as we go along. */
+ env->n_vregmap = bb->tyenv->types_used;
+ env->vregmap = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
+ env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
+
+ /* and finally ... */
+ env->hwcaps = hwcaps_host;
+ env->chainingAllowed = chainingAllowed;
+ env->hwcaps = hwcaps_host;
+ env->max_ga = max_ga;
+
+ /* For each IR temporary, allocate a suitably-kinded virtual
+ register. */
+ j = 0;
+ for (i = 0; i < env->n_vregmap; i++) {
+ hregHI = hreg = INVALID_HREG;
+ switch (bb->tyenv->types[i]) {
+ case Ity_I1:
+ case Ity_I8:
+ case Ity_I16:
+ case Ity_I32: {
+ hreg = mkHReg(j++, HRcInt32, True);
+ break;
+ }
+ case Ity_I64: {
+ hreg = mkHReg(j++, HRcInt32, True);
+ hregHI = mkHReg(j++, HRcInt32, True);
+ break;
+ }
+ case Ity_I128:
+ vassert(mode64);
+ hreg = mkHReg(j++, HRcInt64, True);
+ hregHI = mkHReg(j++, HRcInt64, True);
+ break;
+ case Ity_F32: {
+ hreg = mkHReg(j++, HRcFlt32, True);
+ break;
+ }
+ case Ity_F64:
+ hreg = mkHReg(j++, HRcFlt64, True);
+ break;
+ default:
+ ppIRType(bb->tyenv->types[i]);
+ vpanic("iselBB(mips): IRTemp type");
+ }
+ env->vregmap[i] = hreg;
+ env->vregmapHI[i] = hregHI;
+ }
+ env->vreg_ctr = j;
+
+ /* The very first instruction must be an event check. */
+ amCounter = MIPSAMode_IR(offs_Host_EvC_Counter, hregMIPS_GPR10(mode64));
+ amFailAddr = MIPSAMode_IR(offs_Host_EvC_FailAddr, hregMIPS_GPR10(mode64));
+ addInstr(env, MIPSInstr_EvCheck(amCounter, amFailAddr));
+
+ /* Possibly a block counter increment (for profiling). At this
+ point we don't know the address of the counter, so just pretend
+ it is zero. It will have to be patched later, but before this
+ translation is used, by a call to LibVEX_patchProfCtr. */
+ if (addProfInc) {
+ addInstr(env, MIPSInstr_ProfInc());
+ }
+
+ /* Ok, finally we can iterate over the statements. */
+ for (i = 0; i < bb->stmts_used; i++)
+ iselStmt(env, bb->stmts[i]);
+
+ iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
+
+ /* record the number of vregs we used. */
+ env->code->n_vregs = env->vreg_ctr;
+ return env->code;
+
+}
+
+/*---------------------------------------------------------------*/
+/*--- end host_mips_isel.c ---*/
+/*---------------------------------------------------------------*/
diff --git a/pub/libvex_guest_mips32.h b/pub/libvex_guest_mips32.h
new file mode 100644
index 0000000..177bf6b
--- /dev/null
+++ b/pub/libvex_guest_mips32.h
@@ -0,0 +1,161 @@
+
+/*---------------------------------------------------------------*/
+/*--- begin libvex_guest_mips32.h ---*/
+/*---------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2010-2012 RT-RK
+ mips-valgrind@rt-rk.com
+
+ 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.
+*/
+
+#ifndef __LIBVEX_PUB_GUEST_MIPS32_H
+#define __LIBVEX_PUB_GUEST_MIPS32_H
+
+#include "libvex_basictypes.h"
+#include "libvex_emwarn.h"
+
+
+/*---------------------------------------------------------------*/
+/*--- Vex's representation of the MIPS32 CPU state. ---*/
+/*---------------------------------------------------------------*/
+
+typedef
+ struct {
+ /* CPU Registers */
+ /* 0 */ UInt guest_r0; /* Hardwired to 0 */
+ /* 4 */ UInt guest_r1; /* Assembler temporary */
+ /* 8 */ UInt guest_r2; /* Values for function returns ...*/
+ /* 12 */ UInt guest_r3; /* ...and expression evaluation */
+ /* 16 */ UInt guest_r4; /* Function arguments */
+ /* 20 */ UInt guest_r5;
+ /* 24 */ UInt guest_r6;
+ /* 28 */ UInt guest_r7;
+ /* 32 */ UInt guest_r8; /* Temporaries */
+ /* 36 */ UInt guest_r9;
+ /* 40 */ UInt guest_r10;
+ /* 44 */ UInt guest_r11;
+ /* 48 */ UInt guest_r12;
+ /* 52 */ UInt guest_r13;
+ /* 56 */ UInt guest_r14;
+ /* 60 */ UInt guest_r15;
+ /* 64 */ UInt guest_r16; /* Saved temporaries */
+ /* 68 */ UInt guest_r17;
+ /* 72 */ UInt guest_r18;
+ /* 76 */ UInt guest_r19;
+ /* 80 */ UInt guest_r20;
+ /* 84 */ UInt guest_r21;
+ /* 88 */ UInt guest_r22;
+ /* 92 */ UInt guest_r23;
+ /* 96 */ UInt guest_r24; /* Temporaries */
+ /* 100 */ UInt guest_r25;
+ /* 104 */ UInt guest_r26; /* Reserved for OS kernel */
+ /* 108 */ UInt guest_r27;
+ /* 112 */ UInt guest_r28; /* Global pointer */
+ /* 116 */ UInt guest_r29; /* Stack pointer */
+ /* 120 */ UInt guest_r30; /* Frame pointer */
+ /* 124 */ UInt guest_r31; /* Return address */
+ /* 128 */ UInt guest_PC; /* Program counter */
+ /* 132 */ UInt guest_HI;/* Multiply and divide register higher result */
+ /* 136 */ UInt guest_LO;/* Multiply and divide register lower result */
+
+ /* FPU Registers */
+ /* 140 */ UInt guest_f0; /* Floting point general purpose registers */
+ /* 144 */ UInt guest_f1;
+ /* 148 */ UInt guest_f2;
+ /* 152 */ UInt guest_f3;
+ /* 156 */ UInt guest_f4;
+ /* 160 */ UInt guest_f5;
+ /* 164 */ UInt guest_f6;
+ /* 168 */ UInt guest_f7;
+ /* 172 */ UInt guest_f8;
+ /* 176 */ UInt guest_f9;
+ /* 180 */ UInt guest_f10;
+ /* 184 */ UInt guest_f11;
+ /* 188 */ UInt guest_f12;
+ /* 192 */ UInt guest_f13;
+ /* 196 */ UInt guest_f14;
+ /* 200 */ UInt guest_f15;
+ /* 204 */ UInt guest_f16;
+ /* 208 */ UInt guest_f17;
+ /* 212 */ UInt guest_f18;
+ /* 216 */ UInt guest_f19;
+ /* 220 */ UInt guest_f20;
+ /* 224 */ UInt guest_f21;
+ /* 228 */ UInt guest_f22;
+ /* 232 */ UInt guest_f23;
+ /* 236 */ UInt guest_f24;
+ /* 240 */ UInt guest_f25;
+ /* 244 */ UInt guest_f26;
+ /* 248 */ UInt guest_f27;
+ /* 252 */ UInt guest_f28;
+ /* 256 */ UInt guest_f29;
+ /* 260 */ UInt guest_f30;
+ /* 264 */ UInt guest_f31;
+
+ /* 268 */ UInt guest_FIR;
+ /* 272 */ UInt guest_FCCR;
+ /* 276 */ UInt guest_FEXR;
+ /* 280 */ UInt guest_FENR;
+ /* 284 */ UInt guest_FCSR;
+
+ /* TLS pointer for the thread. It's read-only in user space.
+ On Linux it is set in user space by various thread-related
+ syscalls.
+ User Local Register.
+ This register provides read access to the coprocessor 0
+ UserLocal register, if it is implemented. In some operating
+ environments, the UserLocal register is a pointer to a
+ thread-specific storage block.
+ */
+ /* 288 */ UInt guest_ULR;
+
+ /* Emulation warnings */
+ UInt guest_EMWARN; /* 292 */
+
+ /* For clflush: record start and length of area to invalidate */
+ UInt guest_TISTART; /* 296 */
+ UInt guest_TILEN; /* 300 */
+ UInt guest_NRADDR; /* 304 */
+
+ UInt host_EvC_FAILADDR; /* 308 */
+ UInt host_EvC_COUNTER; /* 312 */
+ UInt guest_COND; /* 316 */
+} VexGuestMIPS32State;
+/*---------------------------------------------------------------*/
+/*--- Utility functions for MIPS32 guest stuff. ---*/
+/*---------------------------------------------------------------*/
+
+/* ALL THE FOLLOWING ARE VISIBLE TO LIBRARY CLIENT */
+
+/* Initialise all guest MIPS32 state. */
+
+extern
+void LibVEX_GuestMIPS32_initialise ( /*OUT*/VexGuestMIPS32State* vex_state );
+
+
+#endif /* ndef __LIBVEX_PUB_GUEST_MIPS32_H */
+
+
+/*---------------------------------------------------------------*/
+/*--- libvex_guest_mips32.h ---*/
+/*---------------------------------------------------------------*/