Flatten out the directory structure in the priv/ side, by pulling all
files into priv/ and giving them unique names. This makes it easier
to use automake to build all this stuff in Valgrind. It also tidies
up a directory structure which had become a bit pointlessly complex.
git-svn-id: svn://svn.valgrind.org/vex/trunk@1904 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/host_arm_isel.c b/priv/host_arm_isel.c
new file mode 100644
index 0000000..302d80f
--- /dev/null
+++ b/priv/host_arm_isel.c
@@ -0,0 +1,980 @@
+
+/*---------------------------------------------------------------*/
+/*--- ---*/
+/*--- This file (host_arm_isel.c) is ---*/
+/*--- Copyright (C) OpenWorks LLP. All rights reserved. ---*/
+/*--- ---*/
+/*---------------------------------------------------------------*/
+
+/*
+ This file is part of LibVEX, a library for dynamic binary
+ instrumentation and translation.
+
+ Copyright (C) 2004-2009 OpenWorks LLP. All rights reserved.
+
+ This library is made available under a dual licensing scheme.
+
+ If you link LibVEX against other code all of which is itself
+ licensed under the GNU General Public License, version 2 dated June
+ 1991 ("GPL v2"), then you may use LibVEX under the terms of the GPL
+ v2, as appearing in the file LICENSE.GPL. If the file LICENSE.GPL
+ is missing, you can obtain a copy of the GPL v2 from the Free
+ Software Foundation Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+ For any other uses of LibVEX, you must first obtain a commercial
+ license from OpenWorks LLP. Please contact info@open-works.co.uk
+ for information about commercial licensing.
+
+ This software is provided by OpenWorks LLP "as is" and any express
+ or implied warranties, including, but not limited to, the implied
+ warranties of merchantability and fitness for a particular purpose
+ are disclaimed. In no event shall OpenWorks LLP be liable for any
+ direct, indirect, incidental, special, exemplary, or consequential
+ damages (including, but not limited to, procurement of substitute
+ goods or services; loss of use, data, or profits; or business
+ interruption) however caused and on any theory of liability,
+ whether in contract, strict liability, or tort (including
+ negligence or otherwise) arising in any way out of the use of this
+ software, even if advised of the possibility of such damage.
+
+ Neither the names of the U.S. Department of Energy nor the
+ University of California nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without prior written permission.
+*/
+
+#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_arm_defs.h"
+
+
+/*---------------------------------------------------------*/
+/*--- 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.
+
+ - The code array, that is, the insns selected so far.
+
+ - A counter, for generating new virtual registers.
+
+ Note, this is all host-independent. */
+
+typedef
+ struct {
+ IRTypeEnv* type_env;
+
+ HReg* vregmap;
+ Int n_vregmap;
+
+ 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 addInstr ( ISelEnv* env, ARMInstr* instr )
+{
+ addHInstr(env->code, instr);
+ if (vex_traceflags & VEX_TRACE_VCODE) {
+ ppARMInstr(instr);
+ vex_printf("\n");
+ }
+}
+
+static HReg newVRegI ( ISelEnv* env )
+{
+ HReg reg = mkHReg(env->vreg_ctr, HRcInt32, True/*virtual reg*/);
+ env->vreg_ctr++;
+ return reg;
+}
+
+
+
+/*---------------------------------------------------------*/
+/*--- 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.
+*/
+static ARMAMode1* iselIntExpr_AMode1_wrk ( ISelEnv* env, IRExpr* e );
+static ARMAMode1* iselIntExpr_AMode1 ( ISelEnv* env, IRExpr* e );
+
+/* static ARMAMode2* iselIntExpr_AMode2_wrk ( ISelEnv* env, IRExpr* e ); */
+static ARMAMode2* iselIntExpr_AMode2 ( ISelEnv* env, IRExpr* e );
+
+static ARMAMode3* iselIntExpr_AMode3_wrk ( ISelEnv* env, IRExpr* e );
+static ARMAMode3* iselIntExpr_AMode3 ( ISelEnv* env, IRExpr* e );
+
+static ARMBranchDest* iselIntExpr_BD_wrk ( ISelEnv* env, IRExpr* e );
+static ARMBranchDest* iselIntExpr_BD ( ISelEnv* env, IRExpr* e );
+
+static ARMCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e );
+static ARMCondCode iselCondCode ( ISelEnv* env, IRExpr* e );
+
+static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e );
+static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e );
+
+#if 0
+static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
+ ISelEnv* env, IRExpr* e );
+static void iselInt64Expr ( HReg* rHi, HReg* rLo,
+ ISelEnv* env, IRExpr* e );
+#endif
+
+
+/*---------------------------------------------------------*/
+/*--- ISEL: Misc helpers ---*/
+/*---------------------------------------------------------*/
+#if 0
+/* Is this a 32-bit zero expression? */
+static Bool isZero32 ( IRExpr* e )
+{
+ return e->tag == Iex_Const
+ && e->Iex.Const.con->tag == Ico_U32
+ && e->Iex.Const.con->Ico.U32 == 0;
+}
+#endif
+
+/* Make a int reg-reg move. */
+static ARMInstr* mk_iMOVsd_RR ( HReg src, HReg dst )
+{
+ vassert(hregClass(src) == HRcInt32);
+ vassert(hregClass(dst) == HRcInt32);
+ return ARMInstr_DPInstr1(ARMalu_MOV, dst, ARMAMode1_ShlI(src, 0));
+}
+
+#if 0
+/* Advance/retreat stack pointer by n. */
+
+static void add_to_sp ( ISelEnv* env, Int n )
+{
+ HReg tmp;
+ ARMImm12A imm12a;
+ vassert(n > 0 && n < 256 && (n%4) == 0);
+
+ if ( mk_ARMImm12A( (UInt)n, &imm12a ) ) {
+ addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD,
+ GET_SP_REG(), GET_SP_REG(),
+ ARMAMode1_I12A( imm12a )));
+ } else {
+ tmp = newVRegI(env);
+ addInstr(env, ARMInstr_Literal( tmp, (UInt)n ));
+ addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD,
+ GET_SP_REG(), GET_SP_REG(),
+ ARMAMode1_ShlI( tmp, 0 )));
+ }
+}
+
+static void sub_from_sp ( ISelEnv* env, Int n )
+{
+ HReg tmp;
+ ARMImm12A imm12a;
+ vassert(n > 0 && n < 256 && (n%4) == 0);
+
+ if ( mk_ARMImm12A( (UInt)n, &imm12a ) ) {
+ addInstr(env, ARMInstr_DPInstr2(ARMalu_SUB,
+ GET_SP_REG(), GET_SP_REG(),
+ ARMAMode1_I12A( imm12a )));
+ } else {
+ tmp = newVRegI(env);
+ addInstr(env, ARMInstr_Literal( tmp, (UInt)n ));
+ addInstr(env, ARMInstr_DPInstr2(ARMalu_SUB,
+ GET_SP_REG(), GET_SP_REG(),
+ ARMAMode1_ShlI( tmp, 0 )));
+ }
+}
+#endif
+
+#if 0
+/* Push an arg onto the host stack, in preparation for a call to a
+ helper function of some kind. Returns the number of 32-bit words
+ pushed. */
+
+static Int pushArg ( ISelEnv* env, IRExpr* arg )
+{
+ IRType arg_ty = typeOfIRExpr(env->type_env, arg);
+ if (arg_ty == Ity_I32) {
+
+ // CAB: This right?
+ addInstr(env, ARMInstr_StoreW( GET_SP_REG(), iselIntExpr_AMode2(env, arg) ) );
+ return 1;
+ }
+
+#if 0
+ else
+ if (arg_ty == Ity_I64) {
+ HReg rHi, rLo;
+ iselInt64Expr(&rHi, &rLo, env, arg);
+ addInstr(env, X86Instr_Push(X86RMI_Reg(rHi)));
+ addInstr(env, X86Instr_Push(X86RMI_Reg(rLo)));
+ return 2;
+ }
+#endif
+ ppIRExpr(arg);
+ vpanic("pushArg(arm): can't handle arg of this type");
+}
+#endif
+
+#if 0
+/* Complete the call to a helper function, by calling the
+ helper and clearing the args off the stack. */
+
+static
+void callHelperAndClearArgs ( ISelEnv* env, ARMCondCode cc,
+ IRCallee* cee, Int n_arg_ws )
+{
+ /* Complication. Need to decide which reg to use as the fn address
+ pointer, in a way that doesn't trash regparm-passed
+ parameters. */
+ vassert(sizeof(void*) == 4);
+
+// CAB: cee->regparms ?
+
+// addInstr(env, X86Instr_Call( cc, (UInt)cee->addr, cee->regparms));
+ ARMBranchDest* dst = ARMBranchDest_Imm( (UInt)cee->addr );
+ addInstr(env, ARMInstr_BranchL(cc, dst));
+
+ if (n_arg_ws > 0)
+ add_to_sp(env, 4*n_arg_ws);
+}
+#endif
+
+#if 0
+/* Used only in doHelperCall. See big comment in doHelperCall re
+ handling of regparm 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_Tmp: case Iex_Const: case Iex_Get:
+ return False;
+ default:
+ return True;
+ }
+}
+#endif
+
+/* 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 )
+{
+#if 0
+ ARMCondCode cc;
+ HReg argregs[3];
+ HReg tmpregs[3];
+ Bool danger;
+ Int not_done_yet, n_args, n_arg_ws, stack_limit,
+ i, argreg, argregX;
+
+ /* Marshal args for a call, do the call, and clear the stack.
+ Complexities to consider:
+
+ * if passBBP is True, %ebp (the baseblock pointer) is to be
+ passed as the first arg.
+
+ * If the callee claims regparmness of 1, 2 or 3, we must pass the
+ first 1, 2 or 3 args in registers (EAX, EDX, and ECX
+ respectively). To keep things relatively simple, only args of
+ type I32 may be passed as regparms -- just bomb out if anything
+ else turns up. Clearly this depends on the front ends not
+ trying to pass any other types as regparms.
+ */
+
+ /* 16 Nov 2004: the regparm handling is complicated by the
+ following problem.
+
+ Consider a call two a function with two regparm parameters:
+ f(e1,e2). We need to compute e1 into %eax and e2 into %edx.
+ Suppose code is first generated to compute e1 into %eax. Then,
+ code is generated to compute e2 into %edx. Unfortunately, if
+ the latter code sequence uses %eax, it will trash the value of
+ e1 computed by the former sequence. This could happen if (for
+ example) e2 itself involved a function call. In the code below,
+ args are evaluated right-to-left, not left-to-right, but the
+ principle and the problem are the same.
+
+ One solution is to compute all regparm-bound args into vregs
+ first, and once they are all done, move them to the relevant
+ real regs. This always gives correct code, but it also gives
+ a bunch of vreg-to-rreg moves which are usually redundant but
+ are hard for the register allocator to get rid of.
+
+ A compromise is to first examine all regparm'd argument
+ expressions. If they are all so simple that it is clear
+ they will be evaluated without use of any fixed registers,
+ use the old compute-directly-to-fixed-target scheme. If not,
+ be safe and use the via-vregs scheme.
+
+ Note this requires being able to examine an expression and
+ determine whether or not evaluation of it might use a fixed
+ register. That requires knowledge of how the rest of this
+ insn selector works. Currently just the following 3 are
+ regarded as safe -- hopefully they cover the majority of
+ arguments in practice: IRExpr_Tmp IRExpr_Const IRExpr_Get.
+ */
+ vassert(cee->regparms >= 0 && cee->regparms <= 3);
+
+ n_args = n_arg_ws = 0;
+ while (args[n_args]) n_args++;
+
+ not_done_yet = n_args;
+ if (passBBP)
+ not_done_yet++;
+
+ stack_limit = cee->regparms;
+ if (cee->regparms > 0 && passBBP) stack_limit--;
+
+ /* ------ BEGIN marshall all arguments ------ */
+
+ /* Push (R to L) the stack-passed args, [n_args-1 .. stack_limit] */
+ for (i = n_args-1; i >= stack_limit; i--) {
+ n_arg_ws += pushArg(env, args[i]);
+ not_done_yet--;
+ }
+
+ /* args [stack_limit-1 .. 0] and possibly %ebp are to be passed in
+ registers. */
+
+ if (cee->regparms > 0) {
+
+ /* ------ BEGIN deal with regparms ------ */
+
+ /* deal with regparms, not forgetting %ebp if needed. */
+ argregs[0] = hregX86_EAX();
+ argregs[1] = hregX86_EDX();
+ argregs[2] = hregX86_ECX();
+ tmpregs[0] = tmpregs[1] = tmpregs[2] = INVALID_HREG;
+
+ argreg = cee->regparms;
+
+ /* In keeping with big comment above, detect potential danger
+ and use the via-vregs scheme if needed. */
+ danger = False;
+ for (i = stack_limit-1; i >= 0; i--) {
+ if (mightRequireFixedRegs(args[i])) {
+ danger = True;
+ break;
+ }
+ }
+
+ if (danger) {
+
+ /* Move via temporaries */
+ argregX = argreg;
+ for (i = stack_limit-1; i >= 0; i--) {
+
+ if (0) {
+ vex_printf("x86 host: register param is complex: ");
+ ppIRExpr(args[i]);
+ vex_printf("\n");
+ }
+
+ argreg--;
+ vassert(argreg >= 0);
+ vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32);
+ tmpregs[argreg] = iselIntExpr_R(env, args[i]);
+ not_done_yet--;
+ }
+ for (i = stack_limit-1; i >= 0; i--) {
+ argregX--;
+ vassert(argregX >= 0);
+ addInstr( env, mk_iMOVsd_RR( tmpregs[argregX], argregs[argregX] ) );
+ }
+
+ } else {
+ /* It's safe to compute all regparm args directly into their
+ target registers. */
+ for (i = stack_limit-1; i >= 0; i--) {
+ argreg--;
+ vassert(argreg >= 0);
+ vassert(typeOfIRExpr(env->type_env, args[i]) == Ity_I32);
+ addInstr(env, X86Instr_Alu32R(Xalu_MOV,
+ iselIntExpr_RMI(env, args[i]),
+ argregs[argreg]));
+ not_done_yet--;
+ }
+
+ }
+
+ /* Not forgetting %ebp if needed. */
+ if (passBBP) {
+ vassert(argreg == 1);
+ addInstr(env, mk_iMOVsd_RR( hregX86_EBP(), argregs[0]));
+ not_done_yet--;
+ }
+
+ /* ------ END deal with regparms ------ */
+
+ } else {
+
+ /* No regparms. Heave %ebp on the stack if needed. */
+ if (passBBP) {
+ addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP())));
+ n_arg_ws++;
+ not_done_yet--;
+ }
+
+ }
+
+ vassert(not_done_yet == 0);
+
+ /* ------ END marshall all arguments ------ */
+
+ /* 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 = Xcc_ALWAYS;
+ if (guard) {
+ if (guard->tag == Iex_Const
+ && guard->Iex.Const.con->tag == Ico_U1
+ && guard->Iex.Const.con->Ico.U1 == True) {
+ /* unconditional -- do nothing */
+ } else {
+ cc = iselCondCode( env, guard );
+ }
+ }
+
+ /* call the helper, and get the args off the stack afterwards. */
+ callHelperAndClearArgs( env, cc, cee, n_arg_ws );
+#endif
+}
+
+
+
+// CAB: Do we need to deal with elemSz != 8 ?
+
+/* Given a guest-state array descriptor, an index expression and a
+ bias, generate an ARMAMode holding the relevant guest state
+ offset. */
+
+static
+ARMAMode2* genGuestArrayOffset ( ISelEnv* env, IRRegArray* descr,
+ IRExpr* off, Int bias )
+{
+ HReg tmp, tmp2, roff;
+ Int elemSz = sizeofIRType(descr->elemTy);
+ Int nElems = descr->nElems;
+ ARMImm12A imm12a;
+
+ /* throw out any cases not generated by an x86 front end. In
+ theory there might be a day where we need to handle them -- if
+ we ever run non-x86-guest on x86 host. */
+
+ if (nElems != 8 || (elemSz != 1 && elemSz != 8))
+ vpanic("genGuestArrayOffset(arm host)");
+
+ /* Compute off into a reg, %off. Then return:
+
+ movl %off, %tmp
+ addl $bias, %tmp (if bias != 0)
+ andl %tmp, 7
+ ... base(%ebp, %tmp, shift) ...
+ */
+ tmp = newVRegI(env);
+ roff = iselIntExpr_R(env, off);
+ addInstr(env, mk_iMOVsd_RR(roff, tmp));
+ if (bias != 0) {
+ if ( mk_ARMImm12A( (UInt)bias, &imm12a ) ) {
+ addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD, tmp, tmp,
+ ARMAMode1_I12A( imm12a )));
+ } else {
+ HReg tmp3 = newVRegI(env);
+ addInstr(env, ARMInstr_Literal( tmp, (UInt)bias ));
+ addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD, tmp, tmp,
+ ARMAMode1_ShlI( tmp3, 0 )));
+ }
+ }
+
+ mk_ARMImm12A( (UInt)7, &imm12a );
+ addInstr(env, ARMInstr_DPInstr2(ARMalu_AND, tmp, tmp,
+ ARMAMode1_I12A( imm12a )));
+ vassert(elemSz == 1 || elemSz == 8);
+
+
+
+// CAB: This anywhere near correct?
+
+// X86AMode_IRRS: Immediate + Reg1 + (Reg2 << Shift)
+// return X86AMode_IRRS( descr->base, hregX86_EBP(), tmp, elemSz==8 ? 3 : 0);
+
+ tmp2 = newVRegI(env); // tmp2 = GET_BP_REG + (tmp << 3|0)
+ addInstr(env, ARMInstr_DPInstr2(ARMalu_ADD, tmp2, GET_BP_REG(),
+ ARMAMode1_ShlI(tmp, elemSz==8 ? 3 : 0)));
+ return ARMAMode2_RI( tmp2, descr->base );
+}
+
+
+/*---------------------------------------------------------*/
+/*--- ISEL ... ---*/
+/*---------------------------------------------------------*/
+
+/* --------------------- AMODEs --------------------- */
+
+/* Return an AMode which computes the value of the specified
+ expression, possibly also adding insns to the code list as a
+ result.
+*/
+
+/* ---------------- Addressing Mode 1 ---------------- */
+
+static Bool sane_AMode1 ( ARMAMode1* am )
+{
+ switch (am->tag) {
+ default:
+ vpanic("sane_AMode1: unknown arm amode tag");
+ }
+}
+
+static ARMAMode1* iselIntExpr_AMode1 ( ISelEnv* env, IRExpr* e )
+{
+ ARMAMode1* am = iselIntExpr_AMode1_wrk(env, e);
+ vassert(sane_AMode1(am));
+ return am;
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static ARMAMode1* iselIntExpr_AMode1_wrk ( ISelEnv* env, IRExpr* e )
+{
+ IRType ty = typeOfIRExpr(env->type_env,e);
+ vassert(ty == Ity_I32);
+
+ // ARMam1_I12A, /* Imm12A: extended (rotated) immedate */
+ // ARMam1_ShlI, /* ShlI reg Imm5 */
+ // ARMam1_ShrI, /* ShrI reg Imm5 */
+ // ARMam1_SarI, /* SarI reg Imm5 */
+ // ARMam1_ShlR, /* ShlR reg reg */
+ // ARMam1_ShrR, /* ShrR reg reg */
+ // ARMam1_SarR, /* SarR reg reg */
+
+ // ALU ops:
+ /*
+ ARMalu_And, ARMalu_Orr, ARMalu_Eor, ARMalu_Bic, // Logic
+ ARMalu_Sub, ARMalu_Rsb, ARMalu_Add, ARMalu_Adc, ARMalu_Sbc, ARMalu_Rsc, // Arith
+ ARMalu_Tst, ARMalu_Teq, ARMalu_Cmp, ARMalu_Cmn, // test
+ ARMalu_Mov, ARMalu_Mvn // Move
+ */
+
+
+ return NULL;
+}
+
+
+
+/* ---------------- Addressing Mode 2 ---------------- */
+
+__attribute__((unused))
+static Bool sane_AMode2 ( ARMAMode2* am )
+{
+ switch (am->tag) {
+ default:
+ vpanic("sane_AMode2: unknown arm amode tag");
+ }
+}
+
+/* Apparently unused
+static ARMAMode2* iselIntExpr_AMode2_wrk ( ISelEnv* env, IRExpr* e )
+{
+ ARMAMode2* am = iselIntExpr_AMode2_wrk(env, e);
+ vassert(sane_AMode2(am));
+ return am;
+}
+*/
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static ARMAMode2* iselIntExpr_AMode2 ( ISelEnv* env, IRExpr* e )
+{
+ IRType ty = typeOfIRExpr(env->type_env,e);
+ vassert(ty == Ity_I32);
+
+ // ARMam2_RI, /* Reg +/- Imm12 */
+ // ARMam2_RR, /* Reg +/- Reg */
+ // ARMam2_RRS, /* Reg +/- (Reg << Imm5) */
+
+ return NULL;
+}
+
+
+
+/* ---------------- Addressing Mode 3 ---------------- */
+
+static Bool sane_AMode3 ( ARMAMode3* am )
+{
+ switch (am->tag) {
+ default:
+ vpanic("sane_AMode3: unknown arm amode tag");
+ }
+}
+
+static ARMAMode3* iselIntExpr_AMode3 ( ISelEnv* env, IRExpr* e )
+{
+ ARMAMode3* am = iselIntExpr_AMode3_wrk(env, e);
+ vassert(sane_AMode3(am));
+ return am;
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static ARMAMode3* iselIntExpr_AMode3_wrk ( ISelEnv* env, IRExpr* e )
+{
+ IRType ty = typeOfIRExpr(env->type_env,e);
+ vassert(ty == Ity_I32);
+
+ // ARMam3_RI, /* Reg +/- Imm8 */
+ // ARMam3_RR, /* Reg +/- Reg */
+
+ return NULL;
+}
+
+
+
+/* ---------------- Branch Destination ---------------- */
+
+static ARMBranchDest* iselIntExpr_BD ( ISelEnv* env, IRExpr* e )
+{
+ ARMBranchDest* bd = iselIntExpr_BD_wrk(env, e);
+ /* sanity checks ... */
+ switch (bd->tag) {
+ case ARMbdImm:
+ return bd;
+ case ARMbdReg:
+ vassert(hregClass(bd->ARMbd.Reg.reg) == HRcInt32);
+// vassert(hregIsVirtual(bd->ARMbd.Reg.reg)); // CAB ?
+ return bd;
+ default:
+ vpanic("iselIntExpr_BD: unknown arm BD tag");
+ }
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static ARMBranchDest* iselIntExpr_BD_wrk ( ISelEnv* env, IRExpr* e )
+{
+ /*
+ ARMbdImm,
+ ARMbdReg
+ */
+
+ return NULL;
+}
+
+
+
+
+
+/* --------------------- 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 ARMCondCode iselCondCode ( ISelEnv* env, IRExpr* e )
+{
+ /* Uh, there's nothing we can sanity check here, unfortunately. */
+ return iselCondCode_wrk(env, e);
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static ARMCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
+{
+#if 0
+ MatchInfo mi;
+ DECLARE_PATTERN(p_32to1);
+ DECLARE_PATTERN(p_1Uto32_then_32to1);
+#endif
+
+ return 0;
+}
+
+
+
+static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
+{
+ return iselIntExpr_R_wrk(env, e);
+}
+
+/* DO NOT CALL THIS DIRECTLY ! */
+static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
+{
+ return 0;
+}
+
+
+
+/*---------------------------------------------------------*/
+/*--- 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 --------- */
+ /* little-endian write to memory */
+ case Ist_Store: {
+ HReg reg;
+ IRType tya = typeOfIRExpr(env->type_env, stmt->Ist.Store.addr);
+ IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Store.data);
+ IREndness end = stmt->Ist.Store.end;
+ IRTemp resSC = stmt->Ist.Store.resSC;
+
+ if (tya != Ity_I32 || end != Iend_LE || resSC != IRTemp_INVALID)
+ goto stmt_fail;
+
+ reg = iselIntExpr_R(env, stmt->Ist.Store.data);
+
+ if (tyd == Ity_I8) {
+ ARMAMode2* am2 = iselIntExpr_AMode2(env, stmt->Ist.Store.addr);
+ addInstr(env, ARMInstr_StoreB(reg,am2));
+ return;
+ }
+ if (tyd == Ity_I16) {
+ ARMAMode3* am3 = iselIntExpr_AMode3(env, stmt->Ist.Store.addr);
+ addInstr(env, ARMInstr_StoreH(reg,am3));
+ return;
+ }
+ if (tyd == Ity_I32) {
+ ARMAMode2* am2 = iselIntExpr_AMode2(env, stmt->Ist.Store.addr);
+ addInstr(env, ARMInstr_StoreW(reg,am2));
+ return;
+ }
+ }
+
+ /* --------- PUT --------- */
+ /* write guest state, fixed offset */
+ case Ist_Put: {
+ IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.Put.data);
+ HReg reg = iselIntExpr_R(env, stmt->Ist.Put.data);
+
+ // CAB: This anywhere near right?!
+ if (tyd == Ity_I32) {
+ ARMAMode2* am2 = ARMAMode2_RI(GET_BP_REG(), stmt->Ist.Put.offset);
+ addInstr(env, ARMInstr_StoreW(reg, am2));
+ return;
+ }
+ if (tyd == Ity_I16) {
+ ARMAMode3* am3 = ARMAMode3_RI(GET_BP_REG(), stmt->Ist.Put.offset);
+ addInstr(env, ARMInstr_StoreH(reg, am3));
+ return;
+ }
+ if (tyd == Ity_I8) {
+ ARMAMode2* am2 = ARMAMode2_RI(GET_BP_REG(), stmt->Ist.Put.offset);
+ addInstr(env, ARMInstr_StoreB(reg, am2));
+ return;
+ }
+// CAB: Ity_I32, Ity_I16 ?
+ break;
+ }
+
+ /* --------- Indexed PUT --------- */
+ /* write guest state, run-time offset */
+ case Ist_PutI: {
+ ARMAMode2* am2
+ = genGuestArrayOffset(
+ env, stmt->Ist.PutI.descr,
+ stmt->Ist.PutI.ix, stmt->Ist.PutI.bias );
+
+ IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data);
+
+ if (tyd == Ity_I8) {
+ HReg reg = iselIntExpr_R(env, stmt->Ist.PutI.data);
+ addInstr(env, ARMInstr_StoreB(reg, am2));
+ return;
+ }
+// CAB: Ity_I32, Ity_I16 ?
+ break;
+ }
+
+ /* --------- TMP --------- */
+ /* assign value to temporary */
+ case Ist_WrTmp: {
+ IRTemp tmp = stmt->Ist.WrTmp.tmp;
+ IRType ty = typeOfIRTemp(env->type_env, tmp);
+
+ if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) {
+ ARMAMode1* am = iselIntExpr_AMode1(env, stmt->Ist.WrTmp.data);
+ HReg dst = lookupIRTemp(env, tmp);
+ addInstr(env, ARMInstr_DPInstr1(ARMalu_MOV,dst,am));
+ return;
+ }
+
+// CAB: Ity_I1 ?
+
+ break;
+ }
+
+ /* --------- Call to DIRTY helper --------- */
+ /* call complex ("dirty") helper function */
+ 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);
+
+// CAB: ? if (retty == Ity_I64) {
+
+#if 0
+ if (retty == Ity_I32 || retty == Ity_I16 || retty == Ity_I8) {
+ /* The returned value is in %eax. Park it in the register
+ associated with tmp. */
+ HReg dst = lookupIRTemp(env, d->tmp);
+ addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dst) );
+ return;
+ }
+#endif
+ break;
+ }
+
+ /* --------- EXIT --------- */
+ /* conditional exit from BB */
+ case Ist_Exit: {
+ ARMBranchDest* dst;
+ ARMCondCode cc;
+ if (stmt->Ist.Exit.dst->tag != Ico_U32)
+ vpanic("isel_arm: Ist_Exit: dst is not a 32-bit value");
+
+ // CAB: Where does jumpkind fit in ?
+ // stmt->Ist.Exit.jk
+
+ dst = iselIntExpr_BD(env, IRExpr_Const(stmt->Ist.Exit.dst));
+ cc = iselCondCode(env,stmt->Ist.Exit.guard);
+ addInstr(env, ARMInstr_Branch(cc, dst));
+ return;
+ }
+
+ default: break;
+ }
+ stmt_fail:
+ ppIRStmt(stmt);
+ vpanic("iselStmt");
+}
+
+
+/*---------------------------------------------------------*/
+/*--- ISEL: Basic block terminators (Nexts) ---*/
+/*---------------------------------------------------------*/
+
+static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
+{
+ ARMBranchDest* bd;
+ if (vex_traceflags & VEX_TRACE_VCODE) {
+ vex_printf("\n-- goto {");
+ ppIRJumpKind(jk);
+ vex_printf("} ");
+ ppIRExpr(next);
+ vex_printf("\n");
+ }
+ bd = iselIntExpr_BD(env, next);
+
+ // CAB: jk ?
+
+ addInstr( env, ARMInstr_Branch(ARMccAL, bd) );
+}
+
+
+/*---------------------------------------------------------*/
+/*--- Insn selector top-level ---*/
+/*---------------------------------------------------------*/
+
+/* Translate an entire SB to arm code. */
+
+HInstrArray* iselSB_ARM ( IRSB* bb )
+{
+ Int i, j;
+
+ /* Make up an initial environment to use. */
+ ISelEnv* env = LibVEX_Alloc(sizeof(ISelEnv));
+ env->vreg_ctr = 0;
+
+ /* 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));
+
+ /* For each IR temporary, allocate a 32bit virtual register. */
+ j = 0;
+ for (i = 0; i < env->n_vregmap; i++) {
+ env->vregmap[i] = mkHReg(j++, HRcInt32, True);
+ }
+ env->vreg_ctr = j;
+
+ /* Ok, finally we can iterate over the statements. */
+ for (i = 0; i < bb->stmts_used; i++)
+ if (bb->stmts[i])
+ iselStmt(env,bb->stmts[i]);
+
+ iselNext(env,bb->next,bb->jumpkind);
+
+ /* record the number of vregs we used. */
+ env->code->n_vregs = env->vreg_ctr;
+ return env->code;
+}
+
+
+
+
+
+/*---------------------------------------------------------------*/
+/*--- end host_arm_isel.c ---*/
+/*---------------------------------------------------------------*/