]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Merge r1925:1948 from branches/ARM. This temporarily breaks all other
authorJulian Seward <jseward@acm.org>
Thu, 31 Dec 2009 18:00:12 +0000 (18:00 +0000)
committerJulian Seward <jseward@acm.org>
Thu, 31 Dec 2009 18:00:12 +0000 (18:00 +0000)
targets, because a few IR primops to do with int<->float conversions
have been renamed, and because an internal interface for creating
spill/reload instructions has changed.

git-svn-id: svn://svn.valgrind.org/vex/trunk@1949

23 files changed:
VEX/Makefile-gcc
VEX/auxprogs/genoffsets.c
VEX/priv/guest_amd64_toIR.c
VEX/priv/guest_arm_defs.h
VEX/priv/guest_arm_helpers.c
VEX/priv/guest_arm_toIR.c
VEX/priv/guest_ppc_toIR.c
VEX/priv/guest_x86_toIR.c
VEX/priv/host_amd64_isel.c
VEX/priv/host_arm_defs.c
VEX/priv/host_arm_defs.h
VEX/priv/host_arm_isel.c
VEX/priv/host_generic_reg_alloc2.c
VEX/priv/host_generic_regs.c
VEX/priv/host_generic_regs.h
VEX/priv/host_ppc_isel.c
VEX/priv/host_x86_isel.c
VEX/priv/ir_defs.c
VEX/priv/ir_opt.c
VEX/priv/main_main.c
VEX/pub/libvex_basictypes.h
VEX/pub/libvex_guest_arm.h
VEX/pub/libvex_ir.h

index efa7af4dfefa1b0a57abed5ebcfdb31715aee0d4..c7d42a3c50efc6a3a46c08831796bf2309a2b4d2 100644 (file)
@@ -98,7 +98,7 @@ all: vex
 # Empty, needed for Valgrind
 install:
 
-scratch: clean version all
+scratch: clean all
 
 vex: libvex.a test_main.o
        $(CC) $(CCFLAGS) -o vex test_main.o libvex.a
@@ -162,33 +162,20 @@ TAG-amd64-darwin:
        touch TAG-amd64-darwin
 
 
-# This doesn't get rid of priv/main/vex_svnversion.h, because
-# that can't be regenerated in the final Valgrind tarball, and
-# so if 'make clean' did get rid of it, then in the tarball,
-# doing 'make ; make clean ; make' (or distclean) would fail.
 clean:
        rm -f $(LIB_OBJS) *.a vex test_main.o TAG-* \
                pub/libvex_guest_offsets.h \
                auxprogs/genoffsets.s
 
-version:
-       rm -f priv/main/vex_svnversion.h
-       cat quote.txt   >> priv/main/vex_svnversion.h
-       svnversion -n . >> priv/main/vex_svnversion.h
-       cat quote.txt   >> priv/main/vex_svnversion.h
-       cat newline.txt >> priv/main/vex_svnversion.h
-
-minidist: version
+minidist:
        rm -f vex--minidist-2005MMDD.tar
        tar cf vex--minidist-2005MMDD.tar $(PUB_HEADERS) $(PRIV_HEADERS) \
-               priv/main/vex_svnversion.h                      \
                test_main.c test_main.h                         \
                Makefile                                        \
                `echo $(LIB_OBJS) | sed "s/\.o/\.c/g"`
        @echo 
-       @echo minidist done, size and svnversion follow:
+       @echo minidist done, size follows:
        @ls -l vex--minidist-2005MMDD.tar
-       @cat priv/main/vex_svnversion.h
        @echo
 
 # This is very uggerly.  Need to sed out both "xyzzyN" and
@@ -223,8 +210,7 @@ priv/ir_opt.o: $(ALL_HEADERS) priv/ir_opt.c
        $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/ir_opt.o \
                                         -c priv/ir_opt.c
 
-priv/main_main.o: $(ALL_HEADERS) priv/main_main.c \
-                                       priv/main/vex_svnversion.h
+priv/main_main.o: $(ALL_HEADERS) priv/main_main.c
        $(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/main_main.o \
                                         -c priv/main_main.c
 
index 4bb16b43eea5f76eb78e9f8f3e6c345d71408d2d..1e967602126e2eff560ffcb7228c5f57735123e0 100644 (file)
@@ -61,6 +61,7 @@
 #include "../pub/libvex_guest_amd64.h"
 #include "../pub/libvex_guest_ppc32.h"
 #include "../pub/libvex_guest_ppc64.h"
+#include "../pub/libvex_guest_arm.h"
 
 #define VG_STRINGIFZ(__str)  #__str
 #define VG_STRINGIFY(__str)  VG_STRINGIFZ(__str)
@@ -151,4 +152,14 @@ void foo ( void )
    GENOFFSET(PPC64,ppc64,GPR10);
    GENOFFSET(PPC64,ppc64,CIA);
    GENOFFSET(PPC64,ppc64,CR0_0);
+
+   // arm
+   GENOFFSET(ARM,arm,R0);
+   GENOFFSET(ARM,arm,R1);
+   GENOFFSET(ARM,arm,R2);
+   GENOFFSET(ARM,arm,R3);
+   GENOFFSET(ARM,arm,R4);
+   GENOFFSET(ARM,arm,R5);
+   GENOFFSET(ARM,arm,R7);
+   GENOFFSET(ARM,arm,R15);
 }
index be656428e7c6c7fa36d943a78791783892de23e9..972e218fa57707271fb2237f4c93b1f4dcdf1d3e 100644 (file)
@@ -5349,7 +5349,7 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                   triop(fop, 
                         get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
                         get_ST(0),
-                        unop(Iop_I32toF64,
+                        unop(Iop_I32StoF64,
                              loadLE(Ity_I32, mkexpr(addr)))));
                break;
 
@@ -5357,7 +5357,7 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                put_ST_UNCHECKED(0, 
                   triop(fop, 
                         get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
-                        unop(Iop_I32toF64,
+                        unop(Iop_I32StoF64,
                              loadLE(Ity_I32, mkexpr(addr))),
                         get_ST(0)));
                break;
@@ -5450,27 +5450,27 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
             case 0: /* FILD m32int */
                DIP("fildl %s\n", dis_buf);
                fp_push();
-               put_ST(0, unop(Iop_I32toF64,
+               put_ST(0, unop(Iop_I32StoF64,
                               loadLE(Ity_I32, mkexpr(addr))));
                break;
 
             case 1: /* FISTTPL m32 (SSE3) */
                DIP("fisttpl %s\n", dis_buf);
                storeLE( mkexpr(addr), 
-                        binop(Iop_F64toI32, mkU32(Irrm_ZERO), get_ST(0)) );
+                        binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) );
                fp_pop();
                break;
 
             case 2: /* FIST m32 */
                DIP("fistl %s\n", dis_buf);
                storeLE( mkexpr(addr), 
-                        binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
+                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
                break;
 
             case 3: /* FISTP m32 */
                DIP("fistpl %s\n", dis_buf);
                storeLE( mkexpr(addr), 
-                        binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
+                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
                fp_pop();
                break;
 
@@ -5781,7 +5781,7 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
             case 1: /* FISTTPQ m64 (SSE3) */
                DIP("fistppll %s\n", dis_buf);
                storeLE( mkexpr(addr), 
-                        binop(Iop_F64toI64, mkU32(Irrm_ZERO), get_ST(0)) );
+                        binop(Iop_F64toI64S, mkU32(Irrm_ZERO), get_ST(0)) );
                fp_pop();
                break;
 
@@ -6025,7 +6025,7 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                   triop(fop, 
                         get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
                         get_ST(0),
-                        unop(Iop_I32toF64,
+                        unop(Iop_I32StoF64,
                              unop(Iop_16Sto32, 
                                   loadLE(Ity_I16, mkexpr(addr))))));
                break;
@@ -6034,7 +6034,7 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                put_ST_UNCHECKED(0, 
                   triop(fop, 
                         get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
-                        unop(Iop_I32toF64,
+                        unop(Iop_I32StoF64,
                              unop(Iop_16Sto32, 
                                   loadLE(Ity_I16, mkexpr(addr)))),
                         get_ST(0)));
@@ -6113,7 +6113,7 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
             case 0: /* FILD m16int */
                DIP("fildw %s\n", dis_buf);
                fp_push();
-               put_ST(0, unop(Iop_I32toF64,
+               put_ST(0, unop(Iop_I32StoF64,
                               unop(Iop_16Sto32,
                                    loadLE(Ity_I16, mkexpr(addr)))));
                break;
@@ -6122,7 +6122,7 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                DIP("fisttps %s\n", dis_buf);
                storeLE( mkexpr(addr), 
                         x87ishly_qnarrow_32_to_16( 
-                        binop(Iop_F64toI32, mkU32(Irrm_ZERO), get_ST(0)) ));
+                        binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) ));
                fp_pop();
                break;
 
@@ -6136,14 +6136,14 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                DIP("fistps %s\n", dis_buf);
                storeLE( mkexpr(addr),
                         x87ishly_qnarrow_32_to_16( 
-                        binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) ));
+                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) ));
                fp_pop();
                break;
 
             case 5: /* FILD m64 */
                DIP("fildll %s\n", dis_buf);
                fp_push();
-               put_ST(0, binop(Iop_I64toF64,
+               put_ST(0, binop(Iop_I64StoF64,
                                get_roundingmode(),
                                loadLE(Ity_I64, mkexpr(addr))));
                break;
@@ -6151,7 +6151,7 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
             case 7: /* FISTP m64 */
                DIP("fistpll %s\n", dis_buf);
                storeLE( mkexpr(addr), 
-                        binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
+                        binop(Iop_F64toI64S, get_roundingmode(), get_ST(0)) );
                fp_pop();
                break;
 
@@ -9192,14 +9192,14 @@ DisResult disInstr_AMD64_WRK (
          gregOfRexRM(pfx,modrm), 0,
          binop(Iop_F64toF32, 
                mkexpr(rmode),
-               unop(Iop_I32toF64, 
+               unop(Iop_I32StoF64, 
                     unop(Iop_64to32, mkexpr(arg64)) )) );
 
       putXMMRegLane32F(
          gregOfRexRM(pfx,modrm), 1, 
          binop(Iop_F64toF32, 
                mkexpr(rmode),
-               unop(Iop_I32toF64,
+               unop(Iop_I32StoF64,
                     unop(Iop_64HIto32, mkexpr(arg64)) )) );
 
       goto decode_success;
@@ -9233,7 +9233,7 @@ DisResult disInstr_AMD64_WRK (
             gregOfRexRM(pfx,modrm), 0,
             binop(Iop_F64toF32,
                   mkexpr(rmode),
-                  unop(Iop_I32toF64, mkexpr(arg32)) ) );
+                  unop(Iop_I32StoF64, mkexpr(arg32)) ) );
       } else {
          /* sz == 8 */
          IRTemp arg64 = newTemp(Ity_I64);
@@ -9253,7 +9253,7 @@ DisResult disInstr_AMD64_WRK (
             gregOfRexRM(pfx,modrm), 0,
             binop(Iop_F64toF32,
                   mkexpr(rmode),
-                  binop(Iop_I64toF64, mkexpr(rmode), mkexpr(arg64)) ) );
+                  binop(Iop_I64StoF64, mkexpr(rmode), mkexpr(arg64)) ) );
       }
 
       goto decode_success;
@@ -9302,10 +9302,10 @@ DisResult disInstr_AMD64_WRK (
       assign( 
          dst64,
          binop( Iop_32HLto64,
-                binop( Iop_F64toI32, 
+                binop( Iop_F64toI32S
                        mkexpr(rmode), 
                        unop( Iop_F32toF64, mkexpr(f32hi) ) ),
-                binop( Iop_F64toI32, 
+                binop( Iop_F64toI32S
                        mkexpr(rmode), 
                        unop( Iop_F32toF64, mkexpr(f32lo) ) )
               )
@@ -9359,12 +9359,12 @@ DisResult disInstr_AMD64_WRK (
 
       if (sz == 4) {
          putIReg32( gregOfRexRM(pfx,modrm),
-                    binop( Iop_F64toI32, 
+                    binop( Iop_F64toI32S
                            mkexpr(rmode), 
                            unop(Iop_F32toF64, mkexpr(f32lo))) );
       } else {
          putIReg64( gregOfRexRM(pfx,modrm),
-                    binop( Iop_F64toI64, 
+                    binop( Iop_F64toI64S
                            mkexpr(rmode), 
                            unop(Iop_F32toF64, mkexpr(f32lo))) );
       }
@@ -10324,12 +10324,12 @@ DisResult disInstr_AMD64_WRK (
 
       putXMMRegLane64F( 
          gregOfRexRM(pfx,modrm), 0,
-         unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)))
+         unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)))
       );
 
       putXMMRegLane64F(
          gregOfRexRM(pfx,modrm), 1, 
-         unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)))
+         unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)))
       );
 
       goto decode_success;
@@ -10361,7 +10361,7 @@ DisResult disInstr_AMD64_WRK (
 
 #     define CVT(_t)  binop( Iop_F64toF32,                    \
                              mkexpr(rmode),                   \
-                             unop(Iop_I32toF64,mkexpr(_t)))
+                             unop(Iop_I32StoF64,mkexpr(_t)))
       
       putXMMRegLane32F( gregOfRexRM(pfx,modrm), 3, CVT(t3) );
       putXMMRegLane32F( gregOfRexRM(pfx,modrm), 2, CVT(t2) );
@@ -10415,7 +10415,7 @@ DisResult disInstr_AMD64_WRK (
       assign( t1, unop(Iop_ReinterpI64asF64, 
                        unop(Iop_V128HIto64, mkexpr(argV))) );
       
-#     define CVT(_t)  binop( Iop_F64toI32                   \
+#     define CVT(_t)  binop( Iop_F64toI32S,                   \
                              mkexpr(rmode),                   \
                              mkexpr(_t) )
       
@@ -10472,8 +10472,8 @@ DisResult disInstr_AMD64_WRK (
       assign( 
          dst64,
          binop( Iop_32HLto64,
-                binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64hi) ),
-                binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo) )
+                binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64hi) ),
+                binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo) )
               )
       );
 
@@ -10551,12 +10551,12 @@ DisResult disInstr_AMD64_WRK (
 
       putXMMRegLane64F( 
          gregOfRexRM(pfx,modrm), 0,
-         unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)) )
+         unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)) )
       );
 
       putXMMRegLane64F( 
          gregOfRexRM(pfx,modrm), 1,
-         unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)) )
+         unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)) )
       );
 
       goto decode_success;
@@ -10599,7 +10599,7 @@ DisResult disInstr_AMD64_WRK (
       /* This is less than ideal.  If it turns out to be a performance
          bottleneck it can be improved. */
 #     define CVT(_t)                             \
-         binop( Iop_F64toI32                   \
+         binop( Iop_F64toI32S,                   \
                 mkexpr(rmode),                   \
                 unop( Iop_F32toF64,              \
                       unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
@@ -10690,10 +10690,10 @@ DisResult disInstr_AMD64_WRK (
 
       if (sz == 4) {
          putIReg32( gregOfRexRM(pfx,modrm),
-                    binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo)) );
+                    binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo)) );
       } else {
          putIReg64( gregOfRexRM(pfx,modrm),
-                    binop( Iop_F64toI64, mkexpr(rmode), mkexpr(f64lo)) );
+                    binop( Iop_F64toI64S, mkexpr(rmode), mkexpr(f64lo)) );
       }
 
       goto decode_success;
@@ -10753,7 +10753,7 @@ DisResult disInstr_AMD64_WRK (
                                     nameXMMReg(gregOfRexRM(pfx,modrm)) );
          }
          putXMMRegLane64F( gregOfRexRM(pfx,modrm), 0,
-                           unop(Iop_I32toF64, mkexpr(arg32)) 
+                           unop(Iop_I32StoF64, mkexpr(arg32)) 
          );
       } else {
          /* sz == 8 */
@@ -10773,7 +10773,7 @@ DisResult disInstr_AMD64_WRK (
          putXMMRegLane64F( 
             gregOfRexRM(pfx,modrm), 
             0,
-            binop( Iop_I64toF64,
+            binop( Iop_I64StoF64,
                    get_sse_roundingmode(),
                    mkexpr(arg64)
             ) 
index 04864a3961a847851299bccdb63dc94c286a0d4f..6bbda538ad7712d662d357c690b35ba8e73f51bd 100644 (file)
    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.
 */
 
 /* Only to be used within the guest-arm directory. */
 /*--- arm to IR conversion                              ---*/
 /*---------------------------------------------------------*/
 
+/* Convert one ARM insn to IR.  See the type DisOneInstrFn in
+   bb_to_IR.h. */
 extern
-IRSB* bbToIR_ARM ( UChar*           armCode, 
-                   Addr64           eip, 
-                   VexGuestExtents* vge,
-                   Bool             (*byte_accessible)(Addr64),
-                   Bool             (*resteerOkFn)(Addr64),
-                   Bool             host_bigendian,
-                   VexArchInfo*     archinfo_guest );
+DisResult disInstr_ARM ( IRSB*        irbb,
+                         Bool         put_IP,
+                         Bool         (*resteerOkFn) ( void*, Addr64 ),
+                         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
@@ -84,18 +85,31 @@ VexGuestLayout armGuest_layout;
 
 /* --- CLEAN HELPERS --- */
 
-extern UInt  armg_calculate_flags_all ( 
-                UInt cc_op, UInt cc_dep1, UInt cc_dep2 
-             );
-extern UInt  armg_calculate_flags_c ( 
-                UInt cc_op, UInt cc_dep1, UInt cc_dep2 
-             );
+/* Calculate NZCV from the supplied thunk components, in the positions
+   they appear in the CPSR, viz bits 31:28 for N Z V C respectively.
+   Returned bits 27:0 are zero. */
+extern 
+UInt armg_calculate_flags_nzcv ( UInt cc_op, UInt cc_dep1,
+                                 UInt cc_dep2, UInt cc_dep3 );
+
+/* Calculate the C flag from the thunk components, in the lowest bit
+   of the word (bit 0). */
+extern 
+UInt armg_calculate_flag_c ( UInt cc_op, UInt cc_dep1,
+                             UInt cc_dep2, UInt cc_dep3 );
+
+/* Calculate the V flag from the thunk components, in the lowest bit
+   of the word (bit 0). */
+extern 
+UInt armg_calculate_flag_v ( UInt cc_op, UInt cc_dep1,
+                             UInt cc_dep2, UInt cc_dep3 );
 
-extern UInt  armg_calculate_condition ( 
-                UInt/*ARMCondcode*/ cond, 
-                UInt cc_op, 
-                UInt cc_dep1, UInt cc_dep2 
-             );
+/* Calculate the specified condition from the thunk components, in the
+   lowest bit of the word (bit 0). */
+extern 
+UInt armg_calculate_condition ( UInt cond_n_op /* ARMCondcode << 4 | cc_op */,
+                                UInt cc_dep1,
+                                UInt cc_dep2, UInt cc_dep3 );
 
 
 /*---------------------------------------------------------*/
@@ -110,64 +124,77 @@ extern UInt  armg_calculate_condition (
 
 #define ARMG_CC_MASK_N    (1 << ARMG_CC_SHIFT_N)
 #define ARMG_CC_MASK_Z    (1 << ARMG_CC_SHIFT_Z)
-#define ARMG_CC_MASK_V    (1 << ARMG_CC_SHIFT_V)
 #define ARMG_CC_MASK_C    (1 << ARMG_CC_SHIFT_C)
+#define ARMG_CC_MASK_V    (1 << ARMG_CC_SHIFT_V)
 
-/* Flag thunk descriptors.  A three-word thunk is used to record
+/* Flag thunk descriptors.  A four-word thunk is used to record
    details of the most recent flag-setting operation, so the flags can
    be computed later if needed.
 
-   The three words are:
+   The four words are:
 
       CC_OP, which describes the operation.
 
-      CC_DEP1 and CC_DEP2.  These are arguments to the operation.
-         We want Memcheck to believe that the resulting flags are
-         data-dependent on both CC_DEP1 and CC_DEP2, hence the 
-         name DEP.
+      CC_DEP1, CC_DEP2, CC_DEP3.  These are arguments to the
+         operation.  We want set up the mcx_masks in flag helper calls
+         involving these fields so that Memcheck "believes" that the
+         resulting flags are data-dependent on both CC_DEP1 and
+         CC_DEP2.  Hence the name DEP.
 
    When building the thunk, it is always necessary to write words into
-   CC_DEP1 and CC_DEP2, even if those args are not used given the
+   CC_DEP1/2/3, even if those args are not used given the
    CC_OP field.  This is important because otherwise Memcheck could
    give false positives as it does not understand the relationship
-   between the CC_OP field and CC_DEP1 and CC_DEP2, and so believes
-   that the definedness of the stored flags always depends on both
-   CC_DEP1 and CC_DEP2.
+   between the CC_OP field and CC_DEP1/2/3, and so believes
+   that the definedness of the stored flags always depends on
+   all 3 DEP values.
 
    A summary of the field usages is:
-   TODO: make this right
 
-   Operation          DEP1               DEP2               NDEP
-   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+   OP                DEP1              DEP2              DEP3
+   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+   OP_COPY           current NZCV      unused            unused
+   OP_ADD            argL              argR              unused
+   OP_SUB            argL              argR              unused
+   OP_ADC            argL              argR              old_C
+   OP_SBB            argL              argR              old_C
+   OP_LOGIC          result            shifter_co        old_V
+   OP_MUL            result            unused            old_C:old_V
+   OP_MULL           resLO32           resHI32           old_C:old_V
+*/
 
-   and/or/xor         result             shift_carry_out
-   tst/teq/bic        result             shift_carry_out
-   mov/mvn            result             shift_carry_out
+enum {
+   ARMG_CC_OP_COPY=0,  /* DEP1 = NZCV in 31:28, DEP2 = 0, DEP3 = 0
+                          just copy DEP1 to output */
 
-   add/cmn            first arg          second arg
-   sub/cmp            first arg          second arg
+   ARMG_CC_OP_ADD,     /* DEP1 = argL (Rn), DEP2 = argR (shifter_op),
+                          DEP3 = 0 */
 
-   ...
+   ARMG_CC_OP_SUB,     /* DEP1 = argL (Rn), DEP2 = argR (shifter_op),
+                          DEP3 = 0 */
 
+   ARMG_CC_OP_ADC,     /* DEP1 = argL (Rn), DEP2 = arg2 (shifter_op),
+                          DEP3 = oldC (in LSB) */
 
-   Therefore Memcheck will believe the following:
+   ARMG_CC_OP_SBB,     /* DEP1 = argL (Rn), DEP2 = arg2 (shifter_op),
+                          DEP3 = oldC (in LSB) */
 
-   * ...
+   ARMG_CC_OP_LOGIC,   /* DEP1 = result, DEP2 = shifter_carry_out (in LSB),
+                          DEP3 = old V flag (in LSB) */
+
+   ARMG_CC_OP_MUL,     /* DEP1 = result, DEP2 = 0, DEP3 = oldC:old_V
+                          (in bits 1:0) */
+
+   ARMG_CC_OP_MULL,    /* DEP1 = resLO32, DEP2 = resHI32, DEP3 = oldC:old_V
+                          (in bits 1:0) */
 
-*/
-enum {
-   ARMG_CC_OP_COPY,    /* DEP1 = current flags, DEP2 = 0 */
-                       /* just copy DEP1 to output */
-
-   ARMG_CC_OP_LOGIC,   /* DEP1 = result, DEP2 = shifter_carry_out */
-   
-   ARMG_CC_OP_SUB,     /* DEP1 = arg1(Rn), DEP2 = arg2 (shifter_op) */
-   ARMG_CC_OP_ADD,     /* DEP1 = arg1(Rn), DEP2 = arg2 (shifter_op) */
-   
    ARMG_CC_OP_NUMBER
 };
 
-/* requires further study */
+/* XXXX because of the calling conventions for
+   armg_calculate_condition, all this OP values MUST be in the range
+   0 .. 15 only (viz, 4-bits). */
 
 
 
@@ -175,33 +202,33 @@ enum {
 
 typedef
    enum {
-      ARMCondEQ     = 0,  /* equal                               : Z=1 */
-      ARMCondNE     = 1,  /* not equal                           : Z=0 */
+      ARMCondEQ     = 0,  /* equal                         : Z=1 */
+      ARMCondNE     = 1,  /* not equal                     : Z=0 */
 
-      ARMCondHS     = 2,  /* >=u (higher or same)                : C=1 */
-      ARMCondLO     = 3,  /* <u  (lower)                         : C=0 */
+      ARMCondHS     = 2,  /* >=u (higher or same)          : C=1 */
+      ARMCondLO     = 3,  /* <u  (lower)                   : C=0 */
 
-      ARMCondMI     = 4,  /* minus (negative)                    : N=1 */
-      ARMCondPL     = 5,  /* plus (zero or +ve)                  : N=0 */
+      ARMCondMI     = 4,  /* minus (negative)              : N=1 */
+      ARMCondPL     = 5,  /* plus (zero or +ve)            : N=0 */
 
-      ARMCondVS     = 6,  /* overflow                            : V=1 */
-      ARMCondVC     = 7,  /* no overflow                         : V=0 */
+      ARMCondVS     = 6,  /* overflow                      : V=1 */
+      ARMCondVC     = 7,  /* no overflow                   : V=0 */
 
-      ARMCondHI     = 8,  /* >u   (higher)                       : C=1 && Z=0 */
-      ARMCondLS     = 9,  /* <=u  (lower or same)                : C=0 || Z=1 */
+      ARMCondHI     = 8,  /* >u   (higher)                 : C=1 && Z=0 */
+      ARMCondLS     = 9,  /* <=u  (lower or same)          : C=0 || Z=1 */
 
-      ARMCondGE     = 10, /* >=s (signed greater or equal)       : N=V */
-      ARMCondLT     = 11, /* <s  (signed less than)              : N!=V */
+      ARMCondGE     = 10, /* >=s (signed greater or equal) : N=V */
+      ARMCondLT     = 11, /* <s  (signed less than)        : N!=V */
 
-      ARMCondGT     = 12, /* >s  (signed greater)                : Z=0 && N=V */
-      ARMCondLE     = 13, /* <=s (signed less or equal)          : Z=1 || N!=V */
+      ARMCondGT     = 12, /* >s  (signed greater)          : Z=0 && N=V */
+      ARMCondLE     = 13, /* <=s (signed less or equal)    : Z=1 || N!=V */
 
-      ARMCondAL     = 14, /* always (unconditional)              : */
-      ARMCondNV     = 15  /* never (basically undefined meaning) : */
-                          /* NB: ARM 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.  */
+      ARMCondAL     = 14, /* always (unconditional)        : 1 */
+      ARMCondNV     = 15  /* never (unconditional):        : 0 */
+      /* NB: ARM 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.  */
    }
    ARMCondcode;
 
index 3c4a156817e112868b9d00e8a813e9d7a2bfa6bb..ffd71d369681ac685554c85cf7123ec60b244f78 100644 (file)
    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_emwarn.h"
 #include "libvex_guest_arm.h"
 #include "libvex_ir.h"
 #include "libvex.h"
 
 #include "main_util.h"
+#include "guest_generic_bb_to_IR.h"
 #include "guest_arm_defs.h"
 
 
-/* This file contains helper functions for arm guest code.
-   Calls to these functions are generated by the back end.
-   These calls are of course in the host machine code and 
-   this file will be compiled to host machine code, so that
-   all makes sense.  
+/* This file contains helper functions for arm guest code.  Calls to
+   these functions are generated by the back end.  These calls are of
+   course in the host machine code and this file will be compiled to
+   host machine code, so that all makes sense.
 
    Only change the signatures of these helper functions very
    carefully.  If you change the signature here, you'll have to change
 
 
 
-
-
-
-
-#define BORROWFROM() \
-{ \
-}
-#define OVERFLOWFROM() \
-{ \
-}
-
-
-/*-------------------------------------------------------------*/
-/*
-  LOGIC: EOR, AND, TST, TEQ, MOV, ORR, MVN, BIC
-  ----------------
-  n: Rd[31]
-  z: Rd==0 ? 1:0
-  c: shifter_carry_out
-  v: unaffected
-*/
-#define ACTIONS_LOGIC()                                          \
-{                                                                \
-   { Int nf, zf, cf, vf;                                         \
-     Int oldV=0;    /* CAB: vf unaffected: what todo? */         \
-     nf = cc_dep1_formal & ARMG_CC_MASK_N;                       \
-     zf = cc_dep1_formal == 0 ? 1 : 0;                           \
-     cf = (cc_dep2_formal << ARMG_CC_SHIFT_C) & ARMG_CC_MASK_C;  \
-     vf = oldV & ARMG_CC_MASK_V;                                 \
-     return nf | zf | cf | vf;                                   \
-   }                                                             \
-}
-
-/*-------------------------------------------------------------*/
-/*
-  ADD: ADD, CMN
-  ----------------
-  n: Rd[31]
-  z: Rd==0 ? 1:0
-  c: CarryFrom(Rn + shifter_op)
-  v: OverflowFrom(Rn + shifter_op)
-*/
-#define ACTIONS_ADD()                                            \
-{                                                                \
-   { Int nf, zf, cf, vf;                                         \
-     Int argL, argR, res;                                        \
-     argL = cc_dep1_formal;                                      \
-     argR = cc_dep2_formal;                                      \
-     res  = argL + argR;                                         \
-     nf = res & ARMG_CC_MASK_N;                                  \
-     zf = (res == 0) << ARMG_CC_SHIFT_Z;                         \
-     cf = ((UInt)argL < (UInt)argR) << ARMG_CC_SHIFT_C;          \
-     vf = (((argL ^ argR ^ -1) & (argL ^ res)) >>                \
-           (32 - ARMG_CC_SHIFT_V)) & ARMG_CC_MASK_V;             \
-     return nf | zf | cf | vf;                                   \
-   }                                                             \
-}
-
-/*-------------------------------------------------------------*/
-/*
-  SUB: SUB, CMP, RSB
-  ----------------
-  n: Rd[31]
-  z: Rd==0 ? 1:0
-  c: NOT BorrowFrom(Rn - shifter_op)
-  v: OverflowFrom(Rn - shifter_op)
-*/
-// CAB: cf right? ARM ARM A4-99
-#define ACTIONS_SUB()                                            \
-{                                                                \
-   { Int nf, zf, cf, vf;                                         \
-     Int argL, argR, res;                                        \
-     argL = cc_dep1_formal;                                      \
-     argR = cc_dep2_formal;                                      \
-     res  = argL - argR;                                         \
-     nf = res & ARMG_CC_MASK_N;                                  \
-     zf = (res == 0) << ARMG_CC_SHIFT_Z;                         \
-     cf = (~((UInt)argL < (UInt)argR) <<                         \
-           ARMG_CC_SHIFT_C) & ARMG_CC_MASK_C;                    \
-     vf = (((argL ^ argR ^ -1) & (argL ^ res)) >>                \
-           (32 - ARMG_CC_SHIFT_V)) & ARMG_CC_MASK_V;             \
-     return nf | zf | cf | vf;                                   \
-   }                                                             \
+/* generalised left-shifter */
+static inline UInt lshift ( UInt x, Int n )
+{
+   if (n >= 0)
+      return x << n;
+   else
+      return x >> (-n);
 }
 
 
-/*-------------------------------------------------------------*/
-/*
-  ADC
-  ----------------
-  n: Rd[31]
-  z: Rd==0 ? 1:0
-  c: CarryFrom(Rn + shifter_op + C Flag)
-  v: OverflowFrom(Rn + shifter_op + C Flag)
-*/
-
-/*-------------------------------------------------------------*/
-/*
-  RSC
-  ----------------
-  n: Rd[31]
-  z: Rd==0 ? 1:0
-  c: NOT BorrowFrom(shifter_op - Rn - NOT(C Flag))
-  v: OverflowFrom(shifter_op - Rn - NOT(C Flag))
-*/
-
-/*-------------------------------------------------------------*/
-/*
-  SBC
-  ----------------
-  n: Rd[31]
-  z: Rd==0 ? 1:0
-  c: NOT BorrowFrom(Rn - shifter_op - NOT(C Flag))
-  v: OverflowFrom(Rn - shifter_op - NOT(C Flag))
-*/
-
-
-
-
-
-
-
-
-
 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
-/* Calculate all the 4 flags from the supplied thunk parameters. */
-UInt armg_calculate_flags_all ( UInt cc_op, 
-                                UInt cc_dep1_formal, 
-                                UInt cc_dep2_formal )
+/* Calculate NZCV from the supplied thunk components, in the positions
+   they appear in the CPSR, viz bits 31:28 for N Z C V respectively.
+   Returned bits 27:0 are zero. */
+UInt armg_calculate_flags_nzcv ( UInt cc_op, UInt cc_dep1,
+                                 UInt cc_dep2, UInt cc_dep3 )
 {
    switch (cc_op) {
-   case ARMG_CC_OP_LOGIC:  ACTIONS_LOGIC();
-   case ARMG_CC_OP_ADD:  ACTIONS_ADD();
-   case ARMG_CC_OP_SUB:  ACTIONS_SUB();
-
-   default:
-      /* shouldn't really make these calls from generated code */
-      vex_printf("armg_calculate_flags_all(ARM)( %u, 0x%x, 0x%x )\n",
-                 cc_op, cc_dep1_formal, cc_dep2_formal );
-      vpanic("armg_calculate_flags_all(ARM)");
+      case ARMG_CC_OP_COPY:
+         /* (nzcv, unused, unused) */
+         return cc_dep1;
+      case ARMG_CC_OP_ADD: {
+         /* (argL, argR, unused) */
+         UInt argL = cc_dep1;
+         UInt argR = cc_dep2;
+         UInt res  = argL + argR;
+         UInt nf   = lshift( res & (1<<31), ARMG_CC_SHIFT_N - 31 );
+         UInt zf   = lshift( res == 0, ARMG_CC_SHIFT_Z );
+         // CF and VF need verification
+         UInt cf   = lshift( res < argL, ARMG_CC_SHIFT_C );
+         UInt vf   = lshift( (res ^ argL) & (res ^ argR),
+                             ARMG_CC_SHIFT_V + 1 - 32 )
+                     & ARMG_CC_MASK_V;
+         //vex_printf("%08x %08x -> n %x z %x c %x v %x\n",
+         //           argL, argR, nf, zf, cf, vf);
+         return nf | zf | cf | vf;
+      }
+      case ARMG_CC_OP_SUB: {
+         /* (argL, argR, unused) */
+         UInt argL = cc_dep1;
+         UInt argR = cc_dep2;
+         UInt res  = argL - argR;
+         UInt nf   = lshift( res & (1<<31), ARMG_CC_SHIFT_N - 31 );
+         UInt zf   = lshift( res == 0, ARMG_CC_SHIFT_Z );
+         // XXX cf is inverted relative to normal sense
+         UInt cf   = lshift( argL >= argR, ARMG_CC_SHIFT_C );
+         UInt vf   = lshift( (argL ^ argR) & (argL ^ res),
+                             ARMG_CC_SHIFT_V + 1 - 32 )
+                     & ARMG_CC_MASK_V;
+         //vex_printf("%08x %08x -> n %x z %x c %x v %x\n",
+         //           argL, argR, nf, zf, cf, vf);
+         return nf | zf | cf | vf;
+      }
+      case ARMG_CC_OP_ADC: {
+         /* (argL, argR, oldC) */
+         UInt argL = cc_dep1;
+         UInt argR = cc_dep2;
+         UInt oldC = cc_dep3;
+         UInt res  = (argL + argR) + oldC;
+         UInt nf   = lshift( res & (1<<31), ARMG_CC_SHIFT_N - 31 );
+         UInt zf   = lshift( res == 0, ARMG_CC_SHIFT_Z );
+         UInt cf   = oldC ? lshift( res <= argL, ARMG_CC_SHIFT_C )
+                          : lshift( res <  argL, ARMG_CC_SHIFT_C );
+         UInt vf   = lshift( (res ^ argL) & (res ^ argR),
+                             ARMG_CC_SHIFT_V + 1 - 32 )
+                     & ARMG_CC_MASK_V;
+         //vex_printf("%08x %08x -> n %x z %x c %x v %x\n",
+         //           argL, argR, nf, zf, cf, vf);
+         return nf | zf | cf | vf;
+      }
+      case ARMG_CC_OP_SBB: {
+         /* (argL, argR, oldC) */
+         UInt argL = cc_dep1;
+         UInt argR = cc_dep2;
+         UInt oldC = cc_dep3;
+         UInt res  = argL - argR - (oldC ^ 1);
+         UInt nf   = lshift( res & (1<<31), ARMG_CC_SHIFT_N - 31 );
+         UInt zf   = lshift( res == 0, ARMG_CC_SHIFT_Z );
+         UInt cf   = oldC ? lshift( argL >= argR, ARMG_CC_SHIFT_C )
+                          : lshift( argL >  argR, ARMG_CC_SHIFT_C );
+         UInt vf   = lshift( (argL ^ argR) & (argL ^ res),
+                             ARMG_CC_SHIFT_V + 1 - 32 )
+                     & ARMG_CC_MASK_V;
+         //vex_printf("%08x %08x -> n %x z %x c %x v %x\n",
+         //           argL, argR, nf, zf, cf, vf);
+         return nf | zf | cf | vf;
+      }
+      case ARMG_CC_OP_LOGIC: {
+         /* (res, shco, oldV) */
+         UInt res  = cc_dep1;
+         UInt shco = cc_dep2;
+         UInt oldV = cc_dep3;
+         UInt nf   = lshift( res & (1<<31), ARMG_CC_SHIFT_N - 31 );
+         UInt zf   = lshift( res == 0, ARMG_CC_SHIFT_Z );
+         UInt cf   = lshift( shco & 1, ARMG_CC_SHIFT_C );
+         UInt vf   = lshift( oldV & 1, ARMG_CC_SHIFT_V );
+         return nf | zf | cf | vf;
+      }
+      case ARMG_CC_OP_MUL: {
+         /* (res, unused, oldC:oldV) */
+         UInt res  = cc_dep1;
+         UInt oldC = (cc_dep3 >> 1) & 1;
+         UInt oldV = (cc_dep3 >> 0) & 1;
+         UInt nf   = lshift( res & (1<<31), ARMG_CC_SHIFT_N - 31 );
+         UInt zf   = lshift( res == 0, ARMG_CC_SHIFT_Z );
+         UInt cf   = lshift( oldC & 1, ARMG_CC_SHIFT_C );
+         UInt vf   = lshift( oldV & 1, ARMG_CC_SHIFT_V );
+         return nf | zf | cf | vf;
+      }
+      case ARMG_CC_OP_MULL: {
+         /* (resLo32, resHi32, oldC:oldV) */
+         UInt resLo32 = cc_dep1;
+         UInt resHi32 = cc_dep2;
+         UInt oldC    = (cc_dep3 >> 1) & 1;
+         UInt oldV    = (cc_dep3 >> 0) & 1;
+         UInt nf      = lshift( resHi32 & (1<<31), ARMG_CC_SHIFT_N - 31 );
+         UInt zf      = lshift( (resHi32|resLo32) == 0, ARMG_CC_SHIFT_Z );
+         UInt cf      = lshift( oldC & 1, ARMG_CC_SHIFT_C );
+         UInt vf      = lshift( oldV & 1, ARMG_CC_SHIFT_V );
+         return nf | zf | cf | vf;
+      }
+      default:
+         /* shouldn't really make these calls from generated code */
+         vex_printf("armg_calculate_flags_nzcv"
+                    "( op=%u, dep1=0x%x, dep2=0x%x, dep3=0x%x )\n",
+                    cc_op, cc_dep1, cc_dep2, cc_dep3 );
+         vpanic("armg_calculate_flags_nzcv");
    }
 }
 
+
 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
-/* Calculate just the carry flag from the supplied thunk parameters. */
-UInt armg_calculate_flags_c ( UInt cc_op, 
-                              UInt cc_dep1, 
-                              UInt cc_dep2 )
+/* Calculate the C flag from the thunk components, in the lowest bit
+   of the word (bit 0). */
+UInt armg_calculate_flag_c ( UInt cc_op, UInt cc_dep1,
+                             UInt cc_dep2, UInt cc_dep3 )
 {
-   /* Fast-case some common ones. */
-   switch (cc_op) {
-   default: 
-      break;
-   }
-   return armg_calculate_flags_all(cc_op,cc_dep1,cc_dep2) & ARMG_CC_MASK_C;
+   UInt r = armg_calculate_flags_nzcv(cc_op, cc_dep1, cc_dep2, cc_dep3);
+   return (r >> ARMG_CC_SHIFT_C) & 1;
 }
 
 
-
 /* CALLED FROM GENERATED CODE: CLEAN HELPER */
-/* returns 1 or 0 */
-/*static*/
-UInt armg_calculate_condition ( UInt/*ARMCondcode*/ cond, 
-                                UInt cc_op, 
-                                UInt cc_dep1, 
-                                UInt cc_dep2 )
+/* Calculate the V flag from the thunk components, in the lowest bit
+   of the word (bit 0). */
+UInt armg_calculate_flag_v ( UInt cc_op, UInt cc_dep1,
+                             UInt cc_dep2, UInt cc_dep3 )
 {
-   UInt nf,zf,vf,cf;
-   UInt inv = cond & 1;
+   UInt r = armg_calculate_flags_nzcv(cc_op, cc_dep1, cc_dep2, cc_dep3);
+   return (r >> ARMG_CC_SHIFT_V) & 1;
+}
+
 
-   UInt nzvc = armg_calculate_flags_all(cc_op, cc_dep1, cc_dep2);
+/* CALLED FROM GENERATED CODE: CLEAN HELPER */
+/* Calculate the specified condition from the thunk components, in the
+   lowest bit of the word (bit 0). */
+extern 
+UInt armg_calculate_condition ( UInt cond_n_op /* ARMCondcode << 4 | cc_op */,
+                                UInt cc_dep1,
+                                UInt cc_dep2, UInt cc_dep3 )
+{
+   UInt cond  = cond_n_op >> 4;
+   UInt cc_op = cond_n_op & 0xF;
+   UInt nf, zf, vf, cf;
+   UInt inv  = cond & 1;
+   //   vex_printf("XXXXXXXX %x %x %x %x\n", cond_n_op, cc_dep1, cc_dep2, cc_dep3);
+   UInt nzcv = armg_calculate_flags_nzcv(cc_op, cc_dep1, cc_dep2, cc_dep3);
 
    switch (cond) {
-   case ARMCondEQ:    // Z=1         => z
-   case ARMCondNE:    // Z=0
-      zf = nzvc >> ARMG_CC_SHIFT_Z;
-      return 1 & (inv ^ zf);
-
-   case ARMCondHS:    // C=1         => c
-   case ARMCondLO:    // C=0
-      cf = nzvc >> ARMG_CC_SHIFT_C;
-      return 1 & (inv ^ cf);
-
-   case ARMCondMI:    // N=1         => n
-   case ARMCondPL:    // N=0
-      nf = nzvc >> ARMG_CC_SHIFT_N;
-      return 1 & (inv ^ nf);
-
-   case ARMCondVS:    // V=1         => v
-   case ARMCondVC:    // V=0
-      vf = nzvc >> ARMG_CC_SHIFT_V;
-      return 1 & (inv ^ vf);
-
-   case ARMCondHI:    // C=1 && Z=0   => c & ~z
-   case ARMCondLS:    // C=0 || Z=1
-      cf = nzvc >> ARMG_CC_SHIFT_C;
-      zf = nzvc >> ARMG_CC_SHIFT_Z;
-      return 1 & (inv ^ (cf & ~zf));
-
-   case ARMCondGE:    // N=V          => ~(n^v)
-   case ARMCondLT:    // N!=V
-      nf = nzvc >> ARMG_CC_SHIFT_N;
-      vf = nzvc >> ARMG_CC_SHIFT_V;
-      return 1 & (inv ^ ~(nf ^ vf));
-
-   case ARMCondGT:    // Z=0 && N=V   => (~z & ~(n^v)  =>  ~(z | (n^v)
-   case ARMCondLE:    // Z=1 || N!=V
-      nf = nzvc >> ARMG_CC_SHIFT_N;
-      vf = nzvc >> ARMG_CC_SHIFT_V;
-      zf = nzvc >> ARMG_CC_SHIFT_Z;
-       return 1 & (inv ^ ~(zf | (nf ^ vf)));
-
-   case ARMCondAL:   // should never get here: Always => no flags to calc
-   case ARMCondNV:   // should never get here: Illegal instr
-   default:
-      /* shouldn't really make these calls from generated code */
-      vex_printf("armg_calculate_condition(ARM)( %u, %u, 0x%x, 0x%x )\n",
-                 cond, cc_op, cc_dep1, cc_dep2 );
-      vpanic("armg_calculate_condition(ARM)");
+      case ARMCondEQ:    // Z=1         => z
+      case ARMCondNE:    // Z=0
+         zf = nzcv >> ARMG_CC_SHIFT_Z;
+         return 1 & (inv ^ zf);
+
+      case ARMCondHS:    // C=1         => c
+      case ARMCondLO:    // C=0
+         cf = nzcv >> ARMG_CC_SHIFT_C;
+         return 1 & (inv ^ cf);
+
+      case ARMCondMI:    // N=1         => n
+      case ARMCondPL:    // N=0
+         nf = nzcv >> ARMG_CC_SHIFT_N;
+         return 1 & (inv ^ nf);
+
+      case ARMCondVS:    // V=1         => v
+      case ARMCondVC:    // V=0
+         vf = nzcv >> ARMG_CC_SHIFT_V;
+         return 1 & (inv ^ vf);
+
+      case ARMCondHI:    // C=1 && Z=0   => c & ~z
+      case ARMCondLS:    // C=0 || Z=1
+         cf = nzcv >> ARMG_CC_SHIFT_C;
+         zf = nzcv >> ARMG_CC_SHIFT_Z;
+         return 1 & (inv ^ (cf & ~zf));
+
+      case ARMCondGE:    // N=V          => ~(n^v)
+      case ARMCondLT:    // N!=V
+         nf = nzcv >> ARMG_CC_SHIFT_N;
+         vf = nzcv >> ARMG_CC_SHIFT_V;
+         return 1 & (inv ^ ~(nf ^ vf));
+
+      case ARMCondGT:    // Z=0 && N=V   => ~z & ~(n^v)  =>  ~(z | (n^v))
+      case ARMCondLE:    // Z=1 || N!=V
+         nf = nzcv >> ARMG_CC_SHIFT_N;
+         vf = nzcv >> ARMG_CC_SHIFT_V;
+         zf = nzcv >> ARMG_CC_SHIFT_Z;
+         return 1 & (inv ^ ~(zf | (nf ^ vf)));
+
+      case ARMCondAL: // should never get here: Always => no flags to calc
+      case ARMCondNV: // should never get here: Illegal instr
+      default:
+         /* shouldn't really make these calls from generated code */
+         vex_printf("armg_calculate_condition(ARM)"
+                    "( %u, %u, 0x%x, 0x%x, 0x%x )\n",
+                    cond, cc_op, cc_dep1, cc_dep2, cc_dep3 );
+         vpanic("armg_calculate_condition(ARM)");
    }
 }
 
 
+/*---------------------------------------------------------------*/
+/*--- Flag-helpers translation-time function specialisers.    ---*/
+/*--- These help iropt specialise calls the above run-time    ---*/
+/*--- flags functions.                                        ---*/
+/*---------------------------------------------------------------*/
+
 /* Used by the optimiser to try specialisations.  Returns an
    equivalent expression, or NULL if none. */
 
-#if 0
-/* temporarily unused */
 static Bool isU32 ( IRExpr* e, UInt n )
 {
-   return (e->tag == Iex_Const
-           && e->Iex.Const.con->tag == Ico_U32
-           && e->Iex.Const.con->Ico.U32 == n);
+   return
+      toBool( e->tag == Iex_Const
+              && e->Iex.Const.con->tag == Ico_U32
+              && e->Iex.Const.con->Ico.U32 == n );
 }
-#endif
+
 IRExpr* guest_arm_spechelper ( HChar* function_name,
                                IRExpr** args )
 {
+#  define unop(_op,_a1) IRExpr_Unop((_op),(_a1))
+#  define binop(_op,_a1,_a2) IRExpr_Binop((_op),(_a1),(_a2))
+#  define mkU32(_n) IRExpr_Const(IRConst_U32(_n))
+#  define mkU8(_n)  IRExpr_Const(IRConst_U8(_n))
+
+   Int i, arity = 0;
+   for (i = 0; args[i]; i++)
+      arity++;
+#  if 0
+   vex_printf("spec request:\n");
+   vex_printf("   %s  ", function_name);
+   for (i = 0; i < arity; i++) {
+      vex_printf("  ");
+      ppIRExpr(args[i]);
+   }
+   vex_printf("\n");
+#  endif
+
+   /* --------- specialising "x86g_calculate_condition" --------- */
+
+   if (vex_streq(function_name, "armg_calculate_condition")) {
+      /* specialise calls to above "armg_calculate condition" function */
+      IRExpr *cond_n_op, *cc_dep1, *cc_dep2, *cc_dep3;
+      vassert(arity == 4);
+      cond_n_op = args[0]; /* ARMCondcode << 4  |  ARMG_CC_OP_* */
+      cc_dep1   = args[1];
+      cc_dep2   = args[2];
+      cc_dep3   = args[3];
+
+      /*---------------- SUB ----------------*/
+
+      if (isU32(cond_n_op, (ARMCondEQ << 4) | ARMG_CC_OP_SUB)) {
+         /* EQ after SUB --> test argL == argR */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpEQ32, cc_dep1, cc_dep2));
+      }
+      if (isU32(cond_n_op, (ARMCondNE << 4) | ARMG_CC_OP_SUB)) {
+         /* NE after SUB --> test argL != argR */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpNE32, cc_dep1, cc_dep2));
+      }
+
+      if (isU32(cond_n_op, (ARMCondLE << 4) | ARMG_CC_OP_SUB)) {
+         /* LE after SUB --> test argL <=s argR */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpLE32S, cc_dep1, cc_dep2));
+      }
+
+      if (isU32(cond_n_op, (ARMCondLT << 4) | ARMG_CC_OP_SUB)) {
+         /* LE after SUB --> test argL <s argR */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpLT32S, cc_dep1, cc_dep2));
+      }
+
+      if (isU32(cond_n_op, (ARMCondGE << 4) | ARMG_CC_OP_SUB)) {
+         /* GE after SUB --> test argL >=s argR
+                         --> test argR <=s argL */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpLE32S, cc_dep2, cc_dep1));
+      }
+
+      if (isU32(cond_n_op, (ARMCondHS << 4) | ARMG_CC_OP_SUB)) {
+         /* HS after SUB --> test argL >=u argR
+                         --> test argR <=u argL */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpLE32U, cc_dep2, cc_dep1));
+      }
+
+      if (isU32(cond_n_op, (ARMCondLS << 4) | ARMG_CC_OP_SUB)) {
+         /* LS after SUB --> test argL <=u argR */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpLE32U, cc_dep1, cc_dep2));
+      }
+
+      /*---------------- LOGIC ----------------*/
+      if (isU32(cond_n_op, (ARMCondEQ << 4) | ARMG_CC_OP_LOGIC)) {
+         /* EQ after LOGIC --> test res == 0 */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpEQ32, cc_dep1, mkU32(0)));
+      }
+      if (isU32(cond_n_op, (ARMCondNE << 4) | ARMG_CC_OP_LOGIC)) {
+         /* NE after LOGIC --> test res != 0 */
+         return unop(Iop_1Uto32,
+                     binop(Iop_CmpNE32, cc_dep1, mkU32(0)));
+      }
+
+   }
+
+#  undef unop
+#  undef binop
+#  undef mkU32
+#  undef mkU8
+
    return NULL;
 }
 
@@ -327,21 +418,21 @@ void LibVEX_GuestARM_put_flags ( UInt flags_native,
    vex_state->guest_CC_OP   = ARMG_CC_OP_COPY;
    vex_state->guest_CC_DEP1 = flags_native;
    vex_state->guest_CC_DEP2 = 0;
+   vex_state->guest_CC_NDEP = 0;
 }
 #endif
 
 /* VISIBLE TO LIBVEX CLIENT */
-UInt LibVEX_GuestARM_get_flags ( /*IN*/VexGuestARMState* vex_state )
+UInt LibVEX_GuestARM_get_cpsr ( /*IN*/VexGuestARMState* vex_state )
 {
-   UInt flags;
-   vassert(0); // FIXME
-
-   flags = armg_calculate_flags_all(
+   UInt nzcv;
+   nzcv = armg_calculate_flags_nzcv(
               vex_state->guest_CC_OP,
               vex_state->guest_CC_DEP1,
-              vex_state->guest_CC_DEP2
+              vex_state->guest_CC_DEP2,
+              vex_state->guest_CC_NDEP
            );
-   return flags;
+   return nzcv;
 }
 
 /* VISIBLE TO LIBVEX CLIENT */
@@ -364,17 +455,43 @@ void LibVEX_GuestARM_initialise ( /*OUT*/VexGuestARMState* vex_state )
    vex_state->guest_R14 = 0;
    vex_state->guest_R15 = 0;
 
-   // CAB: Want this?
-   //vex_state->guest_SYSCALLNO = 0;
-
-   vex_state->guest_CC_OP   = 0;// CAB: ? ARMG_CC_OP_COPY;
+   vex_state->guest_CC_OP   = ARMG_CC_OP_COPY;
    vex_state->guest_CC_DEP1 = 0;
    vex_state->guest_CC_DEP2 = 0;
-
-   // CAB: Want this?   
-   //vex_state->guest_EMWARN = 0;
-
-   vex_state->guest_SYSCALLNO = 0;
+   vex_state->guest_CC_NDEP = 0;
+
+   vex_state->guest_EMWARN  = 0;
+   vex_state->guest_TISTART = 0;
+   vex_state->guest_TILEN   = 0;
+   vex_state->guest_NRADDR  = 0;
+   vex_state->guest_IP_AT_SYSCALL = 0;
+
+   vex_state->guest_D0  = 0;
+   vex_state->guest_D1  = 0;
+   vex_state->guest_D2  = 0;
+   vex_state->guest_D3  = 0;
+   vex_state->guest_D4  = 0;
+   vex_state->guest_D5  = 0;
+   vex_state->guest_D6  = 0;
+   vex_state->guest_D7  = 0;
+   vex_state->guest_D8  = 0;
+   vex_state->guest_D9  = 0;
+   vex_state->guest_D10 = 0;
+   vex_state->guest_D11 = 0;
+   vex_state->guest_D12 = 0;
+   vex_state->guest_D13 = 0;
+   vex_state->guest_D14 = 0;
+   vex_state->guest_D15 = 0;
+
+   /* ARM encoded; zero is the default as it happens (result flags
+      (NZCV) cleared, FZ disabled, round to nearest, non-vector mode,
+      all exns masked, all exn sticky bits cleared). */
+   vex_state->guest_FPSCR = 0;
+
+   vex_state->guest_TPIDRURO = 0;
+
+   /* vex_state->padding1 = 0; */
+   /* vex_state->padding2 = 0; */
 }
 
 
@@ -387,32 +504,40 @@ void LibVEX_GuestARM_initialise ( /*OUT*/VexGuestARMState* vex_state )
    .. maxoff requires precise memory exceptions.  If in doubt return
    True (but this is generates significantly slower code).  
 
-   We enforce precise exns for guest %ESP and %EIP only.
+   We enforce precise exns for guest R13(sp), R15(pc).
 */
 Bool guest_arm_state_requires_precise_mem_exns ( Int minoff, 
                                                  Int maxoff)
 {
-   return True; // FIXME (also comment above)
-#if 0
-   Int esp_min = offsetof(VexGuestX86State, guest_ESP);
-   Int esp_max = esp_min + 4 - 1;
-   Int eip_min = offsetof(VexGuestX86State, guest_EIP);
-   Int eip_max = eip_min + 4 - 1;
+   Int sp_min = offsetof(VexGuestARMState, guest_R13);
+   Int sp_max = sp_min + 4 - 1;
+   Int pc_min = offsetof(VexGuestARMState, guest_R15);
+   Int pc_max = pc_min + 4 - 1;
 
-   if (maxoff < esp_min || minoff > esp_max) {
-      /* no overlap with esp */
+   if (maxoff < sp_min || minoff > sp_max) {
+      /* no overlap with sp */
    } else {
       return True;
    }
 
-   if (maxoff < eip_min || minoff > eip_max) {
-      /* no overlap with eip */
+   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 r11_min = offsetof(VexGuestARMState, guest_R11);
+   Int r11_max = r11_min + 4 - 1;
+
+   if (maxoff < r11_min || minoff > r11_max) {
+      /* no overlap with pc */
    } else {
       return True;
    }
 
    return False;
-#endif
 }
 
 
@@ -437,14 +562,21 @@ VexGuestLayout
 
           /* Describe any sections to be regarded by Memcheck as
              'always-defined'. */
-          .n_alwaysDefd = 2,
+          .n_alwaysDefd = 9,
+
           /* flags thunk: OP is always defd, whereas DEP1 and DEP2
              have to be tracked.  See detailed comment in gdefs.h on
              meaning of thunk fields. */
-
-          .alwaysDefd 
-             = { /*  0 */ ALWAYSDEFD(guest_CC_OP),
-                 /*  1 */ ALWAYSDEFD(guest_SYSCALLNO)
+          .alwaysDefd
+             = { /* 0 */ ALWAYSDEFD(guest_R15),
+                 /* 1 */ ALWAYSDEFD(guest_CC_OP),
+                 /* 2 */ ALWAYSDEFD(guest_CC_NDEP),
+                 /* 3 */ ALWAYSDEFD(guest_EMWARN),
+                 /* 4 */ ALWAYSDEFD(guest_TISTART),
+                 /* 5 */ ALWAYSDEFD(guest_TILEN),
+                 /* 6 */ ALWAYSDEFD(guest_NRADDR),
+                 /* 7 */ ALWAYSDEFD(guest_IP_AT_SYSCALL),
+                 /* 8 */ ALWAYSDEFD(guest_TPIDRURO)
                }
         };
 
index fb6a6b73e4b21b81b15759578b3fda4f2a22c446..ec13011e38d4c781fdb4b168ffebf67a8170d097 100644 (file)
    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.
+*/
+
+/* Limitations, etc
+
+   - pretty dodgy exception semantics for {LD,ST}Mxx, no doubt
+
+   - SWP: the restart jump back is Ijk_Boring; it should be
+     Ijk_NoRedir but that's expensive.  See comments on casLE() in
+     guest_x86_toIR.c.
+
+*/
+
+/* "Special" instructions.
+
+   This instruction decoder can decode four special instructions
+   which mean nothing natively (are no-ops as far as regs/mem are
+   concerned) but have meaning for supporting Valgrind.  A special
+   instruction is flagged by a 16-byte preamble:
 
-   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.
+      E1A0C1EC E1A0C6EC E1A0CEEC E1A0C9EC
+      (mov r12, r12, ROR #3;   mov r12, r12, ROR #13;
+       mov r12, r12, ROR #29;  mov r12, r12, ROR #19)
+
+   Following that, one of the following 3 are allowed
+   (standard interpretation in parentheses):
+
+      E18AA00A (orr r10,r10,r10)   R3 = client_request ( R4 )
+      E18BB00B (orr r11,r11,r11)   R3 = guest_NRADDR
+      E18CC00C (orr r12,r12,r12)   branch-and-link-to-noredir R4
+
+   Any other bytes following the 16-byte preamble are illegal and
+   constitute a failure in instruction decoding.  This all assumes
+   that the preamble will never occur except in specific code
+   fragments designed for Valgrind to catch.
 */
 
-/* Translates ARM(v4) code to IR. */
+/* Translates ARM(v5) code to IR. */
 
 #include "libvex_basictypes.h"
 #include "libvex_ir.h"
@@ -53,6 +82,7 @@
 
 #include "main_util.h"
 #include "main_globals.h"
+#include "guest_generic_bb_to_IR.h"
 #include "guest_arm_defs.h"
 
 
 /*--- Globals                                              ---*/
 /*------------------------------------------------------------*/
 
-/* These are set at the start of the translation of a BB, so that we
-   don't have to pass them around endlessly.  CONST means does not
-   change during translation of a bb. 
+/* 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.
 */
 
-/* We need to know this to do sub-register accesses correctly. */
-/* CONST */
+/* 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. */
-/* CONST */
-static UChar* guest_code;
-
-/* The guest address corresponding to guest_code[0]. */
-/* CONST */
-static Addr32 guest_pc_bbstart;
+/* CONST: The guest address for the instruction currently being
+   translated. */
+static Addr32 guest_R15_curr_instr;
 
-/* The IRSB* into which we're generating code. */
+/* MOD: The IRSB* into which we're generating code. */
 static IRSB* irsb;
 
+/* These are to do with handling writes to r15.  They are initially
+   set at the start of disInstr_ARM_WRK to indicate no update,
+   possibly updated during the routine, and examined again at the end.
+   If they have been set to indicate a r15 update then a jump is
+   generated.  Note, "explicit" jumps (b, bx, etc) are generated
+   directly, not using this mechanism -- this is intended to handle
+   the implicit-style jumps resulting from (eg) assigning to r15 as
+   the result of insns we wouldn't normally consider branchy. */
+
+/* MOD.  Initially False; set to True iff abovementioned handling is
+   required. */
+static Bool r15written;
+
+/* MOD.  Initially IRTemp_INVALID.  If the r15 branch to be generated
+   is conditional, this holds the gating IRTemp :: Ity_I32.  If the
+   branch to be generated is unconditional, this remains
+   IRTemp_INVALID. */
+static IRTemp r15guard; /* :: Ity_I32, 0 or 1 */
+
+/* MOD.  Initially Ijk_Boring.  If an r15 branch is to be generated,
+   this holds the jump kind. */
+static IRTemp r15kind;
+
 
 /*------------------------------------------------------------*/
 /*--- Debugging output                                     ---*/
@@ -94,2099 +144,4607 @@ static IRSB* irsb;
       vex_sprintf(buf, format, ## args)
 
 
-
-
-/*------------------------------------------------------------*/
-/*--- Offsets of various parts of the arm guest state.     ---*/
-/*------------------------------------------------------------*/
-
-#define OFFB_R0       offsetof(VexGuestARMState,guest_R0)
-#define OFFB_R1       offsetof(VexGuestARMState,guest_R1)
-#define OFFB_R2       offsetof(VexGuestARMState,guest_R2)
-#define OFFB_R3       offsetof(VexGuestARMState,guest_R3)
-#define OFFB_R4       offsetof(VexGuestARMState,guest_R4)
-#define OFFB_R5       offsetof(VexGuestARMState,guest_R5)
-#define OFFB_R6       offsetof(VexGuestARMState,guest_R6)
-#define OFFB_R7       offsetof(VexGuestARMState,guest_R7)
-#define OFFB_R8       offsetof(VexGuestARMState,guest_R8)
-#define OFFB_R9       offsetof(VexGuestARMState,guest_R9)
-#define OFFB_R10      offsetof(VexGuestARMState,guest_R10)
-#define OFFB_R11      offsetof(VexGuestARMState,guest_R11)
-#define OFFB_R12      offsetof(VexGuestARMState,guest_R12)
-#define OFFB_R13      offsetof(VexGuestARMState,guest_R13)
-#define OFFB_R14      offsetof(VexGuestARMState,guest_R14)
-#define OFFB_R15      offsetof(VexGuestARMState,guest_R15)
-
-// CAB: ? guest_SYSCALLNO;
-
-#define OFFB_CC_OP    offsetof(VexGuestARMState,guest_CC_OP)
-#define OFFB_CC_DEP1  offsetof(VexGuestARMState,guest_CC_DEP1)
-#define OFFB_CC_DEP2  offsetof(VexGuestARMState,guest_CC_DEP2)
-
-// CAB: ? guest_EMWARN;
-
-
 /*------------------------------------------------------------*/
-/*--- Disassemble an entire basic block                    ---*/
+/*--- Helper bits and pieces for deconstructing the        ---*/
+/*--- arm insn stream.                                     ---*/
 /*------------------------------------------------------------*/
 
-/* The results of disassembling an instruction.  There are three
-   possible outcomes.  For Dis_Resteer, the disassembler _must_
-   continue at the specified address.  For Dis_StopHere, the
-   disassembler _must_ terminate the BB.  For Dis_Continue, we may at
-   our option either disassemble the next insn, or terminate the BB;
-   but in the latter case we must set the bb's ->next field to point
-   to the next instruction.  */
-
-typedef
-   enum { 
-      Dis_StopHere, /* this insn terminates the BB; we must stop. */
-      Dis_Continue, /* we can optionally continue into the next insn */
-      Dis_Resteer   /* followed a branch; continue at the spec'd addr */
-   }
-   DisResult;
-
-
-/* forward decls .. */
-static IRExpr* mkU32 ( UInt i );
-static void stmt ( IRStmt* st );
-
-
-/* disInstr disassembles an instruction located at &guest_code[delta],
-   and sets *size to its size.  If the returned value is Dis_Resteer,
-   the next guest address is assigned to *whereNext.  disInstr is not
-   permitted to return Dis_Resteer if either (1) resteerOK is False,
-   or (2) resteerOkFn, when applied to the address which it wishes to
-   resteer into, returns False.  */
-   
-static DisResult disInstr ( /*IN*/  Bool    resteerOK,
-                            /*IN*/  Bool    (*resteerOkFn) ( Addr64 ),
-                            /*IN*/  Long    delta, 
-                            /*OUT*/ Int*    size,
-                            /*OUT*/ Addr64* whereNext );
-
+/* Do a little-endian load of a 32-bit word, regardless of the
+   endianness of the underlying host. */
+static UInt getUIntLittleEndianly ( UChar* p )
+{
+   UInt w = 0;
+   w = (w << 8) | p[3];
+   w = (w << 8) | p[2];
+   w = (w << 8) | p[1];
+   w = (w << 8) | p[0];
+   return w;
+}
 
-/* This is the main (only, in fact) entry point for this module. */
+static UInt ROR32 ( UInt x, UInt sh ) {
+   vassert(sh >= 0 && sh < 32);
+   if (sh == 0)
+      return x;
+   else
+      return (x << (32-sh)) | (x >> sh);
+}
 
-/* Disassemble a complete basic block, starting at guest_pc_start, and
-   dumping the IR into global irsb.  Returns the size, in bytes, of
-   the basic block.  
-*/
-IRSB* bbToIR_ARM ( UChar*           armCode, 
-                   Addr64           guest_pc_start, 
-                   VexGuestExtents* vge,
-                   Bool             (*byte_accessible)(Addr64),
-                   Bool             (*chase_into_ok)(Addr64),
-                   Bool             host_bigendian,
-                   VexArchInfo*     archinfo_guest )
-{
-   Long       delta;
-   Int        i, n_instrs, size, first_stmt_idx;
-   Addr64     guest_next;
-   Bool       resteerOK;
-   DisResult  dres;
-   static Int n_resteers = 0;
-   Int        d_resteers = 0;
-
-   /* check sanity .. */
-   vassert(vex_control.guest_max_insns >= 1);
-   vassert(vex_control.guest_max_insns < 500);
-   vassert(vex_control.guest_chase_thresh >= 0);
-   vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns);
-
-   vassert(archinfo_guest->hwcaps == 0);
-
-   /* Start a new, empty extent. */
-   vge->n_used  = 1;
-   vge->base[0] = guest_pc_start;
-   vge->len[0]  = 0;
-
-   /* Set up globals. */
-   host_is_bigendian = host_bigendian;
-   guest_code        = armCode;
-   guest_pc_bbstart  = (Addr32)guest_pc_start;
-   irsb              = emptyIRSB();
-
-   vassert((guest_pc_start >> 32) == 0);
-
-   /* Delta keeps track of how far along the armCode array we
-      have so far gone. */
-   delta             = 0;
-   n_instrs          = 0;
-
-   while (True) {
-      vassert(n_instrs < vex_control.guest_max_insns);
-
-      guest_next = 0;
-      resteerOK = toBool(n_instrs < vex_control.guest_chase_thresh);
-      first_stmt_idx = irsb->stmts_used;
-
-      if (n_instrs > 0) {
-         /* for the first insn, the dispatch loop will have set
-            R15, but for all the others we have to do it ourselves. */
-         stmt( IRStmt_Put( OFFB_R15, mkU32(toUInt(guest_pc_bbstart + delta))) );
-      }
-
-      dres = disInstr( resteerOK, chase_into_ok, 
-                       delta, &size, &guest_next );
-
-      /* Print the resulting IR, if needed. */
-      if (vex_traceflags & VEX_TRACE_FE) {
-         for (i = first_stmt_idx; i < irsb->stmts_used; i++) {
-            vex_printf("              ");
-            ppIRStmt(irsb->stmts[i]);
-            vex_printf("\n");
-         }
-      }
-   
-      if (dres == Dis_StopHere) {
-         vassert(irsb->next != NULL);
-         if (vex_traceflags & VEX_TRACE_FE) {
-            vex_printf("              ");
-            vex_printf( "goto {");
-            ppIRJumpKind(irsb->jumpkind);
-            vex_printf( "} ");
-            ppIRExpr( irsb->next );
-            vex_printf( "\n");
-         }
-      }
+#define BITS2(_b1,_b0) \
+   (((_b1) << 1) | (_b0))
 
-      delta += size;
-      vge->len[vge->n_used-1] = toUShort(vge->len[vge->n_used-1] + size);
-      n_instrs++;
-      DIP("\n");
+#define BITS3(_b2,_b1,_b0)                      \
+  (((_b2) << 2) | ((_b1) << 1) | (_b0))
 
-      vassert(size > 0 && size <= 18);
-      if (!resteerOK) 
-         vassert(dres != Dis_Resteer);
-      if (dres != Dis_Resteer) 
-         vassert(guest_next == 0);
+#define BITS4(_b3,_b2,_b1,_b0) \
+   (((_b3) << 3) | ((_b2) << 2) | ((_b1) << 1) | (_b0))
 
-      switch (dres) {
-      case Dis_Continue:
-         vassert(irsb->next == NULL);
-         if (n_instrs < vex_control.guest_max_insns) {
-            /* keep going */
-         } else {
-            irsb->next = mkU32(toUInt(guest_pc_start+delta));
-            return irsb;
-         }
-         break;
-      case Dis_StopHere:
-         vassert(irsb->next != NULL);
-         return irsb;
-      case Dis_Resteer:
-         vpanic("bbToIR_ARM: Dis_Resteer: fixme");
-         /* need to add code here to start a new extent ... */
-         vassert(irsb->next == NULL);
-         /* figure out a new delta to continue at. */
-         vassert(chase_into_ok(guest_next));
-         delta = guest_next - guest_pc_start;
-         n_resteers++;
-         d_resteers++;
-         if (0 && (n_resteers & 0xFF) == 0)
-            vex_printf("resteer[%d,%d] to %p (delta = %lld)\n",
-                       n_resteers, d_resteers,
-                       ULong_to_Ptr(guest_next), delta);
-         break;
-      }
-   }
-}
+#define BITS8(_b7,_b6,_b5,_b4,_b3,_b2,_b1,_b0)  \
+   ((BITS4((_b7),(_b6),(_b5),(_b4)) << 4) \
+    | BITS4((_b3),(_b2),(_b1),(_b0)))
 
 
 /*------------------------------------------------------------*/
-/*--- Helper bits and pieces for deconstructing the        ---*/
-/*--- ARM insn stream.                                     ---*/
+/*--- Helper bits and pieces for creating IR fragments.    ---*/
 /*------------------------------------------------------------*/
 
-/* Add a statement to the list held by "irsb". */
-static void stmt ( IRStmt* st )
-{
-   addStmtToIRSB( irsb, st );
-}
-
-/* Generate a new temporary of the given type. */
-static IRTemp newTemp ( IRType ty )
+static IRExpr* mkU32 ( UInt i )
 {
-   vassert(isPlausibleIRType(ty));
-   return newIRTemp( irsb->tyenv, ty );
+   return IRExpr_Const(IRConst_U32(i));
 }
 
-#if 0
-/* Bomb out if we can't handle something. */
-__attribute__ ((noreturn))
-static void unimplemented ( Char* str )
+static IRExpr* mkU8 ( UInt i )
 {
-   vex_printf("armToIR: unimplemented feature\n");
-   vpanic(str);
+   vassert(i < 256);
+   return IRExpr_Const(IRConst_U8( (UChar)i ));
 }
-#endif
 
-/* Various simple conversions */
-
-#if 0
-static UInt extend_s_8to32( UInt x )
+static IRExpr* mkexpr ( IRTemp tmp )
 {
-   return (UInt)((((Int)x) << 24) >> 24);
+   return IRExpr_RdTmp(tmp);
 }
 
-static UInt extend_s_16to32 ( UInt x )
+static IRExpr* unop ( IROp op, IRExpr* a )
 {
-   return (UInt)((((Int)x) << 16) >> 16);
+   return IRExpr_Unop(op, a);
 }
-#endif
 
-static UInt extend_s_24to32 ( UInt x )
+static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
 {
-   return (UInt)((((Int)x) << 8) >> 8);
+   return IRExpr_Binop(op, a1, a2);
 }
 
-#if 0
-/* Fetch a byte from the guest insn stream. */
-static UChar getIByte ( UInt delta )
+static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 )
 {
-   return guest_code[delta];
+   return IRExpr_Triop(op, a1, a2, a3);
 }
-#endif
-
-/* Get a 8/16/32-bit unsigned value out of the insn stream. */
 
-#if 0
-static UInt getUChar ( UInt delta )
+static IRExpr* loadLE ( IRType ty, IRExpr* addr )
 {
-   UInt v = guest_code[delta+0];
-   return v & 0xFF;
+   return IRExpr_Load(Iend_LE, ty, addr);
 }
-#endif
 
-#if 0
-static UInt getUDisp16 ( UInt delta )
+/* Add a statement to the list held by "irbb". */
+static void stmt ( IRStmt* st )
 {
-   UInt v = guest_code[delta+1]; v <<= 8;
-   v |= guest_code[delta+0];
-   return v & 0xFFFF;
+   addStmtToIRSB( irsb, st );
 }
-#endif
 
-#if 0
-static UInt getUDisp32 ( UInt delta )
+static void assign ( IRTemp dst, IRExpr* e )
 {
-   UInt v = guest_code[delta+3]; v <<= 8;
-   v |= guest_code[delta+2]; v <<= 8;
-   v |= guest_code[delta+1]; v <<= 8;
-   v |= guest_code[delta+0];
-   return v;
+   stmt( IRStmt_WrTmp(dst, e) );
 }
-#endif
 
-#if 0
-static UInt getUDisp ( Int size, UInt delta )
+static void storeLE ( IRExpr* addr, IRExpr* data )
 {
-   switch (size) {
-   case 4: return getUDisp32(delta);
-   case 2: return getUDisp16(delta);
-   case 1: return getUChar(delta);
-   default: vpanic("getUDisp(ARM)");
-   }
-   return 0; /*notreached*/
+   stmt( IRStmt_Store(Iend_LE, addr, data) );
 }
-#endif
 
-#if 0
-/* Get a byte value out of the insn stream and sign-extend to 32
-   bits. */
-static UInt getSDisp8 ( UInt delta )
+/* Generate a new temporary of the given type. */
+static IRTemp newTemp ( IRType ty )
 {
-   return extend_s_8to32( (UInt) (guest_code[delta]) );
+   vassert(isPlausibleIRType(ty));
+   return newIRTemp( irsb->tyenv, ty );
 }
-#endif
 
-#if 0
-static UInt getSDisp16 ( UInt delta0 )
+/* Produces a value in 0 .. 3, which is encoded as per the type
+   IRRoundingMode. */
+static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void )
 {
-   UChar* eip = (UChar*)(&guest_code[delta0]);
-   UInt d = *eip++;
-   d |= ((*eip++) << 8);
-   return extend_s_16to32(d);
+   return mkU32(Irrm_NEAREST);
 }
-#endif
 
-#if 0
-static UInt getSDisp ( Int size, UInt delta )
+/* Generate an expression for SRC rotated right by ROT. */
+static IRExpr* genROR32( IRTemp src, Int rot )
 {
-   switch (size) {
-   case 4: return getUDisp32(delta);
-   case 2: return getSDisp16(delta);
-   case 1: return getSDisp8(delta);
-   default: vpanic("getSDisp(ARM)");
-   }
-   return 0; /*notreached*/
+   vassert(rot >= 0 && rot < 32);
+   if (rot == 0)
+      return mkexpr(src);
+   return
+      binop(Iop_Or32,
+            binop(Iop_Shl32, mkexpr(src), mkU8(32 - rot)),
+            binop(Iop_Shr32, mkexpr(src), mkU8(rot)));
 }
-#endif
 
 
 /*------------------------------------------------------------*/
-/*--- Helpers for constructing IR.                         ---*/
+/*--- Helpers for accessing guest registers.               ---*/
 /*------------------------------------------------------------*/
 
-/* Create a 1/2/4 byte read of an x86 integer registers.  For 16/8 bit
-   register references, we need to take the host endianness into
-   account.  Supplied value is 0 .. 7 and in the Intel instruction
-   encoding. */
+#define OFFB_R0       offsetof(VexGuestARMState,guest_R0)
+#define OFFB_R1       offsetof(VexGuestARMState,guest_R1)
+#define OFFB_R2       offsetof(VexGuestARMState,guest_R2)
+#define OFFB_R3       offsetof(VexGuestARMState,guest_R3)
+#define OFFB_R4       offsetof(VexGuestARMState,guest_R4)
+#define OFFB_R5       offsetof(VexGuestARMState,guest_R5)
+#define OFFB_R6       offsetof(VexGuestARMState,guest_R6)
+#define OFFB_R7       offsetof(VexGuestARMState,guest_R7)
+#define OFFB_R8       offsetof(VexGuestARMState,guest_R8)
+#define OFFB_R9       offsetof(VexGuestARMState,guest_R9)
+#define OFFB_R10      offsetof(VexGuestARMState,guest_R10)
+#define OFFB_R11      offsetof(VexGuestARMState,guest_R11)
+#define OFFB_R12      offsetof(VexGuestARMState,guest_R12)
+#define OFFB_R13      offsetof(VexGuestARMState,guest_R13)
+#define OFFB_R14      offsetof(VexGuestARMState,guest_R14)
+#define OFFB_R15      offsetof(VexGuestARMState,guest_R15)
 
-#if 0
-static IRType szToITy ( Int n )
+#define OFFB_CC_OP    offsetof(VexGuestARMState,guest_CC_OP)
+#define OFFB_CC_DEP1  offsetof(VexGuestARMState,guest_CC_DEP1)
+#define OFFB_CC_DEP2  offsetof(VexGuestARMState,guest_CC_DEP2)
+#define OFFB_CC_NDEP  offsetof(VexGuestARMState,guest_CC_NDEP)
+#define OFFB_NRADDR   offsetof(VexGuestARMState,guest_NRADDR)
+
+#define OFFB_D0       offsetof(VexGuestARMState,guest_D0)
+#define OFFB_D1       offsetof(VexGuestARMState,guest_D1)
+#define OFFB_D2       offsetof(VexGuestARMState,guest_D2)
+#define OFFB_D3       offsetof(VexGuestARMState,guest_D3)
+#define OFFB_D4       offsetof(VexGuestARMState,guest_D4)
+#define OFFB_D5       offsetof(VexGuestARMState,guest_D5)
+#define OFFB_D6       offsetof(VexGuestARMState,guest_D6)
+#define OFFB_D7       offsetof(VexGuestARMState,guest_D7)
+#define OFFB_D8       offsetof(VexGuestARMState,guest_D8)
+#define OFFB_D9       offsetof(VexGuestARMState,guest_D9)
+#define OFFB_D10      offsetof(VexGuestARMState,guest_D10)
+#define OFFB_D11      offsetof(VexGuestARMState,guest_D11)
+#define OFFB_D12      offsetof(VexGuestARMState,guest_D12)
+#define OFFB_D13      offsetof(VexGuestARMState,guest_D13)
+#define OFFB_D14      offsetof(VexGuestARMState,guest_D14)
+#define OFFB_D15      offsetof(VexGuestARMState,guest_D15)
+
+#define OFFB_FPSCR    offsetof(VexGuestARMState,guest_FPSCR)
+#define OFFB_TPIDRURO offsetof(VexGuestARMState,guest_TPIDRURO)
+
+
+/* ---------------- Integer registers ---------------- */
+
+static Int integerGuestRegOffset ( UInt iregNo )
 {
-   switch (n) {
-   case 1: return Ity_I8;
-   case 2: return Ity_I16;
-   case 4: return Ity_I32;
-   default: vpanic("szToITy(ARM)");
+   /* 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
+      ARM. */
+   switch (iregNo) {
+      case 0:  return OFFB_R0;
+      case 1:  return OFFB_R1;
+      case 2:  return OFFB_R2;
+      case 3:  return OFFB_R3;
+      case 4:  return OFFB_R4;
+      case 5:  return OFFB_R5;
+      case 6:  return OFFB_R6;
+      case 7:  return OFFB_R7;
+      case 8:  return OFFB_R8;
+      case 9:  return OFFB_R9;
+      case 10: return OFFB_R10;
+      case 11: return OFFB_R11;
+      case 12: return OFFB_R12;
+      case 13: return OFFB_R13;
+      case 14: return OFFB_R14;
+      case 15: return OFFB_R15;
+      default: vassert(0);
    }
 }
-#endif
 
-static Int integerGuestRegOffset ( UInt archreg )
+/* Plain ("low level") read from a reg; no +8 offset magic for r15. */
+static IRExpr* llGetIReg ( UInt iregNo )
 {
-   vassert(archreg < 16);
-
-   vassert(!host_is_bigendian);   //TODO: is this necessary?
-   // jrs: probably not; only matters if we reference sub-parts
-   // of the arm registers, but that isn't the case
-   switch (archreg) {
-   case  0: return offsetof(VexGuestARMState,guest_R0);
-   case  1: return offsetof(VexGuestARMState,guest_R1);
-   case  2: return offsetof(VexGuestARMState,guest_R2);
-   case  3: return offsetof(VexGuestARMState,guest_R3);
-   case  4: return offsetof(VexGuestARMState,guest_R4);
-   case  5: return offsetof(VexGuestARMState,guest_R5);
-   case  6: return offsetof(VexGuestARMState,guest_R6);
-   case  7: return offsetof(VexGuestARMState,guest_R7);
-   case  8: return offsetof(VexGuestARMState,guest_R8);
-   case  9: return offsetof(VexGuestARMState,guest_R9);
-   case 10: return offsetof(VexGuestARMState,guest_R10);
-   case 11: return offsetof(VexGuestARMState,guest_R11);
-   case 12: return offsetof(VexGuestARMState,guest_R12);
-   case 13: return offsetof(VexGuestARMState,guest_R13);
-   case 14: return offsetof(VexGuestARMState,guest_R14);
-   case 15: return offsetof(VexGuestARMState,guest_R15);
-   }
-
-   vpanic("integerGuestRegOffset(arm,le)"); /*notreached*/
+   vassert(iregNo < 16);
+   return IRExpr_Get( integerGuestRegOffset(iregNo), Ity_I32 );
 }
 
-static IRExpr* getIReg ( UInt archreg )
+/* Architected read from a reg.  This automagically adds 8 to all 
+   reads of r15. */
+static IRExpr* getIReg ( UInt iregNo )
 {
-   vassert(archreg < 16);
-   return IRExpr_Get( integerGuestRegOffset(archreg), Ity_I32 );
+   IRExpr* e;
+   vassert(iregNo < 16);
+   if (iregNo == 15) {
+      /* If asked for r15, don't read the guest state value, as that
+         may not be up to date in the case where loop unrolling has
+         happened, because the first insn's write to the block is
+         omitted; hence in the 2nd and subsequent unrollings we don't
+         have a correct value in guest r15.  Instead produce the
+         constant that we know would be produced at this point. */
+      e = mkU32(guest_R15_curr_instr + 8);
+   } else {
+      e = IRExpr_Get( integerGuestRegOffset(iregNo), Ity_I32 );
+   }
+   return e;
 }
 
-/* Ditto, but write to a reg instead. */
-static void putIReg ( UInt archreg, IRExpr* e )
+/* Plain ("low level") write to a reg; no jump or alignment magic for
+   r15. */
+static void llPutIReg ( UInt iregNo, IRExpr* e )
 {
-   vassert(archreg < 16);
-   stmt( IRStmt_Put(integerGuestRegOffset(archreg), e) );
+   vassert(iregNo < 16);
+   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
+   stmt( IRStmt_Put(integerGuestRegOffset(iregNo), e) );
 }
 
-static void assign ( IRTemp dst, IRExpr* e )
+/* Architected write to a reg.  If it is to r15, record info so at the
+   end of this insn's translation, a branch to it can be made.  Also
+   handles conditional writes to the register:
+   if guardT == IRTemp_INVALID then the write is unconditional.
+   If writing r15, also 4-align it. */
+static void putIReg ( UInt       iregNo,
+                      IRExpr*    e,
+                      IRTemp     guardT /* :: Ity_I32, 0 or 1 */,
+                      IRJumpKind jk /* if a jump is generated */ )
 {
-   stmt( IRStmt_WrTmp(dst, e) );
+   /* if writing r15, force e to be 4-aligned. */
+   if (iregNo == 15)
+      e = binop(Iop_And32, e, mkU32(~3));
+   /* So, generate either an unconditional or a conditional write to
+      the reg. */
+   if (guardT == IRTemp_INVALID) {
+      /* unconditional write */
+      llPutIReg( iregNo, e );
+   } else {
+      llPutIReg( iregNo,
+                 IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
+                               llGetIReg(iregNo),
+                               e ));
+   }
+   if (iregNo == 15) {
+      // assert against competing r15 updates.  Shouldn't
+      // happen; should be ruled out by the instr matching
+      // logic.
+      vassert(r15written == False);
+      vassert(r15guard   == IRTemp_INVALID);
+      vassert(r15kind    == Ijk_Boring);
+      r15written = True;
+      r15guard   = guardT;
+      r15kind    = jk;
+   }
 }
 
-static void storeLE ( IRExpr* addr, IRExpr* data )
-{
-   stmt( IRStmt_Store(Iend_LE, addr, data) );
-}
 
-static IRExpr* unop ( IROp op, IRExpr* a )
+/* ---------------- Double registers ---------------- */
+
+static Int doubleGuestRegOffset ( UInt dregNo )
 {
-   return IRExpr_Unop(op, a);
+   /* Do we care about endianness here?  Probably do if we ever get
+      into the situation of dealing with the single-precision VFP
+      registers. */
+   switch (dregNo) {
+      case 0:  return OFFB_D0;
+      case 1:  return OFFB_D1;
+      case 2:  return OFFB_D2;
+      case 3:  return OFFB_D3;
+      case 4:  return OFFB_D4;
+      case 5:  return OFFB_D5;
+      case 6:  return OFFB_D6;
+      case 7:  return OFFB_D7;
+      case 8:  return OFFB_D8;
+      case 9:  return OFFB_D9;
+      case 10: return OFFB_D10;
+      case 11: return OFFB_D11;
+      case 12: return OFFB_D12;
+      case 13: return OFFB_D13;
+      case 14: return OFFB_D14;
+      case 15: return OFFB_D15;
+      default: vassert(0);
+   }
 }
 
-static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 )
+/* Plain ("low level") read from a VFP Dreg. */
+static IRExpr* llGetDReg ( UInt dregNo )
 {
-   return IRExpr_Binop(op, a1, a2);
+   vassert(dregNo < 16);
+   return IRExpr_Get( doubleGuestRegOffset(dregNo), Ity_F64 );
 }
 
-static IRExpr* mkexpr ( IRTemp tmp )
-{
-   return IRExpr_RdTmp(tmp);
+/* Architected read from a VFP Dreg. */
+static IRExpr* getDReg ( UInt dregNo ) {
+   return llGetDReg( dregNo );
 }
 
-static IRExpr* mkU8 ( UChar i )
+/* Plain ("low level") write to a VFP Dreg. */
+static void llPutDReg ( UInt dregNo, IRExpr* e )
 {
-   return IRExpr_Const(IRConst_U8(i));
+   vassert(dregNo < 16);
+   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F64);
+   stmt( IRStmt_Put(doubleGuestRegOffset(dregNo), e) );
 }
 
-#if 0
-static IRExpr* mkU16 ( UInt i )
+/* Architected write to a VFP Dreg.  Handles conditional writes to the
+   register: if guardT == IRTemp_INVALID then the write is
+   unconditional. */
+static void putDReg ( UInt    dregNo,
+                      IRExpr* e,
+                      IRTemp  guardT /* :: Ity_I32, 0 or 1 */)
 {
-   vassert(i < 65536);
-   return IRExpr_Const(IRConst_U16(i));
+   /* So, generate either an unconditional or a conditional write to
+      the reg. */
+   if (guardT == IRTemp_INVALID) {
+      /* unconditional write */
+      llPutDReg( dregNo, e );
+   } else {
+      llPutDReg( dregNo,
+                 IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
+                               llGetDReg(dregNo),
+                               e ));
+   }
 }
-#endif
 
-static IRExpr* mkU32 ( UInt i )
+
+/* ---------------- Float registers ---------------- */
+
+static Int floatGuestRegOffset ( UInt fregNo )
 {
-   return IRExpr_Const(IRConst_U32(i));
+   /* Start with the offset of the containing double, and the correct
+      for endianness.  Actually this is completely bogus and needs
+      careful thought. */
+   Int off;
+   vassert(fregNo < 32);
+   off = doubleGuestRegOffset(fregNo >> 1);
+   if (host_is_bigendian) {
+      vassert(0);
+   } else {
+      if (fregNo & 1)
+         off += 4;
+   }
+   return off;
 }
 
-#if 0
-static IRExpr* mkU ( IRType ty, UInt i )
+/* Plain ("low level") read from a VFP Freg. */
+static IRExpr* llGetFReg ( UInt fregNo )
 {
-   if (ty == Ity_I8)  return mkU8(i);
-   if (ty == Ity_I16) return mkU16(i);
-   if (ty == Ity_I32) return mkU32(i);
-   /* If this panics, it usually means you passed a size (1,2,4)
-      value as the IRType, rather than a real IRType. */
-   vpanic("mkU(ARM)");
+   vassert(fregNo < 32);
+   return IRExpr_Get( floatGuestRegOffset(fregNo), Ity_F32 );
 }
-#endif
 
-static IRExpr* loadLE ( IRType ty, IRExpr* addr )
-{
-   return IRExpr_Load(Iend_LE, ty, addr);
+/* Architected read from a VFP Freg. */
+static IRExpr* getFReg ( UInt fregNo ) {
+   return llGetFReg( fregNo );
 }
 
-#if 0
-static IROp mkSizedOp ( IRType ty, IROp op8 )
+/* Plain ("low level") write to a VFP Freg. */
+static void llPutFReg ( UInt fregNo, IRExpr* e )
 {
-   Int adj;
-   vassert(ty == Ity_I8 || ty == Ity_I16 || ty == Ity_I32);
-   vassert(op8 == Iop_Add8 || op8 == Iop_Sub8 
-           || op8 == Iop_Mul8 
-           || op8 == Iop_Or8 || op8 == Iop_And8 || op8 == Iop_Xor8
-           || op8 == Iop_Shl8 || op8 == Iop_Shr8 || op8 == Iop_Sar8
-           || op8 == Iop_CmpEQ8 || op8 == Iop_CmpNE8
-           || op8 == Iop_Not8 );
-   adj = ty==Ity_I8 ? 0 : (ty==Ity_I16 ? 1 : 2);
-   return adj + op8;
+   vassert(fregNo < 32);
+   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_F32);
+   stmt( IRStmt_Put(floatGuestRegOffset(fregNo), e) );
 }
-#endif
 
-#if 0
-static IROp mkWidenOp ( Int szSmall, Int szBig, Bool signd )
+/* Architected write to a VFP Freg.  Handles conditional writes to the
+   register: if guardT == IRTemp_INVALID then the write is
+   unconditional. */
+static void putFReg ( UInt    fregNo,
+                      IRExpr* e,
+                      IRTemp  guardT /* :: Ity_I32, 0 or 1 */)
 {
-   if (szSmall == 1 && szBig == 4) {
-      return signd ? Iop_8Sto32 : Iop_8Uto32;
-   }
-   if (szSmall == 1 && szBig == 2) {
-      return signd ? Iop_8Sto16 : Iop_8Uto16;
-   }
-   if (szSmall == 2 && szBig == 4) {
-      return signd ? Iop_16Sto32 : Iop_16Uto32;
+   /* So, generate either an unconditional or a conditional write to
+      the reg. */
+   if (guardT == IRTemp_INVALID) {
+      /* unconditional write */
+      llPutFReg( fregNo, e );
+   } else {
+      llPutFReg( fregNo,
+                 IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
+                               llGetFReg(fregNo),
+                               e ));
    }
-   vpanic("mkWidenOp(ARM,guest)");
 }
-#endif
-
-
-
-
 
 
+/* ---------------- Misc registers ---------------- */
 
+static void putMiscReg32 ( UInt    gsoffset, 
+                           IRExpr* e, /* :: Ity_I32 */
+                           IRTemp  guardT /* :: Ity_I32, 0 or 1 */)
+{
+   switch (gsoffset) {
+      case OFFB_FPSCR: break;
+      default: vassert(0); /* awaiting more cases */
+   }
+   vassert(typeOfIRExpr(irsb->tyenv, e) == Ity_I32);
 
+   if (guardT == IRTemp_INVALID) {
+      /* unconditional write */
+      stmt(IRStmt_Put(gsoffset, e));
+   } else {
+      vassert(0); //ATC
+      stmt(IRStmt_Put( gsoffset,
+                       IRExpr_Mux0X( unop(Iop_32to8, mkexpr(guardT)),
+                                     IRExpr_Get(gsoffset, Ity_I32),
+                                     e) ));
 
+   }
+}
 
 
+/* ---------------- FPSCR stuff ---------------- */
 
+/* Generate IR to get hold of the rounding mode bits in FPSCR, and
+   convert them to IR format.  Bind the final result to the
+   returned temp. */
+static IRTemp /* :: Ity_I32 */ mk_get_IR_rounding_mode ( void )
+{
+   /* The ARMvfp encoding for rounding mode bits is:
+         00  to nearest
+         01  to +infinity
+         10  to -infinity
+         11  to zero
+      We need to convert that to the IR encoding:
+         00  to nearest (the default)
+         10  to +infinity
+         01  to -infinity
+         11  to zero
+      Which can be done by swapping bits 0 and 1.
+      The rmode bits are at 23:22 in FPSCR.
+   */
+   IRTemp armEncd = newTemp(Ity_I32);
+   IRTemp swapped = newTemp(Ity_I32);
+   /* Fish FPSCR[23:22] out, and slide to bottom.  Doesn't matter that
+      we don't zero out bits 24 and above, since the assignment to
+      'swapped' will mask them out anyway. */
+   assign(armEncd,
+          binop(Iop_Shr32, IRExpr_Get(OFFB_FPSCR, Ity_I32), mkU8(22)));
+   /* Now swap them. */
+   assign(swapped,
+          binop(Iop_Or32,
+                binop(Iop_And32,
+                      binop(Iop_Shl32, mkexpr(armEncd), mkU8(1)),
+                      mkU32(2)),
+                binop(Iop_And32,
+                      binop(Iop_Shr32, mkexpr(armEncd), mkU8(1)),
+                      mkU32(1))
+         ));
+   return swapped;
+}
 
 
 /*------------------------------------------------------------*/
-/*--- Helpers for %flags.                                 ---*/
+/*--- Helpers for flag handling and conditional insns      ---*/
 /*------------------------------------------------------------*/
 
-/* -------------- Evaluating the flags-thunk. -------------- */
+static HChar* name_ARMCondcode ( ARMCondcode cond )
+{
+   switch (cond) {
+      case ARMCondEQ:  return "{eq}";
+      case ARMCondNE:  return "{ne}";
+      case ARMCondHS:  return "{hs}";  // or 'cs'
+      case ARMCondLO:  return "{lo}";  // or 'cc'
+      case ARMCondMI:  return "{mi}";
+      case ARMCondPL:  return "{pl}";
+      case ARMCondVS:  return "{vs}";
+      case ARMCondVC:  return "{vc}";
+      case ARMCondHI:  return "{hi}";
+      case ARMCondLS:  return "{ls}";
+      case ARMCondGE:  return "{ge}";
+      case ARMCondLT:  return "{lt}";
+      case ARMCondGT:  return "{gt}";
+      case ARMCondLE:  return "{le}";
+      case ARMCondAL:  return ""; // {al}: is the default
+      case ARMCondNV:  return "{nv}";
+      default: vpanic("name_ARMCondcode");
+   }
+}
+/* and a handy shorthand for it */
+static HChar* nCC ( ARMCondcode cond ) {
+   return name_ARMCondcode(cond);
+}
+
 
-#if 0
-/* Build IR to calculate all the flags from stored
-   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.
-   Returns an expression :: Ity_I32. */
-static IRExpr* mk_armg_calculate_flags_all ( void )
+/* Build IR to calculate some particular condition from stored
+   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression of type
+   Ity_I32, suitable for narrowing.  Although the return type is
+   Ity_I32, the returned value is either 0 or 1.
+*/
+static IRExpr* mk_armg_calculate_condition ( ARMCondcode cond )
 {
+  /* First arg is "(cond << 4) | condition".  This requires that the
+     ARM_CC_OP_ values all fit in 4 bits.  Hence we are passing a
+     (COND, OP) pair in the lowest 8 bits of the first argument. */
+   vassert(cond >= 0 && cond <= 15);
    IRExpr** args
-      = mkIRExprVec_3( IRExpr_Get(OFFB_CC_OP,   Ity_I32),
-                       IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
-                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32) );
+      = mkIRExprVec_4(
+           binop(Iop_Or32, IRExpr_Get(OFFB_CC_OP, Ity_I32),
+                           mkU32(cond << 4)),
+           IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
+           IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
+           IRExpr_Get(OFFB_CC_NDEP, Ity_I32)
+        );
    IRExpr* call
       = mkIRExprCCall(
            Ity_I32,
            0/*regparm*/, 
-           "armg_calculate_flags_all", &armg_calculate_flags_all,
+           "armg_calculate_condition", &armg_calculate_condition,
            args
         );
 
-   /* Exclude OP from definedness checking.  We're only
-      interested in DEP1 and DEP2. */
-   call->Iex.CCall.cee->mcx_mask = 1;
+   /* Exclude the requested condition, OP and NDEP from definedness
+      checking.  We're only interested in DEP1 and DEP2. */
+   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
    return call;
 }
-#endif
+
 
 /* Build IR to calculate just the carry flag from stored
-   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression :: Ity_I32. */
-static IRExpr* mk_armg_calculate_flags_c ( void )
+   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression ::
+   Ity_I32. */
+static IRExpr* mk_armg_calculate_flag_c ( void )
 {
    IRExpr** args
-      = mkIRExprVec_3( IRExpr_Get(OFFB_CC_OP,   Ity_I32),
+      = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP,   Ity_I32),
                        IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
-                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32) );
+                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
+                       IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
    IRExpr* call
       = mkIRExprCCall(
            Ity_I32,
            0/*regparm*/, 
-           "armg_calculate_flags_c", &armg_calculate_flags_c,
+           "armg_calculate_flag_c", &armg_calculate_flag_c,
            args
         );
-   /* Exclude OP from definedness checking.  We're only
+   /* Exclude OP and NDEP from definedness checking.  We're only
       interested in DEP1 and DEP2. */
-   call->Iex.CCall.cee->mcx_mask = 1;
+   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
    return call;
 }
 
 
-/* Build IR to calculate some particular condition from stored
-   CC_OP/CC_DEP1/CC_DEP2.  Returns an expression
-   of type Ity_I1.
-*/
-static IRExpr* mk_armg_calculate_condition ( ARMCondcode cond )
+/* Build IR to calculate just the overflow flag from stored
+   CC_OP/CC_DEP1/CC_DEP2/CC_NDEP.  Returns an expression ::
+   Ity_I32. */
+static IRExpr* mk_armg_calculate_flag_v ( void )
 {
    IRExpr** args
-      = mkIRExprVec_4( mkU32(cond),
-                       IRExpr_Get(OFFB_CC_OP,  Ity_I32),
+      = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP,   Ity_I32),
                        IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
-                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32) );
+                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
+                       IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
    IRExpr* call
       = mkIRExprCCall(
            Ity_I32,
            0/*regparm*/, 
-           "armg_calculate_condition", &armg_calculate_condition,
+           "armg_calculate_flag_v", &armg_calculate_flag_v,
            args
         );
-
-   /* Exclude the requested condition and OP from definedness
-      checking.  We're only interested in DEP1 and DEP2. */
-   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<1);
-   return unop(Iop_32to1, call);
+   /* Exclude OP and NDEP from definedness checking.  We're only
+      interested in DEP1 and DEP2. */
+   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
+   return call;
 }
 
 
-
-
-
-
-
-/* -------------- Building the flags-thunk. -------------- */
-
-/* The machinery in this section builds the flag-thunk following a
-   flag-setting operation.  Hence the various setFlags_* functions.
-*/
-
-#if 0
-static Bool isAddSub ( IROp op8 )
+/* Build IR to calculate N Z C V in bits 31:28 of the
+   returned word. */
+static IRExpr* mk_armg_calculate_flags_nzcv ( void )
 {
-   return op8 == Iop_Add8 || op8 == Iop_Sub8;
+   IRExpr** args
+      = mkIRExprVec_4( IRExpr_Get(OFFB_CC_OP,   Ity_I32),
+                       IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
+                       IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
+                       IRExpr_Get(OFFB_CC_NDEP, Ity_I32) );
+   IRExpr* call
+      = mkIRExprCCall(
+           Ity_I32,
+           0/*regparm*/, 
+           "armg_calculate_flags_nzcv", &armg_calculate_flags_nzcv,
+           args
+        );
+   /* Exclude OP and NDEP from definedness checking.  We're only
+      interested in DEP1 and DEP2. */
+   call->Iex.CCall.cee->mcx_mask = (1<<0) | (1<<3);
+   return call;
 }
-#endif
 
-#if 0
-static Bool isLogic ( IROp op8 )
-{
-   return op8 == Iop_And8 || op8 == Iop_Or8 || op8 == Iop_Xor8;
-}
-#endif
 
-/* U-widen 8/16/32 bit int expr to 32. */
-static IRExpr* widenUto32 ( IRExpr* e )
+/* Build IR to conditionally set the flags thunk.  As with putIReg, if
+   guard is IRTemp_INVALID then it's unconditional, else it holds a
+   condition :: Ity_I32. */
+static
+void setFlags_D1_D2_ND ( UInt cc_op, IRTemp t_dep1,
+                         IRTemp t_dep2, IRTemp t_ndep,
+                         IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
 {
-   switch (typeOfIRExpr(irsb->tyenv,e)) {
-   case Ity_I32: return e;
-   case Ity_I16: return unop(Iop_16Uto32,e);
-   case Ity_I8:  return unop(Iop_8Uto32,e);
-   default: vpanic("widenUto32");
+   IRTemp c8;
+   vassert(typeOfIRTemp(irsb->tyenv, t_dep1 == Ity_I32));
+   vassert(typeOfIRTemp(irsb->tyenv, t_dep2 == Ity_I32));
+   vassert(typeOfIRTemp(irsb->tyenv, t_ndep == Ity_I32));
+   vassert(cc_op >= ARMG_CC_OP_COPY && cc_op < ARMG_CC_OP_NUMBER);
+   if (guardT == IRTemp_INVALID) {
+      /* unconditional */
+      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(cc_op) ));
+      stmt( IRStmt_Put( OFFB_CC_DEP1, mkexpr(t_dep1) ));
+      stmt( IRStmt_Put( OFFB_CC_DEP2, mkexpr(t_dep2) ));
+      stmt( IRStmt_Put( OFFB_CC_NDEP, mkexpr(t_ndep) ));
+   } else {
+      /* conditional */
+      c8 = newTemp(Ity_I8);
+      assign( c8, unop(Iop_32to8, mkexpr(guardT)) );
+      stmt( IRStmt_Put(
+               OFFB_CC_OP,
+               IRExpr_Mux0X( mkexpr(c8),
+                             IRExpr_Get(OFFB_CC_OP, Ity_I32),
+                             mkU32(cc_op) )));
+      stmt( IRStmt_Put(
+               OFFB_CC_DEP1,
+               IRExpr_Mux0X( mkexpr(c8),
+                             IRExpr_Get(OFFB_CC_DEP1, Ity_I32),
+                             mkexpr(t_dep1) )));
+      stmt( IRStmt_Put(
+               OFFB_CC_DEP2,
+               IRExpr_Mux0X( mkexpr(c8),
+                             IRExpr_Get(OFFB_CC_DEP2, Ity_I32),
+                             mkexpr(t_dep2) )));
+      stmt( IRStmt_Put(
+               OFFB_CC_NDEP,
+               IRExpr_Mux0X( mkexpr(c8),
+                             IRExpr_Get(OFFB_CC_NDEP, Ity_I32),
+                             mkexpr(t_ndep) )));
    }
 }
 
-#if 0
-/* S-widen 8/16/32 bit int expr to 32. */
-static IRExpr* widenSto32 ( IRExpr* e )
-{
-   switch (typeOfIRExpr(irsb->tyenv,e)) {
-   case Ity_I32: return e;
-   case Ity_I16: return unop(Iop_16Sto32,e);
-   case Ity_I8:  return unop(Iop_8Sto32,e);
-   default: vpanic("widenSto32");
-   }
-}
-#endif
 
-/* 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 )
+/* Minor variant of the above that sets NDEP to zero (if it
+   sets it at all) */
+static void setFlags_D1_D2 ( UInt cc_op, IRTemp t_dep1,
+                             IRTemp t_dep2,
+                             IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
 {
-   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);
-
-   vex_printf("\nsrc, dst tys are: ");
-   ppIRType(src_ty);
-   vex_printf(", ");
-   ppIRType(dst_ty);
-   vex_printf("\n");
-   vpanic("narrowTo(ARM)");
+   IRTemp z32 = newTemp(Ity_I32);
+   assign( z32, mkU32(0) );
+   setFlags_D1_D2_ND( cc_op, t_dep1, t_dep2, z32, guardT );
 }
 
 
-/* Set the flags thunk OP, DEP1 and DEP2 fields.  The supplied op is
-   auto-sized up to the real op. */
-
-static 
-void setFlags_DEP1_DEP2 ( IROp op, IRTemp dep1, IRTemp dep2 )
+/* Minor variant of the above that sets DEP2 to zero (if it
+   sets it at all) */
+static void setFlags_D1_ND ( UInt cc_op, IRTemp t_dep1,
+                             IRTemp t_ndep,
+                             IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
 {
-   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(op)) );
-   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
-   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(dep2))) );
+   IRTemp z32 = newTemp(Ity_I32);
+   assign( z32, mkU32(0) );
+   setFlags_D1_D2_ND( cc_op, t_dep1, z32, t_ndep, guardT );
 }
 
 
-/* Set the OP and DEP1 fields only, and write zero to DEP2. */
-
-#if 0
-static 
-void setFlags_DEP1 ( IROp op, IRTemp dep1 )
+/* Minor variant of the above that sets DEP2 and NDEP to zero (if it
+   sets them at all) */
+static void setFlags_D1 ( UInt cc_op, IRTemp t_dep1,
+                          IRTemp guardT /* :: Ity_I32, 0 or 1 */ )
 {
-   stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(op)) );
-   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(dep1))) );
-   stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0)) );
+   IRTemp z32 = newTemp(Ity_I32);
+   assign( z32, mkU32(0) );
+   setFlags_D1_D2_ND( cc_op, t_dep1, z32, z32, guardT );
 }
-#endif
 
-#if 0
-/* For shift operations, we put in the result and the undershifted
-   result.  Except if the shift amount is zero, the thunk is left
-   unchanged. */
 
-static void setFlags_DEP1_DEP2_shift ( IROp    op,
-                                       IRTemp  res,
-                                       IRTemp  resUS,
-                                       IRTemp  guard )
+/* Generate a side-exit to the next instruction, if the given guard
+   expression :: Ity_I32 is 0 (note!  the side exit is taken if the
+   condition is false!)  This is used to skip over conditional
+   instructions which we can't generate straight-line code for, either
+   because they are too complex or (more likely) they potentially
+   generate exceptions.
+*/
+static void mk_skip_to_next_if_cond_is_false ( 
+               IRTemp guardT /* :: Ity_I32, 0 or 1 */
+            )
 {
-   vassert(guard);
-   
-   /* DEP1 contains the result, DEP2 contains the undershifted value. */
-   stmt( IRStmt_Put( OFFB_CC_OP,
-                     IRExpr_Mux0X( mkexpr(guard),
-                                   IRExpr_Get(OFFB_CC_OP,Ity_I32),
-                                   mkU32(op))) );
-   stmt( IRStmt_Put( OFFB_CC_DEP1,
-                     IRExpr_Mux0X( mkexpr(guard),
-                                   IRExpr_Get(OFFB_CC_DEP1,Ity_I32),
-                                   widenUto32(mkexpr(res)))) );
-   stmt( IRStmt_Put( OFFB_CC_DEP2, 
-                     IRExpr_Mux0X( mkexpr(guard),
-                                   IRExpr_Get(OFFB_CC_DEP2,Ity_I32),
-                                   widenUto32(mkexpr(resUS)))) );
+   vassert(guardT != IRTemp_INVALID);
+   stmt( IRStmt_Exit(
+            unop(Iop_Not1, unop(Iop_32to1, mkexpr(guardT))),
+            Ijk_Boring,
+            IRConst_U32(toUInt(guest_R15_curr_instr + 4))
+       ));
 }
-#endif
-
-
 
 
+/*------------------------------------------------------------*/
+/*--- Larger helpers                                       ---*/
+/*------------------------------------------------------------*/
 
-#if 0
-/* Multiplies are pretty much like add and sub: DEP1 and DEP2 hold the
-   two arguments. */
+/* Generate an expression corresponding to a shifter_operand, bind it
+   to a temporary, and return that via *shop.  If shco is non-NULL,
+   also compute a value for the shifter's carry out (in the LSB of a
+   word), bind it to a temporary, and return that via *shco.
 
-static
-void setFlags_MUL ( IRTemp arg1, IRTemp arg2, UInt op )
+   If for some reason we can't come up with a shifter operand (missing
+   case?  not really a shifter operand?) return False.
+*/
+static Bool mk_shifter_operand ( UInt insn_25, UInt insn_11_0,
+                                 /*OUT*/IRTemp* shop,
+                                 /*OUT*/IRTemp* shco,
+                                 /*OUT*/HChar* buf )
 {
-   stmt( IRStmt_Put( OFFB_CC_OP, mkU32(op) ) );
-   stmt( IRStmt_Put( OFFB_CC_DEP1, widenUto32(mkexpr(arg1)) ));
-   stmt( IRStmt_Put( OFFB_CC_DEP2, widenUto32(mkexpr(arg2)) ));
-}
-#endif
-
-
-
-
-
-
-
+   UInt insn_4 = (insn_11_0 >> 4) & 1;
+   UInt insn_7 = (insn_11_0 >> 7) & 1;
+   vassert(insn_25 <= 0x1);
+   vassert(insn_11_0 <= 0xFFF);
 
+   vassert(shop && *shop == IRTemp_INVALID);
+   *shop = newTemp(Ity_I32);
 
-/* -------------- Condition codes. -------------- */
-
-/* Condition codes, using the ARM encoding.  */
-
-static HChar* name_ARMCondcode ( ARMCondcode cond )
-{
-   switch (cond) {
-   case ARMCondEQ:  return "{eq}";
-   case ARMCondNE:  return "{ne}";
-   case ARMCondHS:  return "{hs}";  // or 'cs'
-   case ARMCondLO:  return "{lo}";  // or 'cc'
-   case ARMCondMI:  return "{mi}";
-   case ARMCondPL:  return "{pl}";
-   case ARMCondVS:  return "{vs}";
-   case ARMCondVC:  return "{vc}";
-   case ARMCondHI:  return "{hi}";
-   case ARMCondLS:  return "{ls}";
-   case ARMCondGE:  return "{ge}";
-   case ARMCondLT:  return "{lt}";
-   case ARMCondGT:  return "{gt}";
-   case ARMCondLE:  return "{le}";
-   case ARMCondAL:  return "";      // {al}: default, doesn't need specifying
-   case ARMCondNV:  return "{nv}";
-   default: vpanic("name_ARMCondcode");
+   if (shco) {
+      vassert(*shco == IRTemp_INVALID);
+      *shco = newTemp(Ity_I32);
    }
-}
 
-#if 0
-static 
-ARMCondcode positiveIse_ARMCondcode ( ARMCondcode  cond,
-                                      Bool*     needInvert )
-{
-   vassert(cond >= ARMCondEQ && cond <= ARMCondNV);
-   if (cond & 1) {
-      *needInvert = True;
-      return cond-1;
-   } else {
-      *needInvert = False;
-      return cond;
+   /* 32-bit immediate */
+
+   if (insn_25 == 1) {
+      /* immediate: (7:0) rotated right by 2 * (11:8) */
+      UInt imm = (insn_11_0 >> 0) & 0xFF;
+      UInt rot = 2 * ((insn_11_0 >> 8) & 0xF);
+      vassert(rot <= 30);
+      imm = ROR32(imm, rot);
+      if (shco) {
+         if (rot == 0) {
+            assign( *shco, mk_armg_calculate_flag_c() );
+         } else {
+            assign( *shco, mkU32( (imm >> 31) & 1 ) );
+         }
+      }
+      DIS(buf, "#0x%x", imm);
+      assign( *shop, mkU32(imm) );
+      return True;
    }
-}
-#endif
 
+   /* Shift/rotate by immediate */
 
-/* Addressing Mode 1 - DP ops
-   Addressing Mode 2 - Load/Store word/ubyte (scaled)
- */
-static HChar* name_ARMShiftOp ( UChar shift_op, UChar imm_val )
-{
-   switch (shift_op) {
-   case 0x0: case 0x1: case 0x8: return "lsl";
-   case 0x2: case 0x3: case 0xA: return "lsr";
-   case 0x4: case 0x5: case 0xC: return "asr";
-   case 0x6:                     return (imm_val==0) ? "rrx" : "ror";
-   case 0x7: case 0xE:           return "ror";
-   default: vpanic("name_ARMShiftcode");
-   }
-}
+   if (insn_25 == 0 && insn_4 == 0) {
+      /* Rm (3:0) shifted (6:5) by immediate (11:7) */
+      UInt shift_amt = (insn_11_0 >> 7) & 0x1F;
+      UInt rM        = (insn_11_0 >> 0) & 0xF;
+      UInt how       = (insn_11_0 >> 5) & 3;
+      /* how: 00 = Shl, 01 = Shr, 10 = Sar, 11 = Ror */
+      IRTemp rMt = newTemp(Ity_I32);
+      assign(rMt, getIReg(rM));
 
+      vassert(shift_amt <= 31);
 
-/* Addressing Mode 4 - Load/Store Multiple */
-static HChar* name_ARMAddrMode4 ( UChar mode )
-{
-   /* See ARM ARM A5-55 for alternative names for stack operations
-      ldmfa (full ascending), etc. */
-   switch (mode) {
-   case 0x0: return "da"; // Decrement after
-   case 0x1: return "ia"; // Increment after
-   case 0x2: return "db"; // Decrement before
-   case 0x3: return "ib"; // Increment before
-   default: vpanic("name_ARMAddrMode4");
-   }
-}
-
-/* Data Processing ops */
-static HChar* name_ARMDataProcOp ( UChar opc )
-{
-   switch (opc) {
-   case 0x0: return "and";
-   case 0x1: return "eor";
-   case 0x2: return "sub";
-   case 0x3: return "rsb";
-   case 0x4: return "add";
-   case 0x5: return "adc";
-   case 0x6: return "sbc";
-   case 0x7: return "rsc";
-   case 0x8: return "tst";
-   case 0x9: return "teq";
-   case 0xA: return "cmp";
-   case 0xB: return "cmn";
-   case 0xC: return "orr";
-   case 0xD: return "mov";
-   case 0xE: return "bic";
-   case 0xF: return "mvn";
-   default: vpanic("name_ARMDataProcOp");
-   }
-}
-
+      switch (how) {
 
-
-/*
-  Addressing mode 4 - LOAD/STORE multiple, LDM|STM
-  ARM ARM A5-48
-*/
-static
-Bool dis_loadstore_mult ( UInt theInstr )
-{
-   UChar flags   = toUChar((theInstr >> 20) & 0x1F); // theInstr[24:20]
-   UChar Rn_addr = toUChar((theInstr >> 16) & 0xF);
-   IRTemp Rn = newTemp(Ity_I32);
-   IRTemp Rn_orig = newTemp(Ity_I32);
-   UInt reg_list = theInstr & 0xFFFF;  // each bit addresses a register: R15 to R0
-   
-              // Load(1) | Store(0)
-   UChar L  = toUChar((flags >> 0) & 1);
-              // (W)riteback Rn (incr(U=1) | decr(U=0) by n_bytes)
-   UChar W  = toUChar((flags >> 1) & 1);
-              // Priviledged mode flag - *** CAB TODO ***
-   UChar S  = toUChar((flags >> 2) & 1);  
-              // Txfr ctl: Direction = upwards(1) | downwards(0)
-   UChar U  = toUChar((flags >> 3) & 1);
-              // Txfr ctl: Rn within(P=1) | outside(P=0) accessed mem
-   UChar PU = toUChar((flags >> 3) & 3);  
-   
-   IRTemp start_addr = newTemp(Ity_I32);
-   IRTemp end_addr   = newTemp(Ity_I32);
-   IRTemp data=0;
-   UInt n_bytes=0;
-   UInt tmp_reg = reg_list;
-   UInt reg_idx, offset;
-   Bool decode_ok = True;
-   
-   HChar* cond_name = name_ARMCondcode( (theInstr >> 28) & 0xF );
-   HChar reg_names[70];
-   UInt buf_offset;
-   
-   while (tmp_reg > 0) {     // Count num bits in reg_list => num_bytes
-      if (tmp_reg & 1) { n_bytes += 4; }
-      tmp_reg = tmp_reg >> 1;
-   }
-   
-   assign( Rn, getIReg(Rn_addr) );
-   assign( Rn_orig, mkexpr(Rn) );
-   
-   switch (PU) {  // <addressing_mode>
-   case 0x0:  // Decrement after  (DA)
-      assign( start_addr, binop( Iop_Add32, mkexpr(Rn), mkU32(n_bytes + 4) ) );
-      assign( end_addr,   mkexpr(Rn) );
-      break;
-      
-   case 0x1:  // Increment after  (IA)
-      assign( start_addr, mkexpr(Rn) );
-      assign( end_addr,   binop( Iop_Add32, mkexpr(Rn), mkU32(n_bytes - 4) ) );
-      break;
-      
-   case 0x2:  // Decrement before (DB)
-      assign( start_addr, binop( Iop_Sub32, mkexpr(Rn), mkU32(n_bytes) ) );
-      assign( end_addr,   binop( Iop_Sub32, mkexpr(Rn), mkU32(4) ) );
-      break;
-      
-   case 0x3:  // Increment before (IB)
-      assign( start_addr, binop( Iop_Add32, mkexpr(Rn), mkU32(4) ) );
-      assign( end_addr,   binop( Iop_Add32, mkexpr(Rn), mkU32(n_bytes) ) );
-      break;
-      
-   default:
-      vex_printf("dis_loadstore_mult(ARM): No such case: 0x%x", PU);
-      return False; 
-   }
-
-   if (W==1) {
-      if (U==1) { // upwards
-         putIReg( Rn_addr, binop( Iop_Add32, mkexpr(Rn), mkU32(n_bytes) ) );
-      } else { // downwards
-         putIReg( Rn_addr, binop( Iop_Sub32, mkexpr(Rn), mkU32(n_bytes) ) );
-      }
-   }
-   
-   
-   /*
-     Loop through register list, LOAD/STORE indicated registers
-     Lowest numbered reg -> lowest address, so start with lowest register
-     reg_idx: guest register address
-     offset : current mem offset from start_addr
-   */
-   reg_names[0] = '\0';
-   buf_offset=0;
-   offset=0;
-   for (reg_idx=0; reg_idx < 16; reg_idx++) {
-      if (( reg_list >> reg_idx ) & 1) {  // reg_list[i] == 1?
-         
-         if (L==1) { // LOAD Ri, (start_addr + offset)
-            
-            if (Rn_addr == reg_idx && W==1) { // Undefined - ARM ARM A4-31
-               decode_ok=False;
-               break;
-            }
-            
-            assign( data, loadLE(Ity_I32, binop(Iop_Add32,
-                                                mkexpr(start_addr),
-                                                mkU32(offset))) );
-            if (reg_idx == 15) {
-               // assuming architecture < 5: See ARM ARM A4-31
-               putIReg( reg_idx, binop(Iop_And32, mkexpr(data), mkU32(0xFFFFFFFC)) );
+         case 0:
+            if (shift_amt == 0) {
+               if (shco) {
+                  assign( *shco, mk_armg_calculate_flag_c() );
+               }
+               assign( *shop, mkexpr(rMt) );
+               DIS(buf, "r%u", rM);
             } else {
-               putIReg( reg_idx, mkexpr(data) );
+               vassert(shift_amt >= 1 && shift_amt <= 31);
+               if (shco) {
+                  assign( *shco,
+                          binop(Iop_And32,
+                                binop(Iop_Shr32, mkexpr(rMt), 
+                                                 mkU8(32 - shift_amt)),
+                                mkU32(1)));
+               }
+               assign( *shop,
+                       binop(Iop_Shl32, mkexpr(rMt), mkU8(shift_amt)) );
+               DIS(buf, "r%u, LSL #%u", rM, shift_amt);
             }
-         } else {    // STORE Ri, (start_addr + offset)
-            
-            // ARM ARM A4-85 (Operand restrictions)
-            if (reg_idx == Rn_addr && W==1) {  // Rn in reg_list && writeback
-               if (offset != 0) {  // Undefined - See ARM ARM A4-85
-                  decode_ok=False;
-                  break;
+            return True;
+            /*NOTREACHED*/
+
+         case 1:
+            if (shift_amt == 0) {
+               // conceptually a 32-bit shift, however:
+               // shop = 0
+               // shco = Rm[31]
+               if (shco) {
+                  assign( *shco,
+                          binop(Iop_And32,
+                                binop(Iop_Shr32, mkexpr(rMt), mkU8(31)), 
+                                mkU32(1)));
                }
-               // is lowest reg in reg_list: store Rn_orig
-               storeLE( mkexpr(start_addr), mkexpr(Rn_orig) );
+               assign( *shop, mkU32(0) );
+               DIS(buf, "r%u, LSR #0(a.k.a. 32)", rM);
             } else {
-               storeLE( binop(Iop_Add32, mkexpr(start_addr), mkU32(offset) ),
-                        getIReg(reg_idx) );
+               // shift in range 1..31
+               // shop = Rm >>u shift_amt
+               // shco = Rm[shift_amt - 1]
+               vassert(shift_amt >= 1 && shift_amt <= 31);
+               if (shco) {
+                  assign( *shco,
+                          binop(Iop_And32,
+                                binop(Iop_Shr32, mkexpr(rMt), 
+                                                 mkU8(shift_amt - 1)),
+                                mkU32(1)));
+               }
+               assign( *shop,
+                       binop(Iop_Shr32, mkexpr(rMt), mkU8(shift_amt)) );
+               DIS(buf, "r%u, LSR #%u", rM, shift_amt);
             }
-         }
-         offset += 4;
-         
-         reg_names[buf_offset++] = 'R';
-         if (reg_idx > 9) {
-            reg_names[buf_offset++] = '1';
-            reg_names[buf_offset++] = (HChar)toUChar(38 + reg_idx);
-         } else {
-            reg_names[buf_offset++] = (HChar)toUChar(48 + reg_idx);
-         }
-         reg_names[buf_offset++] = ',';
-         // CAB: Eugh!  Where's strcpy?!
-      }
-   }
-   if (buf_offset > 0) {
-      reg_names[buf_offset-1] = '\0';
-   }
-   DIP("%s%s%s R%d%s, {%s}%s\n", (L==1) ? "ldm":"stm", cond_name,
-       name_ARMAddrMode4( PU ), Rn_addr, (W==1) ? "!" : "",
-       reg_names, (S==1) ? "^" : "");
-   
-   // CAB TODO:
-   // IR assert( end_addr == (start_addr + offset) - 8 )
-   
-   if (offset == 0) {   // Unpredictable - ARM ARM A5-21
-      vex_printf("dis_loadstore_mult(arm): Unpredictable - offset==0\n");
-      decode_ok = False;
-   }
-   
-   return decode_ok;
-}
-
-
-
-
-
-static
-Bool dis_loadstore_w_ub_address ( UInt theInstr, IRTemp* address, HChar* buf )
-{
-   UChar is_reg    = toUChar((theInstr >> 25) & 0x1); 
-                     // immediate | register offset/index
-   UInt  flags     =         (theInstr >> 20) & 0x3F; // theInstr[25:20]
-   UChar Rn_addr   = toUChar((theInstr >> 16) & 0xF);
-   UChar Rm_addr   = toUChar((theInstr >> 00) & 0xF);
-   UChar shift_op  = toUChar((theInstr >> 04) & 0xFF);
-   UInt  offset_12 =         (theInstr >> 00) & 0xFFF;
-   IRTemp Rn = newTemp(Ity_I32);
-   IRTemp Rm = newTemp(Ity_I32);
-   UChar shift_imm, shift;
-   
-   UChar W = toUChar((flags >> 1) & 1); // base register writeback flag - See *Note
-   UChar U = toUChar((flags >> 3) & 1); // offset is added(1)|subtracted(0) from the base
-   UChar P = toUChar((flags >> 4) & 1); // addressing mode flag - See *Note
-   /* *Note
-      P==0: post-indexed addressing: addr -> Rn
-      W==0: normal mem access
-      W==1: unprivileged mem access
-      P==1: W==0: offset addressing: Rn not updated  - ARM ARM A5-20
-      W==1: pre-indexed addressing: addr -> Rn
-   */
-   
-   IRTemp scaled_index = newTemp(Ity_I32);
-   IRTemp reg_offset = newTemp(Ity_I32);
-   
-   IRTemp oldFlagC = newTemp(Ity_I32);
-   
-   HChar buf2[30];
-   HChar buf3[20];
-   buf3[0] = '\0';
-   
-   if (Rn_addr == 15) {
-      if (P==1 && W==0) { // offset addressing
-         // CAB: This right?
-         assign( Rn, binop(Iop_And32, getIReg(15), mkU32(8)) );
-      } else {                        // Unpredictable - ARM ARM A5-25,29...
-         vex_printf("dis_loadstore_w_ub_address(arm): Unpredictable - Rn_addr==15\n");
-         return False;
-      }
-   } else {
-      assign( Rn, getIReg(Rn_addr) );
-   }
-   
-   /*
-     Retrieve / Calculate reg_offset
-   */
-   if (is_reg) {
-      if (Rm_addr == 15) {               // Unpredictable - ARM ARM A5-21
-         vex_printf("dis_loadstore_w_ub_address(arm): Unpredictable - Rm_addr==15\n");
-         return False;
-      }
-      if (P==0 || W==1) {  // pre|post-indexed addressing
-         if (Rm_addr == Rn_addr) {      // Unpredictable - ARM ARM A5-25
-            vex_printf("dis_loadstore_w_ub_address(arm): Unpredictable - Rm_addr==Rn_addr\n");
-            return False;
-         }
-      }
-      assign( Rm, getIReg(Rm_addr) );
-      
-      if (shift_op == 0) {  // Register addressing
-         assign( reg_offset, mkexpr(Rm) );
-      } else {              // Scaled Register addressing
-         shift_imm = toUChar((shift_op >> 3) & 0x1F);
-         shift     = toUChar((shift_op >> 1) & 0x3);
-         
-         switch (shift) {
-         case 0x0: // LSL
-            assign( scaled_index, binop(Iop_Shl32, mkexpr(Rm), mkU8(shift_imm)) );
-            break;
-            
-         case 0x1: // LSR
-            if (shift_imm) {
-               assign( scaled_index, binop(Iop_Shr32, mkexpr(Rm), mkU8(shift_imm)) );
+            return True;
+            /*NOTREACHED*/
+
+         case 2:
+            if (shift_amt == 0) {
+               // conceptually a 32-bit shift, however:
+               // shop = Rm >>s 31
+               // shco = Rm[31]
+               if (shco) {
+                  assign( *shco,
+                          binop(Iop_And32,
+                                binop(Iop_Shr32, mkexpr(rMt), mkU8(31)), 
+                                mkU32(1)));
+               }
+               assign( *shop, binop(Iop_Sar32, mkexpr(rMt), mkU8(31)) );
+               DIS(buf, "r%u, ASR #0(a.k.a. 32)", rM);
             } else {
-               assign( scaled_index, mkU32(0) );
+               // shift in range 1..31
+               // shop = Rm >>s shift_amt
+               // shco = Rm[shift_amt - 1]
+               vassert(shift_amt >= 1 && shift_amt <= 31);
+               if (shco) {
+                  assign( *shco,
+                          binop(Iop_And32,
+                                binop(Iop_Shr32, mkexpr(rMt), 
+                                                 mkU8(shift_amt - 1)),
+                                mkU32(1)));
+               }
+               assign( *shop,
+                       binop(Iop_Sar32, mkexpr(rMt), mkU8(shift_amt)) );
+               DIS(buf, "r%u, ASR #%u", rM, shift_amt);
             }
-            break;
-            
-         case 0x2: // ASR
-            if (shift_imm) {
-               assign( scaled_index, binop(Iop_Sar32, mkexpr(Rm), mkU32(shift_imm)) );
+            return True;
+            /*NOTREACHED*/
+
+         case 3:
+            if (shift_amt == 0) {
+               IRTemp oldcT = newTemp(Ity_I32);
+               // rotate right 1 bit through carry (?)
+               // RRX -- described at ARM ARM A5-17
+               // shop = (oldC << 31) | (Rm >>u 1)
+               // shco = Rm[0]
+               if (shco) {
+                  assign( *shco,
+                           binop(Iop_And32, mkexpr(rMt), mkU32(1)));
+               }
+               assign( oldcT, mk_armg_calculate_flag_c() );
+               assign( *shop, 
+                       binop(Iop_Or32,
+                             binop(Iop_Shl32, mkexpr(oldcT), mkU8(31)),
+                             binop(Iop_Shr32, mkexpr(rMt), mkU8(1))) );
+               DIS(buf, "r%u, RRX", rM);
             } else {
-               assign( scaled_index,     // Rm[31] ? 0xFFFFFFFF : 0x0
-                       IRExpr_Mux0X(binop(Iop_And32, mkexpr(Rm), mkU32(0x8FFFFFFF)),
-                                    mkexpr(0x0), mkexpr(0xFFFFFFFF)) );
-            }
-            break;
-            
-         case 0x3: // ROR|RRX
-            assign( oldFlagC, binop(Iop_Shr32,
-                                    mk_armg_calculate_flags_c(),
-                                    mkU8(ARMG_CC_SHIFT_C)) );
-            
-            if (shift_imm == 0) { // RRX (ARM ARM A5-17)
-               // 33 bit ROR using carry flag as the 33rd bit
-               // op = Rm >> 1, carry flag replacing vacated bit position.  
-               // scaled_index = (c_flag << 31) | (Rm >> 1)
-               assign( scaled_index, binop(Iop_Or32,
-                                           binop(Iop_Shl32, mkexpr(oldFlagC), mkU32(31)),
-                                           binop(Iop_Shr32, mkexpr(Rm),  mkU8(1))) );
-               
-            } else { // ROR
-               // scaled_index = Rm ROR shift_imm
-               //              = (Rm >> shift_imm) | (Rm << (32-shift_imm))
-               assign( scaled_index,
+               // rotate right in range 1..31
+               // shop = Rm `ror` shift_amt
+               // shco = Rm[shift_amt - 1]
+               vassert(shift_amt >= 1 && shift_amt <= 31);
+               if (shco) {
+                  assign( *shco,
+                          binop(Iop_And32,
+                                binop(Iop_Shr32, mkexpr(rMt), 
+                                                 mkU8(shift_amt - 1)),
+                                mkU32(1)));
+               }
+               assign( *shop,
                        binop(Iop_Or32,
-                             binop(Iop_Shr32, mkexpr(Rm), mkU8(shift_imm)),
-                             binop(Iop_Shl32, mkexpr(Rm),
-                                   binop(Iop_Sub8, mkU8(32), mkU32(shift_imm)))) );
+                             binop(Iop_Shr32, mkexpr(rMt), mkU8(shift_amt)),
+                             binop(Iop_Shl32, mkexpr(rMt),
+                                              mkU8(32-shift_amt))));
+               DIS(buf, "r%u, ROR #%u", rM, shift_amt);
             }
-            break;
-            
+            return True;
+            /*NOTREACHED*/
+
          default:
-            vex_printf("dis_loadstore_w_ub(ARM): No such case: 0x%x", shift);
-            return False; 
-         }
-         assign( reg_offset, mkexpr(scaled_index) );
-         
-         if (shift == 0x3 && shift_imm == 0) {
-            DIS(buf3, ", %s", name_ARMShiftOp(toUChar(shift_op * 2), shift_imm));
-         } else {
-            DIS(buf3, ", %s #%d", 
-                      name_ARMShiftOp(toUChar(shift_op * 2), shift_imm), 
-                      shift_imm);
-         }
-      }
-      DIS(buf2, "%cR%d%s", (U==1) ? '+' : '-', Rm_addr, buf3);
-   } else { // immediate
-      assign( reg_offset, mkU32(offset_12) );
-      
-      DIS(buf2, "#%c%u", (U==1) ? '+' : '-', offset_12);
-   }
-   DIS(buf, "[R%d%s, %s%s", Rn_addr,
-       (P==0) ? "]" : "", buf2,
-       (P==1) ? ((W==1) ? "]!" : "]") : "");
-   
-   /*
-     Depending on P,U,W, write to Rn and set address to load/store
-   */
-   if (P==1) {       // offset | pre-indexed addressing
-      if (U == 1) { // - increment
-         assign( *address, binop(Iop_Add32, mkexpr(Rn), mkexpr(reg_offset)) );
-      } else {      // - decrement
-         assign( *address, binop(Iop_Sub32, mkexpr(Rn), mkexpr(reg_offset)) );
-      }
-      if (W == 1) { // pre-indexed addressing, base register writeback
-         putIReg( Rn_addr, mkexpr(*address) );
-      }
-   } else {          // post-indexed addressing
-      assign( *address, mkexpr(Rn) );
-      if (U == 1) { // - increment
-         putIReg( Rn_addr, binop( Iop_Add32, mkexpr(Rn), mkexpr(reg_offset) ) );
-      } else {      // - decrement
-         putIReg( Rn_addr, binop( Iop_Sub32, mkexpr(Rn), mkexpr(reg_offset) ) );
+            /*NOTREACHED*/
+            vassert(0);
       }
    }
-   return True;
-}
-
-
 
-
-/*
-  Addressing mode 2 - LOAD/STORE word or unsigned byte
-  ARM ARM A5-18
-*/
-static
-Bool dis_loadstore_w_ub ( UInt theInstr )
-{
-   UInt   flags   =         (theInstr >> 20) & 0x3F;  // theInstr[25:20]
-   UChar  Rn_addr = toUChar((theInstr >> 16) & 0xF);
-   UChar  Rd_addr = toUChar((theInstr >> 12) & 0xF);
-   IRTemp address = newTemp(Ity_I32);
-  
-   UChar L  = toUChar((flags >> 0) & 1); // Load(1) | Store(0)
-   UChar W  = toUChar((flags >> 1) & 1); // base register writeback
-   UChar B  = toUChar((flags >> 2) & 1); // access = unsigned byte(1) | word(0)
-   
-   IRTemp value      = newTemp(Ity_I32);
-   IRTemp data       = newTemp(Ity_I32);
-   IRTemp data_ror8  = newTemp(Ity_I32);
-   IRTemp data_ror16 = newTemp(Ity_I32);
-   IRTemp data_ror24 = newTemp(Ity_I32);
-   IRExpr* expr_addr_10;
-   HChar* cond_name = name_ARMCondcode( (theInstr >> 28) & 0xF );
-   HChar dis_buf[50];
-   
-   
-   vassert(((theInstr >> 26) & 0x3) == 0x1);
-   
-   // Get the address to load/store
-   if (!dis_loadstore_w_ub_address(theInstr, &address, dis_buf)) { return False; }
-   
-   DIP("%s%s%s R%d, %s\n", (L==1) ? "ldr" : "str", cond_name,
-       (B==1) ? "b" : "", Rd_addr, dis_buf);
-   
-   if (Rd_addr == Rn_addr && W==1) {  // Unpredictable - ARM ARM A4-39,41,89,91
-      vex_printf("dis_loadstore_w_ub(arm): Unpredictable - Rd_addr==Rn_addr\n");
-      return False;
-   }
-   
-   /*
-     LOAD/STORE Rd, address
-   */
-   if (L==1) { // LOAD
-      if (B==1) {  // unsigned byte (LDRB): ARM ARM A4-40
-         if (Rd_addr == 15) {  // Unpredictable - ARM ARM A4-40
-            vex_printf("dis_loadstore_w_ub(arm): Unpredictable - Rd_addr==15\n");
-            return False;
+   /* Shift/rotate by register */
+   if (insn_25 == 0 && insn_4 == 1) {
+      /* Rm (3:0) shifted (6:5) by Rs (11:8) */
+      UInt rM  = (insn_11_0 >> 0) & 0xF;
+      UInt rS  = (insn_11_0 >> 8) & 0xF;
+      UInt how = (insn_11_0 >> 5) & 3;
+      /* how: 00 = Shl, 01 = Shr, 10 = Sar, 11 = Ror */
+      IRTemp rMt = newTemp(Ity_I32);
+      IRTemp rSt = newTemp(Ity_I32);
+
+      if (insn_7 == 1)
+         return False; /* not really a shifter operand */
+
+      assign(rMt, getIReg(rM));
+      assign(rSt, getIReg(rS));
+
+      switch (how) {
+         case 0: { /* LSL */
+            // shift left in range 0 .. 255
+            // amt = rS & 255
+            // shop = amt < 32 ?  Rm << amt  : 0
+            // shco = amt == 0     ? oldC  :
+            //        amt in 1..32 ?  Rm[32-amt]  : 0
+            IRTemp amtT = newTemp(Ity_I32);
+            assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
+            if (shco) {
+               /* mux0X(amt == 0,
+                        mux0X(amt < 32, 
+                              0,
+                              Rm[(32-amt) & 31])
+                        oldC)
+               */
+               /* About the best you can do is pray that iropt is able
+                  to nuke most or all of the following junk. */
+               IRTemp oldC = newTemp(Ity_I32);
+               assign(oldC, mk_armg_calculate_flag_c() );
+               assign(
+                  *shco,
+                  IRExpr_Mux0X(
+                     unop(Iop_1Uto8,
+                          binop(Iop_CmpEQ32, mkexpr(amtT), mkU32(0))),
+                     IRExpr_Mux0X(
+                        unop(Iop_1Uto8,
+                             binop(Iop_CmpLE32U, mkexpr(amtT), mkU32(32))),
+                        mkU32(0),
+                        binop(Iop_Shr32,
+                              mkexpr(rMt),
+                              unop(Iop_32to8,
+                                   binop(Iop_And32,
+                                         binop(Iop_Sub32,
+                                               mkU32(32),
+                                               mkexpr(amtT)),
+                                         mkU32(31)
+                                   )
+                              )
+                        )
+                     ),
+                     mkexpr(oldC)
+                  )
+               );
+            }
+            // (Rm << (Rs & 31))  &  (((Rs & 255) - 32) >>s 31)
+            // Lhs of the & limits the shift to 31 bits, so as to
+            // give known IR semantics.  Rhs of the & is all 1s for
+            // Rs <= 31 and all 0s for Rs >= 32.
+            assign(
+               *shop,
+               binop(
+                  Iop_And32,
+                  binop(Iop_Shl32,
+                        mkexpr(rMt),
+                        unop(Iop_32to8,
+                             binop(Iop_And32, mkexpr(rSt), mkU32(31)))),
+                  binop(Iop_Sar32,
+                        binop(Iop_Sub32,
+                              mkexpr(amtT),
+                              mkU32(32)),
+                        mkU8(31))));
+             DIS(buf, "r%u, LSL r%u", rM, rS);
+             return True;
          }
-         putIReg( Rd_addr, loadLE( Ity_I8, mkexpr( address ) ) );
-      }
-      else {       // word (LDR): ARM ARM A4-38
-         expr_addr_10 = binop(Iop_And32, mkexpr(address), mkU32(0x3));
-         
-         /*
-           CAB TODO
-           if (Rd_addr == 15 && address[1:0] == 0) => Unpredictable
-           How to bomb out using IR?
-         */
-         
-         /* LOAD memory data (4 bytes) */
-         assign( data, loadLE( Ity_I32, mkexpr( address ) ) );
-         
-         // data ROR 8
-         assign( data_ror8, binop(Iop_Sub8, mkU8(32), mkU32(8)) ); 
-         assign( data_ror8,
-                 binop( Iop_Or32,
-                        binop( Iop_Shr32, mkexpr(data), mkU8(8) ),
-                        binop( Iop_Shl32, mkexpr(data), mkexpr(data_ror8) )));
-         // data ROR 16
-         assign( data_ror16, binop(Iop_Sub8, mkU8(32), mkU32(16)) );
-         assign( data_ror16,
-                 binop( Iop_Or32,
-                        binop( Iop_Shr32, mkexpr(data), mkU8(16) ),
-                        binop( Iop_Shl32, mkexpr(data), mkexpr(data_ror16) )));
-         
-         // data ROR 24
-         assign( data_ror24, binop(Iop_Sub8, mkU8(32), mkU32(24)) );
-         assign( data_ror24,
-                 binop( Iop_Or32,
-                        binop( Iop_Shr32, mkexpr(data), mkU8(24) ),
-                        binop( Iop_Shl32, mkexpr(data), mkexpr(data_ror24) )));
-         
-         /* switch (address[1:0]) {
-            0x0: value = data;
-            0x1: value = data ROR 8;
-            0x2: value = data ROR 16;
-            0x3: value = data ROR 24; } */
-         assign( value, IRExpr_Mux0X(
-                    binop(Iop_CmpEQ32, expr_addr_10, mkU32(0x0)),
-                    IRExpr_Mux0X(
-                       binop(Iop_CmpEQ32, expr_addr_10, mkU32(0x1)),
-                       IRExpr_Mux0X(
-                          binop(Iop_CmpEQ32, expr_addr_10, mkU32(0x2)),
-                          mkexpr(data_ror24),
-                          mkexpr(data_ror16) ),
-                       mkexpr(data_ror8) ),
-                    mkexpr(data) ) );
-         
-         if (Rd_addr == 15) {
-            // assuming architecture < 5: See ARM ARM A4-28
-            putIReg( Rd_addr, binop(Iop_And32, mkexpr(value), mkU32(0xFFFFFFFC)) );
-            
-            // CAB: Need to tell vex we're doing a jump here?
-            // irsb->jumpkind = Ijk_Boring;
-            // irsb->next     = mkexpr(value);
-         } else {
-            putIReg( Rd_addr, mkexpr(value) );
+         case 1: { /* LSR */
+            // shift right in range 0 .. 255
+            // amt = rS & 255
+            // shop = amt < 32 ?  Rm >>u amt  : 0
+            // shco = amt == 0     ? oldC  :
+            //        amt in 1..32 ?  Rm[amt-1]  : 0
+            IRTemp amtT = newTemp(Ity_I32);
+            assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
+            if (shco) {
+               /* mux0X(amt == 0,
+                        mux0X(amt < 32, 
+                              0,
+                              Rm[(amt-1) & 31])
+                        oldC)
+               */
+               IRTemp oldC = newTemp(Ity_I32);
+               assign(oldC, mk_armg_calculate_flag_c() );
+               assign(
+                  *shco,
+                  IRExpr_Mux0X(
+                     unop(Iop_1Uto8,
+                          binop(Iop_CmpEQ32, mkexpr(amtT), mkU32(0))),
+                     IRExpr_Mux0X(
+                        unop(Iop_1Uto8,
+                             binop(Iop_CmpLE32U, mkexpr(amtT), mkU32(32))),
+                        mkU32(0),
+                        binop(Iop_Shr32,
+                              mkexpr(rMt),
+                              unop(Iop_32to8,
+                                   binop(Iop_And32,
+                                         binop(Iop_Sub32,
+                                               mkexpr(amtT),
+                                               mkU32(1)),
+                                         mkU32(31)
+                                   )
+                              )
+                        )
+                     ),
+                     mkexpr(oldC)
+                  )
+               );
+            }
+            // (Rm >>u (Rs & 31))  &  (((Rs & 255) - 32) >>s 31)
+            // Lhs of the & limits the shift to 31 bits, so as to
+            // give known IR semantics.  Rhs of the & is all 1s for
+            // Rs <= 31 and all 0s for Rs >= 32.
+            assign(
+               *shop,
+               binop(
+                  Iop_And32,
+                  binop(Iop_Shr32,
+                        mkexpr(rMt),
+                        unop(Iop_32to8,
+                             binop(Iop_And32, mkexpr(rSt), mkU32(31)))),
+                  binop(Iop_Sar32,
+                        binop(Iop_Sub32,
+                              mkexpr(amtT),
+                              mkU32(32)),
+                        mkU8(31))));
+             DIS(buf, "r%u, LSR r%u", rM, rS);
+             return True;
          }
-         
-      }
-   } else { // STORE: ARM ARM A4-88
-      if (B==1) {  // unsigned byte
-         if (Rd_addr == 15) {  // Unpredictable - ARM ARM A4-90
-            vex_printf("dis_loadstore_w_ub(arm): Unpredictable - Rd_addr==15\n");
-            return False;
+         case 2: { /* ASR */
+            // arithmetic shift right in range 0 .. 255
+            // amt = rS & 255
+            // shop = amt < 32 ?  Rm >>s amt  : Rm >>s 31
+            // shco = amt == 0     ? oldC  :
+            //        amt in 1..32 ?  Rm[amt-1]  : Rm[31]
+            IRTemp amtT = newTemp(Ity_I32);
+            assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
+            if (shco) {
+               /* mux0X(amt == 0,
+                        mux0X(amt < 32, 
+                              Rm[31],
+                              Rm[(amt-1) & 31])
+                        oldC)
+               */
+               IRTemp oldC = newTemp(Ity_I32);
+               assign(oldC, mk_armg_calculate_flag_c() );
+               assign(
+                  *shco,
+                  IRExpr_Mux0X(
+                     unop(Iop_1Uto8,
+                          binop(Iop_CmpEQ32, mkexpr(amtT), mkU32(0))),
+                     IRExpr_Mux0X(
+                        unop(Iop_1Uto8,
+                             binop(Iop_CmpLE32U, mkexpr(amtT), mkU32(32))),
+                        binop(Iop_Shr32,
+                              mkexpr(rMt),
+                              mkU8(31)
+                        ),
+                        binop(Iop_Shr32,
+                              mkexpr(rMt),
+                              unop(Iop_32to8,
+                                   binop(Iop_And32,
+                                         binop(Iop_Sub32,
+                                               mkexpr(amtT),
+                                               mkU32(1)),
+                                         mkU32(31)
+                                   )
+                              )
+                        )
+                     ),
+                     mkexpr(oldC)
+                  )
+               );
+            }
+            // (Rm >>s (amt <u 32 ? amt : 31))
+            assign(
+               *shop,
+               binop(
+                  Iop_Sar32,
+                  mkexpr(rMt),
+                  unop(
+                     Iop_32to8,
+                     IRExpr_Mux0X(
+                        unop(
+                          Iop_1Uto8,
+                          binop(Iop_CmpLT32U, mkexpr(amtT), mkU32(32))),
+                        mkU32(31),
+                        mkexpr(amtT)))));
+             DIS(buf, "r%u, ASR r%u", rM, rS);
+             return True;
          }
-         storeLE( mkexpr(address), unop(Iop_32to8, getIReg(Rd_addr)) );   // Rd[7:0]
-      } else {     // word
-         
-         if (Rd_addr == 15) {  // Implementation Defined - ARM ARM A4-88
-            vex_printf("dis_loadstore_w_ub(arm): Implementation Defined - Rd_addr==15\n");
-            return False;
-            // CAB TODO: What to do here?
+         case 3: { /* ROR */
+            // rotate right in range 0 .. 255
+            // amt = rS & 255
+            // shop =  Rm `ror` (amt & 31)
+            // shco =  amt == 0 ? oldC : Rm[(amt-1) & 31]
+            IRTemp amtT = newTemp(Ity_I32);
+            assign( amtT, binop(Iop_And32, mkexpr(rSt), mkU32(255)) );
+            IRTemp amt5T = newTemp(Ity_I32);
+            assign( amt5T, binop(Iop_And32, mkexpr(rSt), mkU32(31)) );
+            IRTemp oldC = newTemp(Ity_I32);
+            assign(oldC, mk_armg_calculate_flag_c() );
+            if (shco) {
+               assign(
+                  *shco,
+                  IRExpr_Mux0X(
+                     unop(Iop_32to8, mkexpr(amtT)),
+                     mkexpr(oldC),
+                     binop(Iop_And32,
+                           binop(Iop_Shr32,
+                                 mkexpr(rMt), 
+                                 unop(Iop_32to8,
+                                      binop(Iop_And32,
+                                            binop(Iop_Sub32,
+                                                  mkexpr(amtT), 
+                                                  mkU32(1)
+                                            ),
+                                            mkU32(31)
+                                      )
+                                 )
+                           ),
+                           mkU32(1)
+                     )
+                  )
+               );
+            }
+            assign(
+               *shop,
+               IRExpr_Mux0X(
+                  unop(Iop_32to8, mkexpr(amt5T)), mkexpr(rMt),
+                  binop(Iop_Or32,
+                        binop(Iop_Shr32,
+                              mkexpr(rMt), 
+                              unop(Iop_32to8, mkexpr(amt5T))
+                        ),
+                        binop(Iop_Shl32,
+                              mkexpr(rMt),
+                              unop(Iop_32to8,
+                                   binop(Iop_Sub32, mkU32(32), mkexpr(amt5T))
+                              )
+                        )
+                  )
+               )
+            );
+            DIS(buf, "r%u, ROR r#%u", rM, rS);
+            return True;
+            /*NOTREACHED*/
          }
-         storeLE( mkexpr(address), getIReg(Rd_addr) );
+         default:
+            /*NOTREACHED*/
+            vassert(0);
       }
    }
-   return True;
-}
-
-
 
+   vex_printf("mk_shifter_operand(0x%x,0x%x)\n", insn_25, insn_11_0 );
+   return False;
+}
 
 
+static 
+IRExpr* mk_EA_reg_plusminus_imm12 ( UInt rN, UInt bU, UInt imm12,
+                                    /*OUT*/HChar* buf )
+{
+   vassert(rN < 16);
+   vassert(bU < 2);
+   vassert(imm12 < 0x1000);
+   UChar opChar = bU == 1 ? '+' : '-';
+   DIS(buf, "[r%u, #%c%u]", rN, opChar, imm12);
+   return
+      binop( (bU == 1 ? Iop_Add32 : Iop_Sub32),
+             getIReg(rN),
+             mkU32(imm12) );
+}
 
-/*
-  ARMG_CC_OP_LSL, ARMG_CC_OP_LSR, ARMG_CC_OP_ASR
-  ARM ARM A5-9...
 
-  carry = carry_out[0]
-*/
 static
-IRExpr* dis_shift( Bool* decode_ok, UInt theInstr, IRTemp* carry_out, HChar* buf )
+IRExpr* mk_EA_reg_plusminus_shifted_reg ( UInt rN, UInt bU, UInt rM,
+                                          UInt sh2, UInt imm5,
+                                          /*OUT*/HChar* buf )
 {
-   UChar   Rn_addr     = toUChar((theInstr >> 16) & 0xF);
-   UChar   Rd_addr     = toUChar((theInstr >> 12) & 0xF);
-   UChar   Rs_addr     = toUChar((theInstr >>  8) & 0xF);
-   UChar   Rm_addr     = toUChar((theInstr >>  0) & 0xF);
-   UChar   by_reg      = toUChar((theInstr >>  4) & 0x1);  // instr[4]
-   UChar   shift_imm   = toUChar((theInstr >>  7) & 0x1F); // instr[11:7]
-   UChar   shift_op    = toUChar((theInstr >>  4) & 0xF);  // instr[7:4]
-   IRTemp  Rm          = newTemp(Ity_I32);
-   IRTemp  Rs          = newTemp(Ity_I32);
-   IRTemp  shift_amt   = newTemp(Ity_I8);
-   IRTemp  carry_shift = newTemp(Ity_I8);
-   IRTemp  oldFlagC    = newTemp(Ity_I32);
-   IRTemp  mux_false   = newTemp(Ity_I32);
-   IRExpr* expr;
-   IROp    op;
-   
-   assign( oldFlagC, binop(Iop_Shr32,
-                           mk_armg_calculate_flags_c(),
-                           mkU8(ARMG_CC_SHIFT_C)) );
-   
-   switch (shift_op) {
-   case 0x0: case 0x8: case 0x1: op = Iop_Shl32; break;
-   case 0x2: case 0xA: case 0x3: op = Iop_Shr32; break;
-   case 0x4: case 0xC: case 0x5: op = Iop_Sar32; break;
-   default:
-      vex_printf("dis_shift(arm): No such case: 0x%x\n", shift_op);
-      *decode_ok = False;
-      return mkU32(0);
-   }
-   
-   
-   if (by_reg) {  // Register Shift
-      assign( Rm, getIReg(Rm_addr) );
-      
-      if (Rd_addr == 15 || Rm_addr == 15 ||
-          Rn_addr == 15 || Rs_addr == 15) {   // Unpredictable (ARM ARM A5-10)
-         vex_printf("dis_shift(arm): Unpredictable - Rd|Rm|Rn|Rs == R15\n");
-         *decode_ok = False;
-         return mkU32(0);
-      }
-      
-      assign( Rs, getIReg((theInstr >> 8) & 0xF) );  // instr[11:8]
-      
-      // shift_amt = shift_expr & 31   => Rs[5:0]
-      assign( shift_amt,
-              narrowTo(Ity_I8, binop( Iop_And32, mkexpr(Rs), mkU32(0x1F)) ) );
-      
-      // CAB TODO: support for >31 shift ?  (Rs[7:0])
-      
-      switch (shift_op) {
-      case 0x1: // LSL(reg)
-         assign( mux_false, mkU32(0) );
-         assign( carry_shift, binop(Iop_Add8, mkU8(32), mkexpr(shift_amt)) );
+   vassert(rN < 16);
+   vassert(bU < 2);
+   vassert(rM < 16);
+   vassert(sh2 < 4);
+   vassert(imm5 < 32);
+   UChar   opChar = bU == 1 ? '+' : '-';
+   IRExpr* index  = NULL;
+   switch (sh2) {
+      case 0: /* LSL */
+         /* imm5 can be in the range 0 .. 31 inclusive. */
+         index = binop(Iop_Shl32, getIReg(rM), mkU8(imm5));
+         DIS(buf, "[r%u, %c r%u LSL #%u]", rN, opChar, rM, imm5); 
+         break;
+      case 1: /* LSR */
+         if (imm5 == 0) {
+            index = mkU32(0);
+            vassert(0); // ATC
+         } else {
+            index = binop(Iop_Shr32, getIReg(rM), mkU8(imm5));
+         }
+         DIS(buf, "[r%u, %cr%u, LSR #%u]",
+                  rN, opChar, rM, imm5 == 0 ? 32 : imm5); 
          break;
-         
-      case 0x3: // LSR(reg)
-         assign( mux_false, mkU32(0) );
-         assign( carry_shift, binop(Iop_Sub8, mkexpr(shift_amt), mkU8(1)) );
+      case 2: /* ASR */
+         /* Doesn't this just mean that the behaviour with imm5 == 0
+            is the same as if it had been 31 ? */
+         if (imm5 == 0) {
+            index = binop(Iop_Sar32, getIReg(rM), mkU8(31));
+            vassert(0); // ATC
+         } else {
+            index = binop(Iop_Sar32, getIReg(rM), mkU8(imm5));
+         }
+         DIS(buf, "[r%u, %cr%u, ASR #%u]",
+                  rN, opChar, rM, imm5 == 0 ? 32 : imm5); 
          break;
-         
-      case 0x5: // ASR(reg)
-         // Rs[31] == 0 ? 0x0 : 0xFFFFFFFF
-         assign( mux_false,
-                 IRExpr_Mux0X(
-                    binop(Iop_CmpLT32U, mkexpr(Rs), mkU32(0x80000000)),
-                    mkU32(0xFFFFFFFF), mkU32(0) ) );
-         assign( carry_shift,
-                 binop(Iop_Sub8, mkexpr(shift_amt), mkU8(1)) );
+      case 3: /* ROR or RRX */
+         if (imm5 == 0) {
+            IRTemp rmT    = newTemp(Ity_I32);
+            IRTemp cflagT = newTemp(Ity_I32);
+            assign(rmT, getIReg(rM));
+            assign(cflagT, mk_armg_calculate_flag_v());
+            vassert(imm5 >= 1 && imm5 <= 31);
+            index = binop(Iop_Or32, 
+                          binop(Iop_Shl32, mkexpr(cflagT), mkU8(31)),
+                          binop(Iop_Shr32, mkexpr(rmT), mkU8(1)));
+            vassert(0); // ATC
+            DIS(buf, "[r%u, %cr%u, RRX]", rN, opChar, rM);
+         } else {
+            IRTemp rmT = newTemp(Ity_I32);
+            assign(rmT, getIReg(rM));
+            vassert(imm5 >= 1 && imm5 <= 31);
+            index = binop(Iop_Or32, 
+                          binop(Iop_Shl32, mkexpr(rmT), mkU8(32-imm5)),
+                          binop(Iop_Shr32, mkexpr(rmT), mkU8(imm5)));
+            vassert(0); // ATC
+            DIS(buf, "[r%u, %cr%u, ROR #%u]", rN, opChar, rM, imm5); 
+         }
          break;
-         
       default:
-         vex_printf("dis_shift(arm): Reg shift: No such case: 0x%x\n", shift_op);
-         *decode_ok = False;
-         return mkU32(0);
-      }
-      
-      expr = IRExpr_Mux0X( 
-         binop(Iop_CmpLT32U, widenUto32(mkexpr(shift_amt)), mkU32(32)),
-         mkexpr(mux_false),
-         binop(op, mkexpr(Rm), mkexpr(shift_amt)) );
-      
-      // shift_amt == 0 ? old_flag_c : Rm >> x
-      assign( *carry_out,
-              IRExpr_Mux0X(
-                 binop(Iop_CmpEQ8, mkexpr(shift_amt), mkU8(0)),
-                 binop(Iop_Shr32, mkexpr(Rm), mkexpr(carry_shift)),
-                 mkexpr(oldFlagC) ) );
-      
-      DIS(buf, "R%d, %s R%d", Rm_addr, name_ARMShiftOp(shift_op, 0), Rs_addr);
-   }
-   else {  // Immediate shift
-      
-      // CAB: This right?
-      // "the value used is the address of the current intruction plus 8"
-      if (Rm_addr == 15 || Rn_addr == 15) {        // ARM ARM A5-9
-         assign( Rm, binop(Iop_Add32, getIReg(15), mkU32(8)) );
-      } else {
-         assign( Rm, getIReg(Rm_addr) );
-      }
-      
-      if (shift_imm == 0) {
-         switch (shift_op) {
-         case 0x0: case 0x8: // LSL(imm)
-            expr = mkexpr(Rm);
-            assign( *carry_out, mkexpr(oldFlagC) );
-            break;
-            
-         case 0x2: case 0xA: // LSR(imm)
-            expr = mkexpr(0);
-            // Rm >> 31: carry = R[0]
-            assign( *carry_out, binop(Iop_Shr32, mkexpr(Rm), mkU8(31)) );
-            break;
-            
-         case 0x4: case 0xC: // ASR(imm)
-            // Rs[31] == 0 ? 0x0 : 0xFFFFFFFF
-            expr = IRExpr_Mux0X(
-               binop(Iop_CmpLT32U, mkexpr(Rs), mkU32(0x80000000)),
-               mkU32(0xFFFFFFFF), mkU32(0) );
-            // Rm >> 31: carry = R[0]
-            assign( *carry_out, binop(Iop_Shr32, mkexpr(Rm), mkU8(31)) );
-            break;
-            
-         default:
-            vex_printf("dis_shift(arm): Imm shift: No such case: 0x%x\n", shift_op);
-            *decode_ok = False;
-            return mkU32(0);
-         }
-         DIS(buf, "R%d", Rm_addr);
-      } else {
-         expr = binop(op, mkexpr(Rm), mkU8(shift_imm));
-         assign( *carry_out, binop(op, mkexpr(Rm),
-                                   binop(Iop_Sub32, mkU32(shift_imm), mkU32(1)) ) );
-
-         DIS(buf, "R%d, %s #%d", Rm_addr, name_ARMShiftOp(shift_op, 0), shift_imm);
-      }
+         vassert(0);
    }
-   return expr;
+   vassert(index);
+   return binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
+                getIReg(rN), index);
 }
 
 
-
-
-/*
-  ARMG_CC_OP_ROR
-  ARM ARM A5-15,16,17
-*/
-static
-IRExpr* dis_rotate ( Bool* decode_ok, UInt theInstr, IRTemp* carry_out, HChar* buf )
+static 
+IRExpr* mk_EA_reg_plusminus_imm8 ( UInt rN, UInt bU, UInt imm8,
+                                   /*OUT*/HChar* buf )
 {
-   UChar  Rn_addr  = toUChar((theInstr >> 16) & 0xF);
-   UChar  Rd_addr  = toUChar((theInstr >> 12) & 0xF);
-   UChar  Rs_addr  = toUChar((theInstr >> 8) & 0xF);
-   UChar  Rm_addr  = toUChar((theInstr >> 0) & 0xF);
-   UChar  by_reg   = toUChar((theInstr >> 4) & 0x1);  // instr[4]
-   UChar  rot_imm  = toUChar((theInstr >> 7) & 0x1F); // instr[11:7]
-   IRTemp Rm       = newTemp(Ity_I32);
-   IRTemp Rs       = newTemp(Ity_I32);
-   IRTemp rot_amt  = newTemp(Ity_I8);      // Rs[7:0]
-   IRTemp oldFlagC = newTemp(Ity_I32);
-   IRExpr* expr=0;
-   
-   assign( oldFlagC, binop(Iop_Shr32,
-                           mk_armg_calculate_flags_c(),
-                           mkU8(ARMG_CC_SHIFT_C)) );
-   
-   if (by_reg) {  // Register rotate
-      assign( Rm, getIReg(Rm_addr) );
-      
-      if (Rd_addr == 15 || Rm_addr == 15 ||
-          Rn_addr == 15 || Rs_addr == 15) {    // Unpredictable (ARM ARM A5-10)
-         vex_printf("dis_rotate(arm): Unpredictable - Rd|Rm|Rn|Rs == R15\n");
-         *decode_ok = False;
-         return mkU32(0);
-      }
-      
-      assign( Rs, getIReg((theInstr >> 8) & 0xF) );  // instr[11:8]
-      // Rs[4:0]
-      assign( rot_amt, narrowTo(Ity_I8,
-                                binop(Iop_And32, mkexpr(Rs), mkU32(0x1F))) );
-      
-      // CAB: This right?
-      // Rs[7:0] == 0 ? oldFlagC : (Rs[4:0] == 0 ? Rm >> 31 : Rm >> rot-1 )
-      assign( *carry_out,
-              IRExpr_Mux0X(
-                 binop(Iop_CmpNE32, mkU32(0),
-                       binop(Iop_And32, mkexpr(Rs), mkU32(0xFF))),
-                 mkexpr(oldFlagC),
-                 IRExpr_Mux0X(
-                    binop(Iop_CmpEQ8, mkexpr(rot_amt), mkU8(0)),
-                    binop(Iop_Shr32, mkexpr(Rm),
-                          binop(Iop_Sub8, mkexpr(rot_amt), mkU8(1))),
-                    binop(Iop_Shr32, mkexpr(Rm),
-                          binop(Iop_Shr32, mkexpr(Rm), mkU8(31))) ) ) );
-      
-      
-      /* expr = (dst0 >> rot_amt) | (dst0 << (wordsize-rot_amt)) */
-      expr = binop(Iop_Or32,
-                   binop(Iop_Shr32, mkexpr(Rm), mkexpr(rot_amt)),
-                   binop(Iop_Shl32, mkexpr(Rm),
-                         binop(Iop_Sub8, mkU8(32), mkexpr(rot_amt))));
-
-      DIS(buf, "R%d, ror R%d", Rm_addr, Rs_addr);
-   }
-   else {  // Immediate rotate
-
-      // CAB: This right?
-      // "the value used is the address of the current intruction plus 8"
-      if (Rm_addr == 15 || Rn_addr == 15) {        // ARM ARM A5-9
-         assign( Rm, binop(Iop_Add32, getIReg(15), mkU32(8)) );
-      } else {
-         assign( Rm, getIReg(Rm_addr) );
-      }
-      
-      // Rm >> rot-1: carry = R[0]
-      assign( *carry_out, binop(Iop_Shr32, mkexpr(Rm),
-                                binop(Iop_Sub8, mkU8(rot_imm), mkU8(1)) ) );
-      
-      if (rot_imm == 0) {   // RRX (ARM ARM A5-17)
-         // 33 bit ROR using carry flag as the 33rd bit
-         // op = Rm >> 1, carry flag replacing vacated bit position.  
-         
-         // CAB: This right?
-         expr = binop(Iop_Or32,
-                      binop(Iop_Shl32, mkexpr(oldFlagC), mkU8(31)),
-                      binop(Iop_Shr32, mkexpr(Rm), mkU8(1)));
-         DIS(buf, "R%d, rrx", Rm_addr);
-      } else {
-         expr = binop(Iop_Or32,
-                      binop(Iop_Shr32, mkexpr(Rm), mkU8(rot_imm)),
-                      binop(Iop_Shl32, mkexpr(Rm),
-                            binop(Iop_Sub8, mkU8(32), mkU8(rot_imm))));
-         
-         DIS(buf, "R%d, ror #%u", Rm_addr, (UInt)rot_imm);
-      }
-   }
-   return expr;
+   vassert(rN < 16);
+   vassert(bU < 2);
+   vassert(imm8 < 0x100);
+   UChar opChar = bU == 1 ? '+' : '-';
+   DIS(buf, "[r%u, #%c%u]", rN, opChar, imm8);
+   return
+      binop( (bU == 1 ? Iop_Add32 : Iop_Sub32),
+             getIReg(rN),
+             mkU32(imm8) );
 }
 
 
-
-
-/*
-  CAB TODO:
-   - Not all shifts by 0 leave c_flag unchanged, so guard_expr is more difficult...
-  assign( flags_guard, binop( Iop_CmpEQ32, mkexpr(shift_amt), mkU32(0) ) );
-  setFlags_DEP1_DEP2_shift( ARMG_CC_OP_LSL, Rm, shift_op, flags_guard );
-*/
-
-
-
-
-/* Addressing mode 1 - Data Processing ops
-   General syntax: <opcode>{<cond>}{S} <Rd>, <Rn>, <shifter_operand>
-   Returns <shifter_operand> expression
-*/
 static
-IRExpr* dis_shifter_op ( Bool *decode_ok, UInt theInstr, IRTemp* carry_out, HChar* buf )
+IRExpr* mk_EA_reg_plusminus_reg ( UInt rN, UInt bU, UInt rM,
+                                  /*OUT*/HChar* buf )
 {
-   UChar is_immed  = toUChar((theInstr >> 25) & 1);  // immediate / register shift
-   UChar shift_op  = toUChar((theInstr >> 4) & 0xF); // second byte
-   UInt immed_8, rot_imm;
-   UInt imm;
-   IRTemp oldFlagC = newTemp(Ity_I32);
-   
-   if (is_immed) {  // ARM ARM A5-2
-      // dst = src ROR rot << 1
-      //     = (src >> rot) | (src << (32-rot));
-      immed_8 = theInstr & 0xFF;
-      rot_imm = ((theInstr >> 8) & 0xF) << 1;  
-      imm = (immed_8 >> rot_imm) | (immed_8 << (32-rot_imm));
-      
-      if (rot_imm == 0) {
-         assign( oldFlagC, binop(Iop_Shr32,
-                                 mk_armg_calculate_flags_c(),
-                                 mkU8(ARMG_CC_SHIFT_C)) );
-         assign( *carry_out, mkexpr(oldFlagC) );
-      } else {
-         assign( *carry_out, binop(Iop_Shr32, mkU32(imm), mkU8(31)) );
-      }
-      DIS(buf, "#%u", imm);
-      return mkU32(imm);
-   } else {
-      
-      // We shouldn't have any 'op' with bits 4=1 and 7=1 : 1xx1
-      switch (shift_op) {
-      case 0x0: case 0x8: case 0x1:
-      case 0x2: case 0xA: case 0x3: 
-      case 0x4: case 0xC: case 0x5:
-         return dis_shift( decode_ok, theInstr, carry_out, buf );
-         
-      case 0x6: case 0xE: case 0x7:
-         return dis_rotate( decode_ok, theInstr, carry_out, buf );
-         
-      default: // Error: Any other value shouldn't be here.
-         *decode_ok = False;
-         vex_printf("dis_shifter_op(arm): shift: No such case: 0x%x\n", shift_op);
-         return mkU32(0);
-      }
-   }
+   vassert(rN < 16);
+   vassert(bU < 2);
+   vassert(rM < 16);
+   UChar   opChar = bU == 1 ? '+' : '-';
+   IRExpr* index  = getIReg(rM);
+   DIS(buf, "[r%u, %c r%u]", rN, opChar, rM); 
+   return binop(bU == 1 ? Iop_Add32 : Iop_Sub32,
+                getIReg(rN), index);
 }
 
 
-
-
-
-/* -------------- Helper for DPI's. --------------
-*/
+/* irRes :: Ity_I32 holds a floating point comparison result encoded
+   as an IRCmpF64Result.  Generate code to convert it to an
+   ARM-encoded (N,Z,C,V) group in the lowest 4 bits of an I32 value.
+   Assign a new temp to hold that value, and return the temp. */
 static
-Bool dis_dataproc ( UInt theInstr )
+IRTemp mk_convert_IRCmpF64Result_to_NZCV ( IRTemp irRes )
 {
-   UChar opc       = toUChar((theInstr >> 21) & 0xF);
-   UChar set_flags = toUChar((theInstr >> 20) & 1);
-   UChar Rn_addr   = toUChar((theInstr >> 16) & 0xF);
-   UChar Rd_addr   = toUChar((theInstr >> 12) & 0xF);
-   IRTemp Rn = newTemp(Ity_I32);
-   IRTemp Rd = newTemp(Ity_I32);
-   IRTemp alu_out = newTemp(Ity_I32);
-   IRTemp shifter_op = newTemp(Ity_I32);
-   IRTemp carry_out = newTemp(Ity_I32);
-   IROp op_set_flags = ARMG_CC_OP_LOGIC;
-   Bool testing_instr = False;
-   Bool decode_ok = True;
-   HChar* cond_name = name_ARMCondcode( (theInstr >> 28) & 0xF );
-   HChar* ch_set_flags = (set_flags == 1) ? "S" : "";
-   HChar dis_buf[50];
-   
-   assign( shifter_op, dis_shifter_op( &decode_ok, theInstr, &carry_out, dis_buf ) );
-   if (!decode_ok) return False;
-   
-   assign( Rd, getIReg(Rd_addr) );
-   assign( Rn, getIReg(Rn_addr) );
-   
-   
-   switch (opc) {
-   case 0x0: case 0x1: case 0x2: case 0x3: case 0x4:
-   case 0xC: case 0xE:
-      DIP("%s%s%s R%d, R%d, %s\n", name_ARMDataProcOp(opc),
-          cond_name, ch_set_flags, Rd_addr, Rn_addr, dis_buf);
-      break;
-   case 0x5: case 0x6: case 0x7:
-      // CAB: Unimplemented
-      break;
-   case 0x8: case 0x9: case 0xA: case 0xB:
-      DIP("%s%s R%d, %s\n", name_ARMDataProcOp(opc),
-          cond_name, Rn_addr, dis_buf);
-      break;
-   case 0xD: case 0xF:
-      DIP("%s%s%s R%d, %s\n", name_ARMDataProcOp(opc),
-          cond_name, ch_set_flags, Rd_addr, dis_buf);
-      break;
-   default:break;
-   }
-
-
-   switch (opc) {
-   case 0x0: // AND
-      assign( alu_out, binop(Iop_And32, getIReg(Rn_addr), mkexpr(shifter_op)) );
-      break;
-       
-   case 0x1: // EOR
-      assign( alu_out, binop(Iop_Xor32, getIReg(Rn_addr), mkexpr(shifter_op)) );
-      break;
-
-   case 0x2: // SUB
-      assign( alu_out, binop( Iop_Sub32, getIReg(Rn_addr), mkexpr(shifter_op) ) );
-      op_set_flags = ARMG_CC_OP_SUB;
-      break;
-
-   case 0x3:  // RSB
-      assign( alu_out, binop( Iop_Sub32, mkexpr(shifter_op), getIReg(Rn_addr) ) );
-      op_set_flags = ARMG_CC_OP_SUB;
-      /* set_flags(), below, switches the args for this case */
-      break;
-
-   case 0x4: // ADD
-      assign( alu_out, binop( Iop_Add32, getIReg(Rn_addr), mkexpr(shifter_op) ) );
-      op_set_flags = ARMG_CC_OP_ADD;
-      break;
-
-   case 0x5:  // ADC  // CAB: Unimplemented
-   case 0x6:  // SBC  // CAB: Unimplemented
-   case 0x7:  // RSC  // CAB: Unimplemented
-      goto decode_failure;
-
-   case 0x8: // TST
-      vassert(set_flags==1);
-      assign( alu_out, binop(Iop_And32, getIReg(Rn_addr), mkexpr(shifter_op)) );
-      testing_instr = True;
-      break;
-      
-   case 0x9: // TEQ
-      vassert(set_flags==1);
-      assign( alu_out, binop(Iop_Xor32, getIReg(Rn_addr), mkexpr(shifter_op)) );
-      testing_instr = True;
-      break;
-      
-   case 0xA: // CMP
-      vassert(set_flags==1);
-      op_set_flags = ARMG_CC_OP_SUB;
-      testing_instr = True;
-      break;
-
-   case 0xB: // CMN
-      vassert(set_flags==1);
-      op_set_flags = ARMG_CC_OP_ADD;
-      testing_instr = True;
-      break;
-
-   case 0xC: // ORR
-      assign( alu_out, binop(Iop_Or32, getIReg(Rn_addr), mkexpr(shifter_op)) );
-      break;
-
-   case 0xD: // MOV
-      assign( alu_out, mkexpr(shifter_op) );
-      break;
-
-   case 0xE: // BIC
-      assign( alu_out, binop(Iop_And32, getIReg(Rn_addr),
-                             unop( Iop_Not32, mkexpr(shifter_op))) );
-      break;
-
-   case 0xF: // MVN
-      assign( alu_out, unop(Iop_Not32, mkexpr(shifter_op)) );
-      break;
-
-   default:
-   decode_failure:
-      vex_printf("dis_dataproc(arm): unhandled opcode: 0x%x\n", opc);
-      return False;
-   }
-
-   if (!testing_instr) {
-      if ( Rd_addr == 15) { // dest reg == PC
-         // CPSR = SPSR: Unpredictable in User | System mode (no SPSR!)
-         // Unpredictable - We're only supporting user mode...
-         vex_printf("dis_dataproc(arm): Unpredictable - Rd_addr==15\n");
-         return False;
-      }
-      putIReg( Rd_addr, mkexpr(alu_out) );
-   }
-   
-   if (set_flags) {
-      if (op_set_flags == ARMG_CC_OP_LOGIC) {
-         setFlags_DEP1_DEP2( op_set_flags, alu_out, carry_out );
-      } else {
-         if (opc == 0x3) {
-            setFlags_DEP1_DEP2( op_set_flags, shifter_op, Rn );
-         } else {
-            setFlags_DEP1_DEP2( op_set_flags, Rn, shifter_op );
-         }
-      }
-   }
-   return decode_ok;
-}
+   IRTemp ix       = newTemp(Ity_I32);
+   IRTemp termL    = newTemp(Ity_I32);
+   IRTemp termR    = newTemp(Ity_I32);
+   IRTemp nzcv     = newTemp(Ity_I32);
+
+   /* This is where the fun starts.  We have to convert 'irRes' from
+      an IR-convention return result (IRCmpF64Result) to an
+      ARM-encoded (N,Z,C,V) group.  The final result is in the bottom
+      4 bits of 'nzcv'. */
+   /* Map compare result from IR to ARM(nzcv) */
+   /*
+      FP cmp result | IR   | ARM(nzcv)
+      --------------------------------
+      UN              0x45   0011
+      LT              0x01   1000
+      GT              0x00   0010
+      EQ              0x40   0110
+   */
+   /* Now since you're probably wondering WTF ..
 
+      ix fishes the useful bits out of the IR value, bits 6 and 0, and
+      places them side by side, giving a number which is 0, 1, 2 or 3.
 
+      termL is a sequence cooked up by GNU superopt.  It converts ix
+         into an almost correct value NZCV value (incredibly), except
+         for the case of UN, where it produces 0100 instead of the
+         required 0011.
 
+      termR is therefore a correction term, also computed from ix.  It
+         is 1 in the UN case and 0 for LT, GT and UN.  Hence, to get
+         the final correct value, we subtract termR from termL.
 
-/* -------------- Helper for Branch. --------------
-*/
-static
-void dis_branch ( UInt theInstr )
-{
-   UChar link = toUChar((theInstr >> 24) & 1);
-   UInt signed_immed_24 = theInstr & 0xFFFFFF;
-   UInt branch_offset;
-   IRTemp addr = newTemp(Ity_I32);
-   IRTemp dest = newTemp(Ity_I32);
-   
-   if (link) { // LR (R14) = addr of instr after branch instr
-      assign( addr, binop(Iop_Add32, getIReg(15), mkU32(4)) );
-      putIReg( 14, mkexpr(addr) );
-   }
-   
-   // PC = PC + (SignExtend(signed_immed_24) << 2)
-   branch_offset = extend_s_24to32( signed_immed_24 ) << 2;
-   assign( dest, binop(Iop_Add32, getIReg(15), mkU32(branch_offset)) );
-   
-   irsb->jumpkind = link ? Ijk_Call : Ijk_Boring;
-   irsb->next     = mkexpr(dest);
-   
-   // Note: Not actually writing to R15 - let the IR stuff do that.
-   
-   DIP("b%s%s 0x%x\n",
-       link ? "l" : "",
-       name_ARMCondcode( (theInstr >> 28) & 0xF ),
-       branch_offset);
+      Don't take my word for it.  There's a test program at the bottom
+      of this file, to try this out with.
+   */
+   assign(
+      ix,
+      binop(Iop_Or32,
+            binop(Iop_And32,
+                  binop(Iop_Shr32, mkexpr(irRes), mkU8(5)),
+                  mkU32(3)),
+            binop(Iop_And32, mkexpr(irRes), mkU32(1))));
+
+   assign(
+      termL,
+      binop(Iop_Add32,
+            binop(Iop_Shr32,
+                  binop(Iop_Sub32,
+                        binop(Iop_Shl32,
+                              binop(Iop_Xor32, mkexpr(ix), mkU32(1)),
+                              mkU8(30)),
+                        mkU32(1)),
+                  mkU8(29)),
+            mkU32(1)));
+
+   assign(
+      termR,
+      binop(Iop_And32,
+            binop(Iop_And32,
+                  mkexpr(ix),
+                  binop(Iop_Shr32, mkexpr(ix), mkU8(1))),
+            mkU32(1)));
+
+   assign(nzcv, binop(Iop_Sub32, mkexpr(termL), mkexpr(termR)));
+   return nzcv;
 }
 
 
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 /*------------------------------------------------------------*/
 /*--- Disassemble a single instruction                     ---*/
 /*------------------------------------------------------------*/
 
-/* Disassemble a single instruction into IR.  The instruction
-   is located in host memory at &guest_code[delta].
-   Set *size to be the size of the instruction.
-   If the returned value is Dis_Resteer,
-   the next guest address is assigned to *whereNext.  If resteerOK
-   is False, disInstr may not return Dis_Resteer. */
-   
-static DisResult disInstr ( /*IN*/  Bool    resteerOK,
-                            /*IN*/  Bool    (*resteerOkFn) ( Addr64 ),
-                            /*IN*/  Long    delta, 
-                            /*OUT*/ Int*    size,
-                            /*OUT*/ Addr64* whereNext )
+/* Disassemble a single instruction into IR.  The instruction is
+   located in host memory at guest_instr, and has guest IP of
+   guest_R15_curr_instr, which will have been set before the call
+   here. */
+
+static   
+DisResult disInstr_ARM_WRK (
+             Bool         put_IP,
+             Bool         (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
+             void*        callback_opaque,
+             UChar*       guest_instr,
+             VexArchInfo* archinfo,
+             VexAbiInfo*  abiinfo
+          )
 {
-   //   IRType    ty;
-   //  IRTemp    addr, t1, t2;
-   //   Int       alen;
-   UChar opc1, opc2, opc_tmp; //, modrm, abyte;
-   ARMCondcode cond;
-   //  UInt      d32;
-   // UChar     dis_buf[50];
-   // Int       am_sz, d_sz;
-   DisResult whatNext = Dis_Continue;
-   UInt      theInstr;
-   
+   // A macro to fish bits out of 'insn'.
+#  define INSN(_bMax,_bMin) \
+      ((insn >> (_bMin)) & ((1 << ((_bMax) - (_bMin) + 1)) - 1))
+#  define INSN_COND \
+      INSN(31,28)
+
+   DisResult dres;
+   UInt      insn;
+   //Bool      allow_VFP = False;
+   //UInt      hwcaps = archinfo->hwcaps;
+   IRTemp    condT; /* :: Ity_I32 */
+   UInt      summary;
+   HChar     dis_buf[128];  // big enough to hold LDMIA etc text
+
+   /* What insn variants are we supporting today? */
+   //allow_VFP  = (0 != (hwcaps & VEX_HWCAPS_ARM_VFP));
+   // etc etc
+
+   /* Set result defaults. */
+   dres.whatNext   = Dis_Continue;
+   dres.len        = 4;
+   dres.continueAt = 0;
+
+   /* Set default actions for post-insn handling of writes to r15, if
+      required. */
+   r15written = False;
+   r15guard   = IRTemp_INVALID; /* unconditional */
+   r15kind    = Ijk_Boring;
 
    /* At least this is simple on ARM: insns are all 4 bytes long, and
       4-aligned.  So just fish the whole thing out of memory right now
       and have done. */
-   
-   /* We will set *size to 4 if the insn is successfully decoded.
-      Setting it to 0 by default makes bbToIR_ARM abort if we fail the
-      decode. */
-   *size = 0;
+   insn = getUIntLittleEndianly( guest_instr );
 
-   theInstr = *(UInt*)(&guest_code[delta]);
-
-//   vex_printf("START: 0x%x, %,b\n", theInstr, theInstr );
-
-   DIP("\t0x%x:  ", toUInt(guest_pc_bbstart+delta));
+   if (0) vex_printf("insn: 0x%x\n", insn);
 
+   DIP("\t0x%x:  ", (UInt)guest_R15_curr_instr);
 
+   /* We may be asked to update the guest R15 before going further. */
+   if (put_IP) {
+      vassert(0 == (guest_R15_curr_instr & 3));
+      llPutIReg( 15, mkU32(guest_R15_curr_instr) );
+   }
 
-   // TODO: fix the client-request stuff, else nothing will work
+   /* ----------------------------------------------------------- */
 
-   /* Spot the client-request magic sequence. */
-   // Essentially a v. unlikely sequence of noops that we can catch
+   /* Spot "Special" instructions (see comment at top of file). */
    {
-      UInt* code = (UInt*)(guest_code + delta);
-      
-      /* Spot this:                                       
-         E1A00EE0                   mov  r0, r0, ror #29
-         E1A001E0                   mov  r0, r0, ror #3
-         E1A00DE0                   mov  r0, r0, ror #27
-         E1A002E0                   mov  r0, r0, ror #5
-         E1A006E0                   mov  r0, r0, ror #13
-         E1A009E0                   mov  r0, r0, ror #19
+      UChar* code = (UChar*)guest_instr;
+      /* Spot the 16-byte preamble: 
+
+         e1a0c1ec  mov r12, r12, ROR #3
+         e1a0c6ec  mov r12, r12, ROR #13
+         e1a0ceec  mov r12, r12, ROR #29
+         e1a0c9ec  mov r12, r12, ROR #19
       */
-      /* I suspect these will have to be turned the other way round to
-         work on little-endian arm. */
-      if (code[0] == 0xE1A00EE0 &&
-          code[1] == 0xE1A001E0 &&
-          code[2] == 0xE1A00DE0 &&
-          code[3] == 0xE1A002E0 &&
-          code[4] == 0xE1A006E0 &&
-          code[5] == 0xE1A009E0) {
-
-         // uh ... I'll figure this out later.  possibly r0 = client_request(r0) */
-         DIP("?CAB? = client_request ( ?CAB? )\n");
-         
-         *size = 24;
-         
-         irsb->next     = mkU32(toUInt(guest_pc_bbstart+delta));
-         irsb->jumpkind = Ijk_ClientReq;
-         
-         whatNext = Dis_StopHere;
-         goto decode_success;
+      UInt word1 = 0xE1A0C1EC;
+      UInt word2 = 0xE1A0C6EC;
+      UInt word3 = 0xE1A0CEEC;
+      UInt word4 = 0xE1A0C9EC;
+      if (getUIntLittleEndianly(code+ 0) == word1 &&
+          getUIntLittleEndianly(code+ 4) == word2 &&
+          getUIntLittleEndianly(code+ 8) == word3 &&
+          getUIntLittleEndianly(code+12) == word4) {
+         /* Got a "Special" instruction preamble.  Which one is it? */
+         if (getUIntLittleEndianly(code+16) == 0xE18AA00A
+                                               /* orr r10,r10,r10 */) {
+            /* R3 = client_request ( R4 ) */
+            DIP("r3 = client_request ( %%r4 )\n");
+            irsb->next     = mkU32( guest_R15_curr_instr + 20 );
+            irsb->jumpkind = Ijk_ClientReq;
+            dres.whatNext  = Dis_StopHere;
+            goto decode_success;
+         }
+         else
+         if (getUIntLittleEndianly(code+16) == 0xE18BB00B
+                                               /* orr r11,r11,r11 */) {
+            /* R3 = guest_NRADDR */
+            DIP("r3 = guest_NRADDR\n");
+            dres.len = 20;
+            llPutIReg(3, IRExpr_Get( OFFB_NRADDR, Ity_I32 ));
+            goto decode_success;
+         }
+         else
+         if (getUIntLittleEndianly(code+16) == 0xE18CC00C
+                                               /* orr r12,r12,r12 */) {
+            /*  branch-and-link-to-noredir R4 */
+            DIP("branch-and-link-to-noredir r4\n");
+            llPutIReg(14, mkU32( guest_R15_curr_instr + 20) );
+            irsb->next     = llGetIReg(4);
+            irsb->jumpkind = 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. */
+         insn = getUIntLittleEndianly(code+16);
+         goto decode_failure;
+         /*NOTREACHED*/
       }
-   }
-
 
+   }
 
+   /* ----------------------------------------------------------- */
 
+   /* Main instruction decoder starts here. */
 
-   /*
-     Deal with condition first
-   */
-   cond = (theInstr >> 28) & 0xF;    /* opcode: bits 31:28 */
-//   vex_printf("\ndisInstr(arm): cond: 0x%x, %b\n", cond, cond );
-   
-   switch (cond) {
-   case 0xF:   // => Illegal instruction prior to v5 (see ARM ARM A3-5)
-      vex_printf("disInstr(arm): illegal condition\n");
-      goto decode_failure;
-      
-   case 0xE:   // => Unconditional: go translate the instruction
-      break;
-
-   default:
-      // => Valid condition: translate the condition test first
-      stmt( IRStmt_Exit( mk_armg_calculate_condition(cond),
-                         Ijk_Boring,
-                         IRConst_U32(toUInt(guest_pc_bbstart+delta+4)) ) );
-      //irsb->next     = mkU32(guest_pc_bbstart+delta+4);
-      //irsb->jumpkind = Ijk_Boring;
+   /* Deal with the condition.  Strategy is to merely generate a
+      condition expression at this point (or NULL, meaning
+      unconditional).  We leave it to lower-level instruction decoders
+      to decide whether they can generate straight-line code, or
+      whether they must generate a side exit before the instruction.
+      condT :: Ity_I32 and is always either zero or one. */
+   condT = IRTemp_INVALID;
+   switch ( (ARMCondcode)INSN_COND ) {
+      case ARMCondNV: // Illegal instruction prior to v5 (see ARM ARM A3-5)
+         goto decode_failure;
+      case ARMCondAL: // Always executed
+         break;
+      case ARMCondEQ: case ARMCondNE: case ARMCondHS: case ARMCondLO:
+      case ARMCondMI: case ARMCondPL: case ARMCondVS: case ARMCondVC:
+      case ARMCondHI: case ARMCondLS: case ARMCondGE: case ARMCondLT:
+      case ARMCondGT: case ARMCondLE:
+         condT = newTemp(Ity_I32);
+         assign( condT, mk_armg_calculate_condition( INSN_COND ));
+         break;
    }
-   
 
-
-   /* Primary opcode is roughly bits 27:20 (ARM ARM(v2) A3-2)
-      secondary opcode is bits 4:0 */
-   opc1 = toUChar((theInstr >> 20) & 0xFF);    /* opcode1: bits 27:20 */
-   opc2 = toUChar((theInstr >> 4 ) & 0xF);     /* opcode2: bits 7:4   */
-//   vex_printf("disInstr(arm): opcode1: 0x%2x, %,09b\n", opc1, opc1 );
-//   vex_printf("disInstr(arm): opcode2: 0x%02x, %,04b\n", opc2, opc2 );
-   
-   switch (opc1 >> 4) { // instr[27:24]
-   case 0x0:
-   case 0x1:
-      /*
-        Multiplies, extra load/store instructions: ARM ARM A3-3
-      */
-      if ( (opc1 & 0xE0) == 0x0 && (opc2 & 0x9) == 0x9 ) {  // 000xxxxx && 1xx1
-         if (opc2 == 0x9) {
-            if ((opc1 & 0x1C) == 0x00) {  // multiply (accumulate)
-               goto decode_failure;
+   /* ----------------------------------------------------------- */
+   /* -- ARMv5 integer instructions                            -- */
+   /* ----------------------------------------------------------- */
+
+   /* ---------------- Data processing ops ------------------- */
+
+   if (0 == (INSN(27,20) & BITS8(1,1,0,0,0,0,0,0))
+       && !(INSN(25,25) == 0 && INSN(7,7) == 1 && INSN(4,4) == 1)) {
+      IRTemp  shop = IRTemp_INVALID; /* shifter operand */
+      IRTemp  shco = IRTemp_INVALID; /* shifter carry out */
+      UInt    rD   = (insn >> 12) & 0xF; /* 15:12 */
+      UInt    rN   = (insn >> 16) & 0xF; /* 19:16 */
+      UInt    bitS = (insn >> 20) & 1; /* 20:20 */
+      IRTemp  rNt  = IRTemp_INVALID;
+      IRTemp  res  = IRTemp_INVALID;
+      IRTemp  oldV = IRTemp_INVALID;
+      IRTemp  oldC = IRTemp_INVALID;
+      HChar*  name = NULL;
+      IROp    op   = Iop_INVALID;
+      Bool    ok;
+
+      switch (INSN(24,21)) {
+
+         /* --------- ADD, SUB, AND, OR --------- */
+         case BITS4(0,1,0,0): /* ADD:  Rd = Rn + shifter_operand */
+            name = "add"; op = Iop_Add32; goto rd_eq_rn_op_SO;
+         case BITS4(0,0,1,0): /* SUB:  Rd = Rn - shifter_operand */
+            name = "sub"; op = Iop_Sub32; goto rd_eq_rn_op_SO;
+         case BITS4(0,0,1,1): /* RSB:  Rd = shifter_operand - Rn */
+            name = "rsb"; op = Iop_Sub32; goto rd_eq_rn_op_SO;
+         case BITS4(0,0,0,0): /* AND:  Rd = Rn & shifter_operand */
+            name = "and"; op = Iop_And32; goto rd_eq_rn_op_SO;
+         case BITS4(1,1,0,0): /* OR:   Rd = Rn | shifter_operand */
+            name = "orr"; op = Iop_Or32; goto rd_eq_rn_op_SO;
+         case BITS4(0,0,0,1): /* EOR:  Rd = Rn ^ shifter_operand */
+            name = "eor"; op = Iop_Xor32; goto rd_eq_rn_op_SO;
+         case BITS4(1,1,1,0): /* BIC:  Rd = Rn & ~shifter_operand */
+            name = "bic"; op = Iop_And32; goto rd_eq_rn_op_SO;
+         rd_eq_rn_op_SO: {
+            Bool isRSB = False;
+            Bool isBIC = False;
+            switch (INSN(24,21)) {
+               case BITS4(0,0,1,1):
+                  vassert(op == Iop_Sub32); isRSB = True; break;
+               case BITS4(1,1,1,0):
+                  vassert(op == Iop_And32); isBIC = True; break;
+               default:
+                  break;
             }
-            if ((opc1 & 0x18) == 0x08) {  // multiply (accumulate) long
-               goto decode_failure;
+            rNt = newTemp(Ity_I32);
+            assign(rNt, getIReg(rN));
+            ok = mk_shifter_operand(
+                    INSN(25,25), INSN(11,0), 
+                    &shop, bitS ? &shco : NULL, dis_buf
+                 );
+            if (!ok)
+               break;
+            res = newTemp(Ity_I32);
+            // compute the main result
+            if (isRSB) {
+               // reverse-subtract: shifter_operand - Rn
+               vassert(op == Iop_Sub32);
+               assign(res, binop(op, mkexpr(shop), mkexpr(rNt)) );
+            } else if (isBIC) {
+               // andn: shifter_operand & ~Rn
+               vassert(op == Iop_And32);
+               assign(res, binop(op, mkexpr(rNt),
+                                     unop(Iop_Not32, mkexpr(shop))) );
+            } else {
+               // normal: Rn op shifter_operand
+               assign(res, binop(op, mkexpr(rNt), mkexpr(shop)) );
             }
-            if ((opc1 & 0x1B) == 0x10) {  // swap/swap byte
-               goto decode_failure;
+            // but don't commit it until after we've finished
+            // all necessary reads from the guest state
+            if (bitS
+                && (op == Iop_And32 || op == Iop_Or32 || op == Iop_Xor32)) {
+               oldV = newTemp(Ity_I32);
+               assign( oldV, mk_armg_calculate_flag_v() );
             }
-         }
-         if ( opc2 == 0xB ) {
-            if ((opc1 & 0x04) == 0x00) {  // load/store 1/2word reg offset
-               goto decode_failure;
-            } else {                      // load/store 1/2word imm offset
-               goto decode_failure;
+            // now safe to put the main result
+            putIReg( rD, mkexpr(res), condT, Ijk_Boring );
+            // XXXX!! not safe to read any guest state after
+            // this point (I think the code below doesn't do that).
+            if (!bitS)
+               vassert(shco == IRTemp_INVALID);
+            /* Update the flags thunk if necessary */
+            if (bitS) {
+               vassert(shco != IRTemp_INVALID);
+               switch (op) {
+                  case Iop_Add32:
+                     setFlags_D1_D2( ARMG_CC_OP_ADD, rNt, shop, condT );
+                     break;
+                  case Iop_Sub32:
+                     if (isRSB) {
+                        setFlags_D1_D2( ARMG_CC_OP_SUB, shop, rNt, condT );
+                     } else {
+                        setFlags_D1_D2( ARMG_CC_OP_SUB, rNt, shop, condT );
+                     }
+                     break;
+                  case Iop_And32: /* BIC and AND set the flags the same */
+                  case Iop_Or32:
+                  case Iop_Xor32:
+                     // oldV has been read just above
+                     setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC,
+                                        res, shco, oldV, condT );
+                     break;
+                  default:
+                     vassert(0);
+               }
             }
+            DIP("%s%s%s r%u, r%u, %s\n",
+                name, nCC(INSN_COND), bitS ? "s" : "", rD, rN, dis_buf );
+            goto decode_success;
          }
-         if ((opc2 & 0xD) == 0xD) {
-            if ((opc1 & 0x05) == 0x00) {  // load/store 2 words reg offset
-               goto decode_failure;
-            }
-            if ((opc1 & 0x05) == 0x04) {  // load/store 2 words imm offset
-               goto decode_failure;
-            }
-            if ((opc1 & 0x05) == 0x01) {  // load/store signed 1/2word/byte reg offset
-               goto decode_failure;
+
+         /* --------- MOV, MVN --------- */
+         case BITS4(1,1,0,1):   /* MOV: Rd = shifter_operand */
+         case BITS4(1,1,1,1): { /* MVN: Rd = not(shifter_operand) */
+            Bool isMVN = INSN(24,21) == BITS4(1,1,1,1);
+            if (rN != 0)
+               break; /* rN must be zero */
+            ok = mk_shifter_operand(
+                    INSN(25,25), INSN(11,0), 
+                    &shop, bitS ? &shco : NULL, dis_buf
+                 );
+            if (!ok)
+               break;
+            res = newTemp(Ity_I32);
+            assign( res, isMVN ? unop(Iop_Not32, mkexpr(shop))
+                               : mkexpr(shop) );
+            if (bitS) {
+               vassert(shco != IRTemp_INVALID);
+               oldV = newTemp(Ity_I32);
+               assign( oldV, mk_armg_calculate_flag_v() );
+            } else {
+               vassert(shco == IRTemp_INVALID);
             }
-            if ((opc1 & 0x05) == 0x05) {  // load/store signed 1/2word/byte imm offset
-               goto decode_failure;
+            // can't safely read guest state after here
+            putIReg( rD, mkexpr(res), condT, Ijk_Boring );
+            /* Update the flags thunk if necessary */
+            if (bitS) {
+               setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC, 
+                                  res, shco, oldV, condT );
             }
+            DIP("%s%s%s r%u, %s\n",
+                isMVN ? "mvn" : "mov",
+                nCC(INSN_COND), bitS ? "s" : "", rD, dis_buf );
+            goto decode_success;
          }
-      } /* endif: Multiplies, extra load/store... */
-      
-      /* 
-         'Misc' Instructions: ARM ARM A3-4
-      */
-      if ((opc1 & 0xF9) == 0x10) {  // 0001 0xx0
-         opc_tmp = toUChar((opc1 >> 1) & 0x3);
-         switch (opc2) {
-         case 0x0:
-            if ((opc_tmp & 0x1) == 0x0) { // move stat reg -> reg
-               goto decode_failure;
-            } else {                      // move reg -> stat reg
-               goto decode_failure;
-            }
-            
-         case 0x1:
-            if (opc_tmp == 0x1) {       // branch/exchange instr set
-               goto decode_failure;
-            }
-            if (opc_tmp == 0x3) {       // count leading zeros
-               goto decode_failure;
-            }
-            break;
-            
-         case 0x3:
-            if (opc_tmp == 0x1) {       // branch & link/exchange instr set
-               goto decode_failure;
-            }
-            break;
-            
-         case 0x5:                       // enhanced dsp add/subtracts
-            goto decode_failure;
-            
-         case 0x7:
-            if (opc_tmp == 0x1) {       // software breakpoint
-               if (cond != 0xE) {            // Unpredictable - ARM ARM A3-4
-                  vex_printf("disInstr(arm): Unpredictable instruction\n");
-                  goto decode_failure;
+
+         /* --------- CMP --------- */
+         case BITS4(1,0,1,0):   /* CMP:  (void) Rn - shifter_operand */
+         case BITS4(1,0,1,1): { /* CMN:  (void) Rn + shifter_operand */
+            Bool isCMN = INSN(24,21) == BITS4(1,0,1,1);
+            if (rD != 0)
+               break; /* rD must be zero */
+            if (bitS == 0)
+               break; /* if S (bit 20) is not set, it's not CMP/CMN */
+            rNt = newTemp(Ity_I32);
+            assign(rNt, getIReg(rN));
+            ok = mk_shifter_operand(
+                    INSN(25,25), INSN(11,0), 
+                    &shop, NULL, dis_buf
+                 );
+            if (!ok)
+               break;
+            /* Update the flags thunk. */
+            setFlags_D1_D2( isCMN ? ARMG_CC_OP_ADD : ARMG_CC_OP_SUB,
+                            rNt, shop, condT );
+            DIP("%s%s r%u, %s\n",
+                isCMN ? "cmn" : "cmp",
+                nCC(INSN_COND), rN, dis_buf );
+            goto decode_success;
+         }
+
+         /* --------- TST --------- */
+         case BITS4(1,0,0,0):   /* TST:  (void) Rn & shifter_operand */
+         case BITS4(1,0,0,1): { /* TEQ:  (void) Rn ^ shifter_operand */
+            Bool isTEQ = INSN(24,21) == BITS4(1,0,0,1);
+            if (rD != 0)
+               break; /* rD must be zero */
+            if (bitS == 0)
+               break; /* if S (bit 20) is not set, it's not TST/TEQ */
+            rNt = newTemp(Ity_I32);
+            assign(rNt, getIReg(rN));
+            ok = mk_shifter_operand(
+                    INSN(25,25), INSN(11,0), 
+                    &shop, &shco, dis_buf
+                 );
+            if (!ok)
+               break;
+            /* Update the flags thunk. */
+            res = newTemp(Ity_I32);
+            assign( res, binop(isTEQ ? Iop_Xor32 : Iop_And32, 
+                               mkexpr(rNt), mkexpr(shop)) );
+            oldV = newTemp(Ity_I32);
+            assign( oldV, mk_armg_calculate_flag_v() );
+            setFlags_D1_D2_ND( ARMG_CC_OP_LOGIC,
+                               res, shco, oldV, condT );
+            DIP("%s%s r%u, %s\n",
+                isTEQ ? "teq" : "tst",
+                nCC(INSN_COND), rN, dis_buf );
+            goto decode_success;
+         }
+
+         /* --------- ADC, SBC, RSC --------- */
+         case BITS4(0,1,0,1): /* ADC:  Rd = Rn + shifter_operand + oldC */
+            name = "adc"; goto rd_eq_rn_op_SO_op_oldC;
+         case BITS4(0,1,1,0): /* SBC:  Rd = Rn - shifter_operand - (oldC ^ 1) */
+            name = "sbc"; goto rd_eq_rn_op_SO_op_oldC;
+         case BITS4(0,1,1,1): /* RSC:  Rd = shifter_operand - Rn - (oldC ^ 1) */
+            name = "rsc"; goto rd_eq_rn_op_SO_op_oldC;
+         rd_eq_rn_op_SO_op_oldC: {
+            rNt = newTemp(Ity_I32);
+            assign(rNt, getIReg(rN));
+            ok = mk_shifter_operand(
+                    INSN(25,25), INSN(11,0), 
+                    &shop, bitS ? &shco : NULL, dis_buf
+                 );
+            if (!ok)
+               break;
+            oldC = newTemp(Ity_I32);
+            assign( oldC, mk_armg_calculate_flag_c() );
+            res = newTemp(Ity_I32);
+            // compute the main result
+            switch (INSN(24,21)) {
+               case BITS4(0,1,0,1): /* ADC */
+                  assign(res,
+                         binop(Iop_Add32,
+                               binop(Iop_Add32, mkexpr(rNt), mkexpr(shop)),
+                               mkexpr(oldC) ));
+                  break;
+               case BITS4(0,1,1,0): /* SBC */
+                  assign(res,
+                         binop(Iop_Sub32,
+                               binop(Iop_Sub32, mkexpr(rNt), mkexpr(shop)),
+                               binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
+                  break;
+               case BITS4(0,1,1,1): /* RSC */
+                  assign(res,
+                         binop(Iop_Sub32,
+                               binop(Iop_Sub32, mkexpr(shop), mkexpr(rNt)),
+                               binop(Iop_Xor32, mkexpr(oldC), mkU32(1)) ));
+                  break;
+               default:
+                  vassert(0);
+            }
+            // but don't commit it until after we've finished
+            // all necessary reads from the guest state
+            // now safe to put the main result
+            putIReg( rD, mkexpr(res), condT, Ijk_Boring );
+            // XXXX!! not safe to read any guest state after
+            // this point (I think the code below doesn't do that).
+            if (!bitS)
+               vassert(shco == IRTemp_INVALID);
+            /* Update the flags thunk if necessary */
+            if (bitS) {
+               vassert(shco != IRTemp_INVALID);
+               switch (INSN(24,21)) {
+                  case BITS4(0,1,0,1): /* ADC */
+                     setFlags_D1_D2_ND( ARMG_CC_OP_ADC,
+                                        rNt, shop, oldC, condT );
+                     break;
+                  case BITS4(0,1,1,0): /* SBC */
+                     setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
+                                        rNt, shop, oldC, condT );
+                     break;
+                  case BITS4(0,1,1,1): /* RSC */
+                     setFlags_D1_D2_ND( ARMG_CC_OP_SBB,
+                                        shop, rNt, oldC, condT );
+                     break;
+                  default:
+                     vassert(0);
                }
-               goto decode_failure;
             }
-            break;
-            
-         case 0x8: case 0x9: case 0xA:   // enhanced dsp multiplies
-         case 0xB: case 0xC: case 0xD: case 0xE:
-            goto decode_failure;
-            
-             default: break;
+            DIP("%s%s%s r%u, r%u, %s\n",
+                name, nCC(INSN_COND), bitS ? "s" : "", rD, rN, dis_buf );
+            goto decode_success;
          }
-      } /* endif: 'Misc' Instructions... */
-      // fall through...
-      
-   case 0x2:
-   case 0x3:
-      if ((opc1 & 0xFB) == 0x30) goto decode_failure; // Undefined - ARM ARM A3-2
-      
-      /*
-        A lonely 'MOV imm to status reg':
-      */
-      if ((opc1 & 0xFB) == 0x32) { // 0011 0x10
-         goto decode_failure;
+
+         /* --------- ??? --------- */
+         default:
+            break;
       }
-      
-      /*
-        Data Processing Instructions
-        (if we get here, it's a dpi)
-      */
-      if (!dis_dataproc( theInstr )) { goto decode_failure; }
-      break;
-      
+   } /* if (0 == (INSN(27,20) & BITS8(1,1,0,0,0,0,0,0)) */
+
+   /* --------------------- Load/store (ubyte & word) -------- */
+   // LDR STR LDRB STRB
+   /*                 31   27   23   19 15 11    6   4 3  # highest bit
+                        28   24   20 16 12
+      A5-20   1 | 16  cond 0101 UB0L Rn Rd imm12
+      A5-22   1 | 32  cond 0111 UBOL Rn Rd imm5  sh2 0 Rm
+      A5-24   2 | 16  cond 0101 UB1L Rn Rd imm12
+      A5-26   2 | 32  cond 0111 UB1L Rn Rd imm5  sh2 0 Rm
+      A5-28   3 | 16  cond 0100 UB0L Rn Rd imm12
+      A5-32   3 | 32  cond 0110 UB0L Rn Rd imm5  sh2 0 Rm
+   */
+   /* case coding:
+             1   at-ea               (access at ea)
+             2   at-ea-then-upd      (access at ea, then Rn = ea)
+             3   at-Rn-then-upd      (access at Rn, then Rn = ea)
+      ea coding
+             16  Rn +/- imm12
+             32  Rn +/- Rm sh2 imm5
+   */
+   /* Quickly skip over all of this for hopefully most instructions */
+   if ((INSN(27,24) & BITS4(1,1,0,0)) != BITS4(0,1,0,0))
+      goto after_load_store_ubyte_or_word;
 
-   /*
-     Load/Store word | unsigned byte
+   summary = 0;
+   
+   /**/ if (INSN(27,24) == BITS4(0,1,0,1) && INSN(21,21) == 0) {
+      summary = 1 | 16;
+   }
+   else if (INSN(27,24) == BITS4(0,1,1,1) && INSN(21,21) == 0
+                                          && INSN(4,4) == 0) {
+      summary = 1 | 32;
+   }
+   else if (INSN(27,24) == BITS4(0,1,0,1) && INSN(21,21) == 1) {
+      summary = 2 | 16;
+   }
+   else if (INSN(27,24) == BITS4(0,1,1,1) && INSN(21,21) == 1
+                                          && INSN(4,4) == 0) {
+      summary = 2 | 32;
+   }
+   else if (INSN(27,24) == BITS4(0,1,0,0) && INSN(21,21) == 0) {
+      summary = 3 | 16;
+   }
+   else if (INSN(27,24) == BITS4(0,1,1,0) && INSN(21,21) == 0
+                                          && INSN(4,4) == 0) {
+      summary = 3 | 32;
+   }
+   else goto after_load_store_ubyte_or_word;
+
+   { UInt rN = (insn >> 16) & 0xF; /* 19:16 */
+     UInt rD = (insn >> 12) & 0xF; /* 15:12 */
+     UInt rM = (insn >> 0)  & 0xF; /*  3:0  */
+     UInt bU = (insn >> 23) & 1;      /* 23 */
+     UInt bB = (insn >> 22) & 1;      /* 22 */
+     UInt bL = (insn >> 20) & 1;      /* 20 */
+     UInt imm12 = (insn >> 0) & 0xFFF; /* 11:0 */
+     UInt imm5  = (insn >> 7) & 0x1F;  /* 11:7 */
+     UInt sh2   = (insn >> 5) & 3;     /* 6:5 */
+
+     /* Skip some invalid cases, which would lead to two competing
+        updates to the same register, or which are otherwise
+        disallowed by the spec. */
+     switch (summary) {
+        case 1 | 16:
+           break;
+        case 1 | 32: 
+           if (rM == 15) goto after_load_store_ubyte_or_word;
+           break;
+        case 2 | 16: case 3 | 16:
+           if (rN == 15) goto after_load_store_ubyte_or_word;
+           if (bL == 1 && rN == rD) goto after_load_store_ubyte_or_word;
+           break;
+        case 2 | 32: case 3 | 32:
+           if (rM == 15) goto after_load_store_ubyte_or_word;
+           if (rN == 15) goto after_load_store_ubyte_or_word;
+           if (rN == rM) goto after_load_store_ubyte_or_word;
+           if (bL == 1 && rN == rD) goto after_load_store_ubyte_or_word;
+           break;
+        default:
+           vassert(0);
+     }
+
+     /* Now, we can't do a conditional load or store, since that very
+        likely will generate an exception.  So we have to take a side
+        exit at this point if the condition is false. */
+     if (condT != IRTemp_INVALID) {
+        mk_skip_to_next_if_cond_is_false( condT );
+        condT = IRTemp_INVALID;
+     }
+     /* Ok, now we're unconditional.  Do the load or store. */
+
+     /* compute the effective address.  Bind it to a tmp since we
+        may need to use it twice. */
+     IRExpr* eaE = NULL;
+     switch (summary & 0xF0) {
+        case 16:
+           eaE = mk_EA_reg_plusminus_imm12( rN, bU, imm12, dis_buf );
+           break;
+        case 32:
+           eaE = mk_EA_reg_plusminus_shifted_reg( rN, bU, rM, sh2, imm5,
+                                                  dis_buf );
+           break;
+     }
+     vassert(eaE);
+     IRTemp eaT = newTemp(Ity_I32);
+     assign(eaT, eaE);
+
+     /* get the old Rn value */
+     IRTemp rnT = newTemp(Ity_I32);
+     assign(rnT, getIReg(rN));
+
+     /* decide on the transfer address */
+     IRTemp taT = IRTemp_INVALID;
+     switch (summary & 0x0F) {
+        case 1: case 2: taT = eaT; break;
+        case 3:         taT = rnT; break;
+     }
+     vassert(taT != IRTemp_INVALID);
+
+     if (bL == 0) {
+       /* Store.  If necessary, update the base register before the
+          store itself, so that the common idiom of "str rX, [sp,
+          #-4]!" (store rX at sp-4, then do new sp = sp-4, a.k.a "push
+          rX") doesn't cause Memcheck to complain that the access is
+          below the stack pointer.  Also, not updating sp before the
+          store confuses Valgrind's dynamic stack-extending logic.  So
+          do it before the store.  Hence we need to snarf the store
+          data before doing the basereg update. */
+
+        /* get hold of the data to be stored */
+        IRTemp rDt = newTemp(Ity_I32);
+        assign(rDt, getIReg(rD));
+
+        /* Update Rn if necessary. */
+        switch (summary & 0x0F) {
+           case 2: case 3:
+              putIReg( rN, mkexpr(eaT), IRTemp_INVALID, Ijk_Boring );
+              break;
+        }
+
+        /* generate the transfer */
+        if (bB == 0) { // word store
+           storeLE( mkexpr(taT), mkexpr(rDt) );
+        } else { // byte store
+           vassert(bB == 1);
+           storeLE( mkexpr(taT), unop(Iop_32to8, mkexpr(rDt)) );
+        }
+
+     } else {
+        /* Load */
+        vassert(bL == 1);
+
+        /* generate the transfer */
+        if (bB == 0) { // word load
+           putIReg( rD, loadLE(Ity_I32, mkexpr(taT)),
+                    IRTemp_INVALID, Ijk_Boring );
+        } else { // byte load
+          vassert(bB == 1);
+           putIReg( rD, unop(Iop_8Uto32, loadLE(Ity_I8, mkexpr(taT))),
+                    IRTemp_INVALID, Ijk_Boring );
+        }
+
+        /* Update Rn if necessary. */
+        switch (summary & 0x0F) {
+           case 2: case 3:
+              // should be assured by logic above:
+              if (bL == 1)
+                 vassert(rD != rN); /* since we just wrote rD */
+              putIReg( rN, mkexpr(eaT), IRTemp_INVALID, Ijk_Boring );
+              break;
+        }
+     }
+     switch (summary & 0x0F) {
+        case 1:  DIP("%sr%s%s r%u, %s\n",
+                     bL == 0 ? "st" : "ld",
+                     bB == 0 ? "" : "b", nCC(INSN_COND), rD, dis_buf);
+                 break;
+        case 2:  DIP("%sr%s%s r%u, %s! (at-EA-then-Rn=EA)\n",
+                     bL == 0 ? "st" : "ld",
+                     bB == 0 ? "" : "b", nCC(INSN_COND), rD, dis_buf);
+                 break;
+        case 3:  DIP("%sr%s%s r%u, %s! (at-Rn-then-Rn=EA)\n",
+                     bL == 0 ? "st" : "ld",
+                     bB == 0 ? "" : "b", nCC(INSN_COND), rD, dis_buf);
+                 break;
+        default: vassert(0);
+     }
+
+     /* XXX deal with alignment constraints */
+
+     goto decode_success;
+
+     /* Complications:
+
+        For all loads: if the Amode specifies base register
+        writeback, and the same register is specified for Rd and Rn,
+        the results are UNPREDICTABLE.
+
+        For all loads and stores: if R15 is written, branch to
+        that address afterwards.
+
+        STRB: straightforward
+        LDRB: loaded data is zero extended
+        STR:  lowest 2 bits of address are ignored
+        LDR:  if the lowest 2 bits of the address are nonzero
+              then the loaded value is rotated right by 8 * the lowest 2 bits
+     */
+   }
+
+  after_load_store_ubyte_or_word:
+
+   /* --------------------- Load/store (sbyte & hword) -------- */
+   // LDRH LDRSH STRH LDRSB
+   /*                 31   27   23   19 15 11   7    3     # highest bit
+                        28   24   20 16 12    8    4    0
+      A5-36   1 | 16  cond 0001 U10L Rn Rd im4h 1SH1 im4l
+      A5-38   1 | 32  cond 0001 U00L Rn Rd 0000 1SH1 Rm
+      A5-40   2 | 16  cond 0001 U11L Rn Rd im4h 1SH1 im4l
+      A5-42   2 | 32  cond 0001 U01L Rn Rd 0000 1SH1 Rm
+      A5-44   3 | 16  cond 0000 U10L Rn Rd im4h 1SH1 im4l
+      A5-46   3 | 32  cond 0000 U00L Rn Rd 0000 1SH1 Rm
    */
-   case 0x6: case 0x7:  // LOAD/STORE reg offset
-      if ((opc2 & 0x1) == 0x1) goto decode_failure; // Undefined - ARM ARM A3-2
-
-  case 0x4: case 0x5:  // LOAD/STORE imm offset
-     if (!dis_loadstore_w_ub(theInstr)) { goto decode_failure; }
-     break;
-     
-   /* 
-      Load/Store multiple 
+   /* case coding:
+             1   at-ea               (access at ea)
+             2   at-ea-then-upd      (access at ea, then Rn = ea)
+             3   at-Rn-then-upd      (access at Rn, then Rn = ea)
+      ea coding
+             16  Rn +/- imm8
+             32  Rn +/- Rm
    */
-   case 0x8: case 0x9:
-      if (!dis_loadstore_mult(theInstr)) { goto decode_failure; }
-      break;
-      
-      
+   /* Quickly skip over all of this for hopefully most instructions */
+   if ((INSN(27,24) & BITS4(1,1,1,0)) != BITS4(0,0,0,0))
+      goto after_load_store_sbyte_or_hword;
+
+   /* Check the "1SH1" thing. */
+   if ((INSN(7,4) & BITS4(1,0,0,1)) != BITS4(1,0,0,1))
+      goto after_load_store_sbyte_or_hword;
+
+   summary = 0;
+
+   /**/ if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(1,0)) {
+      summary = 1 | 16;
+   }
+   else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(0,0)) {
+      summary = 1 | 32;
+   }
+   else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(1,1)) {
+      summary = 2 | 16;
+   }
+   else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,21) == BITS2(0,1)) {
+      summary = 2 | 32;
+   }
+   else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,21) == BITS2(1,0)) {
+      summary = 3 | 16;
+   }
+   else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,21) == BITS2(0,0)) {
+      summary = 3 | 32;
+   }
+   else goto after_load_store_sbyte_or_hword;
+
+   { UInt rN   = (insn >> 16) & 0xF; /* 19:16 */
+     UInt rD   = (insn >> 12) & 0xF; /* 15:12 */
+     UInt rM   = (insn >> 0)  & 0xF; /*  3:0  */
+     UInt bU   = (insn >> 23) & 1;   /* 23 U=1 offset+, U=0 offset- */
+     UInt bL   = (insn >> 20) & 1;   /* 20 L=1 load, L=0 store */
+     UInt bH   = (insn >> 5) & 1;    /* H=1 halfword, H=0 byte */
+     UInt bS   = (insn >> 6) & 1;    /* S=1 signed, S=0 unsigned */
+     UInt imm8 = ((insn >> 4) & 0xF0) | (insn & 0xF); /* 11:8, 3:0 */
+
+     /* Skip combinations that are either meaningless or already
+        handled by main word-or-unsigned-byte load-store
+        instructions. */
+     if (bS == 0 && bH == 0) /* "unsigned byte" */
+        goto after_load_store_sbyte_or_hword;
+     if (bS == 1 && bL == 0) /* "signed store" */
+        goto after_load_store_sbyte_or_hword;
+
+     /* Require 11:8 == 0 for Rn +/- Rm cases */
+     if ((summary & 32) != 0 && (imm8 & 0xF0) != 0)
+        goto after_load_store_sbyte_or_hword;
+
+     /* Skip some invalid cases, which would lead to two competing
+        updates to the same register, or which are otherwise
+        disallowed by the spec. */
+     switch (summary) {
+        case 1 | 16:
+           break;
+        case 1 | 32: 
+           if (rM == 15) goto after_load_store_sbyte_or_hword;
+           break;
+        case 2 | 16: case 3 | 16:
+           if (rN == 15) goto after_load_store_sbyte_or_hword;
+           if (bL == 1 && rN == rD) goto after_load_store_sbyte_or_hword;
+           break;
+        case 2 | 32: case 3 | 32:
+           if (rM == 15) goto after_load_store_sbyte_or_hword;
+           if (rN == 15) goto after_load_store_sbyte_or_hword;
+           if (rN == rM) goto after_load_store_sbyte_or_hword;
+           if (bL == 1 && rN == rD) goto after_load_store_sbyte_or_hword;
+           break;
+        default:
+           vassert(0);
+     }
+
+     /* Now, we can't do a conditional load or store, since that very
+        likely will generate an exception.  So we have to take a side
+        exit at this point if the condition is false. */
+     if (condT != IRTemp_INVALID) {
+        mk_skip_to_next_if_cond_is_false( condT );
+        condT = IRTemp_INVALID;
+     }
+     /* Ok, now we're unconditional.  Do the load or store. */
+
+     /* compute the effective address.  Bind it to a tmp since we
+        may need to use it twice. */
+     IRExpr* eaE = NULL;
+     switch (summary & 0xF0) {
+        case 16:
+           eaE = mk_EA_reg_plusminus_imm8( rN, bU, imm8, dis_buf );
+           break;
+        case 32:
+           eaE = mk_EA_reg_plusminus_reg( rN, bU, rM, dis_buf );
+           break;
+     }
+     vassert(eaE);
+     IRTemp eaT = newTemp(Ity_I32);
+     assign(eaT, eaE);
+
+     /* get the old Rn value */
+     IRTemp rnT = newTemp(Ity_I32);
+     assign(rnT, getIReg(rN));
+
+     /* decide on the transfer address */
+     IRTemp taT = IRTemp_INVALID;
+     switch (summary & 0x0F) {
+        case 1: case 2: taT = eaT; break;
+        case 3:         taT = rnT; break;
+     }
+     vassert(taT != IRTemp_INVALID);
+
+     /* halfword store  H 1  L 0  S 0
+        uhalf load      H 1  L 1  S 0
+        shalf load      H 1  L 1  S 1
+        sbyte load      H 0  L 1  S 1
+     */
+     HChar* name = NULL;
+     /* generate the transfer */
+     /**/ if (bH == 1 && bL == 0 && bS == 0) { // halfword store
+        storeLE( mkexpr(taT), unop(Iop_32to16, getIReg(rD)) );
+        name = "strh";
+     }
+     else if (bH == 1 && bL == 1 && bS == 0) { // uhalf load
+        putIReg( rD, unop(Iop_16Uto32, loadLE(Ity_I16, mkexpr(taT))),
+                 IRTemp_INVALID, Ijk_Boring );
+        name = "ldrh";
+     }
+     else if (bH == 1 && bL == 1 && bS == 1) { // shalf load
+        putIReg( rD, unop(Iop_16Sto32, loadLE(Ity_I16, mkexpr(taT))),
+                 IRTemp_INVALID, Ijk_Boring );
+        name = "ldrsh";
+     }
+     else if (bH == 0 && bL == 1 && bS == 1) { // sbyte load
+        putIReg( rD, unop(Iop_8Sto32, loadLE(Ity_I8, mkexpr(taT))),
+                 IRTemp_INVALID, Ijk_Boring );
+        name = "ldrsb";
+     }
+     else
+        vassert(0); // should be assured by logic above
+
+     /* Update Rn if necessary. */
+     switch (summary & 0x0F) {
+        case 2: case 3:
+           // should be assured by logic above:
+           if (bL == 1)
+              vassert(rD != rN); /* since we just wrote rD */
+           putIReg( rN, mkexpr(eaT), IRTemp_INVALID, Ijk_Boring );
+           break;
+     }
+
+     switch (summary & 0x0F) {
+        case 1:  DIP("%s%s r%u, %s\n", name, nCC(INSN_COND), rD, dis_buf);
+                 break;
+        case 2:  DIP("%s%s r%u, %s! (at-EA-then-Rn=EA)\n",
+                     name, nCC(INSN_COND), rD, dis_buf);
+                 break;
+        case 3:  DIP("%s%s r%u, %s! (at-Rn-then-Rn=EA)\n",
+                     name, nCC(INSN_COND), rD, dis_buf);
+                 break;
+        default: vassert(0);
+     }
+
+     /* XXX deal with alignment constraints */
+
+     goto decode_success;
+
+     /* Complications:
+
+        For all loads: if the Amode specifies base register
+        writeback, and the same register is specified for Rd and Rn,
+        the results are UNPREDICTABLE.
+
+        For all loads and stores: if R15 is written, branch to
+        that address afterwards.
+
+        Misaligned halfword stores => Unpredictable
+        Misaligned halfword loads  => Unpredictable
+     */
+   }
+
+  after_load_store_sbyte_or_hword:
+
+   /* --------------------- Load/store multiple -------------- */
+   // LD/STMIA LD/STMIB LD/STMDA LD/STMDB
+   // Remarkably complex and difficult to get right
+   // match 27:20 as 100XX0WL
+   if (BITS8(1,0,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,1,0,0))) {
+      // A5-50 LD/STMIA  cond 1000 10WL Rn RegList
+      // A5-51 LD/STMIB  cond 1001 10WL Rn RegList
+      // A5-53 LD/STMDA  cond 1000 00WL Rn RegList
+      // A5-53 LD/STMDB  cond 1001 00WL Rn RegList
+      //                   28   24   20 16       0
+
+      Int  i, r, m, nRegs;
+
+      UInt bINC    = (insn >> 23) & 1;
+      UInt bBEFORE = (insn >> 24) & 1;
+
+      UInt bL      = (insn >> 20) & 1;  /* load=1, store=0 */
+      UInt bW      = (insn >> 21) & 1;  /* Rn wback=1, no wback=0 */
+      UInt rN      = (insn >> 16) & 0xF;
+      UInt regList = insn & 0xFFFF;
+      /* Skip some invalid cases, which would lead to two competing
+         updates to the same register, or which are otherwise
+         disallowed by the spec.  Note the test above has required
+         that S == 0, since that looks like a kernel-mode only thing.
+         Done by forcing the real pattern, viz 100XXSWL to actually be
+         100XX0WL. */
+      if (rN == 15) goto after_load_store_multiple;
+      // reglist can't be empty
+      if (regList == 0) goto after_load_store_multiple;
+      // if requested to writeback Rn, and this is a load instruction,
+      // then Rn can't appear in RegList, since we'd have two competing
+      // new values for Rn.  We do however accept this case for store
+      // instructions.
+      if (bW == 1 && bL == 1 && ((1 << rN) & regList) > 0)
+         goto after_load_store_multiple;
+
+      /* Now, we can't do a conditional load or store, since that very
+         likely will generate an exception.  So we have to take a side
+         exit at this point if the condition is false. */
+      if (condT != IRTemp_INVALID) {
+         mk_skip_to_next_if_cond_is_false( condT );
+         condT = IRTemp_INVALID;
+      }
+      /* Ok, now we're unconditional.  Do the load or store. */
+
+      /* Get hold of the old Rn value.  We might need to write its
+         value to memory during a store, and if it's also the
+         writeback register then we need to get its value now.  We
+         can't treat it exactly like the other registers we're going
+         to transfer, because for xxMDA and xxMDB writeback forms, the
+         generated IR updates Rn in the guest state before any
+         transfers take place.  We have to do this as per comments
+         below, in order that if Rn is the stack pointer then it
+         always has a value is below or equal to any of the transfer
+         addresses.  Ick. */
+      IRTemp oldRnT = newTemp(Ity_I32);
+      assign(oldRnT, getIReg(rN));
+
+      IRTemp anchorT = newTemp(Ity_I32);
+      assign(anchorT, binop(Iop_And32, mkexpr(oldRnT), mkU32(~3U)));
+
+      IROp opADDorSUB = bINC ? Iop_Add32 : Iop_Sub32;
+      // bINC == 1:  xxMIA, xxMIB
+      // bINC == 0:  xxMDA, xxMDB
+
+      // For xxMDA and xxMDB, update Rn first if necessary.  We have
+      // to do this first so that, for the common idiom of the transfers
+      // faulting because we're pushing stuff onto a stack and the stack
+      // is growing down onto allocate-on-fault pages (as Valgrind simulates),
+      // we need to have the SP up-to-date "covering" (pointing below) the
+      // transfer area.  For the same reason, if we are doing xxMIA or xxMIB,
+      // do the transfer first, and then update rN afterwards.
+      nRegs = 0;
+      for (i = 0; i < 16; i++) {
+        if ((regList & (1 << i)) != 0)
+            nRegs++;
+      }
+      if (bW == 1 && !bINC) {
+         putIReg( rN, binop(opADDorSUB, mkexpr(oldRnT), mkU32(4*nRegs)),
+                  IRTemp_INVALID, Ijk_Boring );
+      }
+
+      // Make up a list of the registers to transfer, and their offsets
+      // in memory relative to the anchor.  If the base reg (Rn) is part
+      // of the transfer, then do it last for a load and first for a store.
+      UInt xReg[16], xOff[16];
+      Int  nX = 0;
+      m = 0;
+      for (i = 0; i < 16; i++) {
+         r = bINC ? i : (15-i);
+         if (0 == (regList & (1<<r)))
+            continue;
+         if (bBEFORE)
+            m++;
+         /* paranoia: check we aren't transferring the writeback
+            register during a load. Should be assured by decode-point
+            check above. */
+         if (bW == 1 && bL == 1)
+            vassert(r != rN);
+
+         xOff[nX] = 4 * m;
+         xReg[nX] = r;
+         nX++;
+
+         if (!bBEFORE)
+            m++;
+      }
+      vassert(m == nRegs);
+      vassert(nX == nRegs);
+      vassert(nX <= 16);
+
+      if (bW == 0 && (regList & (1<<rN)) != 0) {
+         /* Non-writeback, and basereg is to be transferred.  Do its
+            transfer last for a load and first for a store.  Requires
+            reordering xOff/xReg. */
+         if (0) {
+            vex_printf("\nREG_LIST_PRE: (rN=%d)\n", rN);
+            for (i = 0; i < nX; i++)
+               vex_printf("reg %d   off %d\n", xReg[i], xOff[i]);
+            vex_printf("\n");
+         }
+
+         vassert(nX > 0);
+         for (i = 0; i < nX; i++) {
+            if (xReg[i] == rN)
+                break;
+         }
+         vassert(i < nX); /* else we didn't find it! */
+         UInt tReg = xReg[i];
+         UInt tOff = xOff[i];
+         if (bL == 1) {
+            /* load; make this transfer happen last */
+            if (i < nX-1) {
+               for (m = i+1; m < nX; m++) {
+                  xReg[m-1] = xReg[m];
+                  xOff[m-1] = xOff[m];
+               }
+               vassert(m == nX);
+               xReg[m-1] = tReg;
+               xOff[m-1] = tOff;
+            }
+         } else {
+            /* store; make this transfer happen first */
+            if (i > 0) {
+               for (m = i-1; m >= 0; m--) {
+                  xReg[m+1] = xReg[m];
+                  xOff[m+1] = xOff[m];
+               }
+               vassert(m == -1);
+               xReg[0] = tReg;
+               xOff[0] = tOff;
+            }
+         }
+
+         if (0) {
+            vex_printf("REG_LIST_POST:\n");
+            for (i = 0; i < nX; i++)
+               vex_printf("reg %d   off %d\n", xReg[i], xOff[i]);
+            vex_printf("\n");
+         }
+      }
+
+      /* Actually generate the transfers */
+      for (i = 0; i < nX; i++) {
+         r = xReg[i];
+         if (bL == 1) {
+            putIReg( r, loadLE(Ity_I32,
+                               binop(opADDorSUB, mkexpr(anchorT),
+                                                 mkU32(xOff[i]))),
+                     IRTemp_INVALID, Ijk_Ret );
+         } else {
+            /* if we're storing Rn, make sure we use the correct
+               value, as per extensive comments above */
+            storeLE( binop(opADDorSUB, mkexpr(anchorT), mkU32(xOff[i])),
+                     r == rN ? mkexpr(oldRnT) : getIReg(r) );
+         }
+      }
+
+      // If we are doing xxMIA or xxMIB,
+      // do the transfer first, and then update rN afterwards.
+      if (bW == 1 && bINC) {
+         putIReg( rN, binop(opADDorSUB, mkexpr(oldRnT), mkU32(4*nRegs)),
+                  IRTemp_INVALID, Ijk_Boring );
+      }
+
+      //if (vex_traceflags & VEX_TRACE_FE) {
+      //}
+      DIP("%sm%c%c%s r%u%s, {0x%04x}\n",
+          bL == 1 ? "ld" : "st", bINC ? 'i' : 'd', bBEFORE ? 'b' : 'a',
+          nCC(INSN_COND),
+          rN, bW ? "!" : "", regList);
+
+      goto decode_success;
+   }
+
+  after_load_store_multiple:
+
+   /* --------------------- Control flow --------------------- */
+   // B, BL (Branch, or Branch-and-Link, to immediate offset)
+   //
+   if (BITS8(1,0,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))) {
+      UInt link   = (insn >> 24) & 1;
+      UInt uimm24 = insn & ((1<<24)-1);
+      Int  simm24 = (Int)uimm24;
+      UInt dst    = guest_R15_curr_instr + 8 + (((simm24 << 8) >> 8) << 2);
+      IRJumpKind jk = link ? Ijk_Call : Ijk_Boring;
+      if (link) {
+         putIReg(14, mkU32(guest_R15_curr_instr + 4), condT, Ijk_Boring);
+      }
+      if (condT == IRTemp_INVALID) {
+         /* unconditional transfer to 'dst'.  See if we can simply
+            continue tracing at the destination. */
+         if (resteerOkFn( callback_opaque, (Addr64)dst )) {
+            /* yes */
+            dres.whatNext   = Dis_Resteer;
+            dres.continueAt = (Addr64)dst;
+         } else {
+            /* no; terminate the SB at this point. */
+            irsb->next     = mkU32(dst);
+            irsb->jumpkind = jk;
+            dres.whatNext  = Dis_StopHere;
+         }
+         DIP("b%s 0x%x\n", link ? "l" : "", dst);
+      } else {
+         /* conditional transfer to 'dst' */
+         stmt( IRStmt_Exit( unop(Iop_32to1, mkexpr(condT)),
+                            jk, IRConst_U32(dst) ));
+         irsb->next     = mkU32(guest_R15_curr_instr + 4);
+         irsb->jumpkind = jk;
+         dres.whatNext  = Dis_StopHere;
+         DIP("b%s%s 0x%x\n", link ? "l" : "", nCC(INSN_COND), dst);
+      }
+      goto decode_success;
+   }
+
+   // BX, BLX (Branch, or Branch-and-Link, to a register)
+   //
+   if (INSN(27,20) == BITS8(0,0,0,1,0,0,1,0)
+       && INSN(19,12) == BITS8(1,1,1,1,1,1,1,1)
+       && (INSN(11,4) == BITS8(1,1,1,1,0,0,1,1)
+           || INSN(11,4) == BITS8(1,1,1,1,0,0,0,1))) {
+      IRExpr* dst;
+      UInt    link = (INSN(11,4) >> 1) & 1;
+      UInt    rM   = INSN(3,0);
+      // we don't decode the case (link && rM == 15), as that's
+      // Unpredictable.
+      if (!(link && rM == 15)) {
+         if (condT != IRTemp_INVALID) {
+            mk_skip_to_next_if_cond_is_false( condT );
+         }
+         // AL after here
+         // pretend no Thumb, hence ~3 instead of ~1
+         dst = binop(Iop_And32, getIReg(rM), mkU32(~3));
+         if (link) {
+            putIReg( 14, mkU32(guest_R15_curr_instr + 4),
+                     IRTemp_INVALID/*because AL*/, Ijk_Boring );
+         }
+         irsb->next     = dst;
+         irsb->jumpkind = link ? Ijk_Call
+                               : (rM == 14 ? Ijk_Ret : Ijk_Boring);
+         dres.whatNext  = Dis_StopHere;
+         if (condT == IRTemp_INVALID) {
+            DIP("b%sx r%u\n", link ? "l" : "", rM);
+         } else {
+            DIP("b%sx%s r%u\n", link ? "l" : "", nCC(INSN_COND), rM);
+         }
+         goto decode_success;
+      }
+      /* else: (link && rM == 15): just fall through */
+   }
+
+   /* --------------------- Clz --------------------- */
+   // CLZ
+   if (INSN(27,20) == BITS8(0,0,0,1,0,1,1,0)
+       && INSN(19,16) == BITS4(1,1,1,1)
+       && INSN(11,4) == BITS8(1,1,1,1,0,0,0,1)) {
+      UInt rD = INSN(15,12);
+      UInt rM = INSN(3,0);
+      IRTemp arg = newTemp(Ity_I32);
+      IRTemp res = newTemp(Ity_I32);
+      assign(arg, getIReg(rM));
+      assign(res, IRExpr_Mux0X(
+                     unop(Iop_1Uto8,binop(Iop_CmpEQ32, mkexpr(arg),
+                                                       mkU32(0))),
+                     unop(Iop_Clz32, mkexpr(arg)),
+                     mkU32(32)
+            ));
+      putIReg(rD, mkexpr(res), condT, Ijk_Boring);
+      DIP("clz%s r%u, r%u\n", nCC(INSN_COND), rD, rM);
+      goto decode_success;
+   }
+
+   /* --------------------- Mul etc --------------------- */
+   // MUL
+   if (BITS8(0,0,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,0))
+       && INSN(15,12) == BITS4(0,0,0,0)
+       && INSN(7,4) == BITS4(1,0,0,1)) {
+      UInt bitS = (insn >> 20) & 1; /* 20:20 */
+      UInt rD = INSN(19,16);
+      UInt rS = INSN(11,8);
+      UInt rM = INSN(3,0);
+      if (rD == 15 || rM == 15 || rS == 15) {
+         /* Unpredictable; don't decode; fall through */
+      } else {
+         IRTemp argL = newTemp(Ity_I32);
+         IRTemp argR = newTemp(Ity_I32);
+         IRTemp res  = newTemp(Ity_I32);
+         IRTemp oldC = IRTemp_INVALID;
+         IRTemp oldV = IRTemp_INVALID;
+         assign( argL, getIReg(rM));
+         assign( argR, getIReg(rS));
+         assign( res, binop(Iop_Mul32, mkexpr(argL), mkexpr(argR)) );
+         if (bitS) {
+            oldC = newTemp(Ity_I32);
+            assign(oldC, mk_armg_calculate_flag_c());
+            oldV = newTemp(Ity_I32);
+            assign(oldV, mk_armg_calculate_flag_v());
+         }
+         // now update guest state
+         putIReg( rD, mkexpr(res), condT, Ijk_Boring );
+         if (bitS) {
+            IRTemp pair = newTemp(Ity_I32);
+            assign( pair, binop(Iop_Or32,
+                                binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
+                                mkexpr(oldV)) );
+            setFlags_D1_ND( ARMG_CC_OP_MUL, res, pair, condT );
+         }
+         DIP("mul%c%s r%u, r%u, r%u\n",
+             bitS ? 's' : ' ', nCC(INSN_COND), rD, rM, rS);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   // MLA, MLS
+   if (BITS8(0,0,0,0,0,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
+       && INSN(7,4) == BITS4(1,0,0,1)) {
+      UInt bitS  = (insn >> 20) & 1; /* 20:20 */
+      UInt isMLS = (insn >> 22) & 1; /* 22:22 */
+      UInt rD = INSN(19,16);
+      UInt rN = INSN(15,12);
+      UInt rS = INSN(11,8);
+      UInt rM = INSN(3,0);
+      if (bitS == 1 && isMLS == 1) {
+         /* This isn't allowed (MLS that sets flags).  don't decode;
+            fall through */
+      }
+      else
+      if (rD == 15 || rM == 15 || rS == 15 || rN == 15) {
+         /* Unpredictable; don't decode; fall through */
+      } else {
+         IRTemp argL = newTemp(Ity_I32);
+         IRTemp argR = newTemp(Ity_I32);
+         IRTemp argP = newTemp(Ity_I32);
+         IRTemp res  = newTemp(Ity_I32);
+         IRTemp oldC = IRTemp_INVALID;
+         IRTemp oldV = IRTemp_INVALID;
+         assign( argL, getIReg(rM));
+         assign( argR, getIReg(rS));
+         assign( argP, getIReg(rN));
+         assign( res, binop(isMLS ? Iop_Sub32 : Iop_Add32,
+                            mkexpr(argP),
+                            binop(Iop_Mul32, mkexpr(argL), mkexpr(argR)) ));
+         if (bitS) {
+            vassert(!isMLS); // guaranteed above
+            oldC = newTemp(Ity_I32);
+            assign(oldC, mk_armg_calculate_flag_c());
+            oldV = newTemp(Ity_I32);
+            assign(oldV, mk_armg_calculate_flag_v());
+         }
+         // now update guest state
+         putIReg( rD, mkexpr(res), condT, Ijk_Boring );
+         if (bitS) {
+            IRTemp pair = newTemp(Ity_I32);
+            assign( pair, binop(Iop_Or32,
+                                binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
+                                mkexpr(oldV)) );
+            setFlags_D1_ND( ARMG_CC_OP_MUL, res, pair, condT );
+         }
+         DIP("ml%c%c%s r%u, r%u, r%u, r%u\n",
+             isMLS ? 's' : 'a', bitS ? 's' : ' ', nCC(INSN_COND), rD, rM, rS, rN);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   // SMULL, UMULL
+   if (BITS8(0,0,0,0,1,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
+       && INSN(7,4) == BITS4(1,0,0,1)) {
+      UInt bitS = (insn >> 20) & 1; /* 20:20 */
+      UInt rDhi = INSN(19,16);
+      UInt rDlo = INSN(15,12);
+      UInt rS   = INSN(11,8);
+      UInt rM   = INSN(3,0);
+      UInt isS  = (INSN(27,20) >> 2) & 1; /* 22:22 */
+      if (rDhi == 15 || rDlo == 15 || rM == 15 || rS == 15 || rDhi == rDlo)  {
+         /* Unpredictable; don't decode; fall through */
+      } else {
+         IRTemp argL  = newTemp(Ity_I32);
+         IRTemp argR  = newTemp(Ity_I32);
+         IRTemp res   = newTemp(Ity_I64);
+         IRTemp resHi = newTemp(Ity_I32);
+         IRTemp resLo = newTemp(Ity_I32);
+         IRTemp oldC  = IRTemp_INVALID;
+         IRTemp oldV  = IRTemp_INVALID;
+         IROp   mulOp = isS ? Iop_MullS32 : Iop_MullU32;
+         assign( argL, getIReg(rM));
+         assign( argR, getIReg(rS));
+         assign( res, binop(mulOp, mkexpr(argL), mkexpr(argR)) );
+         assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
+         assign( resLo, unop(Iop_64to32, mkexpr(res)) );
+         if (bitS) {
+            oldC = newTemp(Ity_I32);
+            assign(oldC, mk_armg_calculate_flag_c());
+            oldV = newTemp(Ity_I32);
+            assign(oldV, mk_armg_calculate_flag_v());
+         }
+         // now update guest state
+         putIReg( rDhi, mkexpr(resHi), condT, Ijk_Boring );
+         putIReg( rDlo, mkexpr(resLo), condT, Ijk_Boring );
+         if (bitS) {
+            IRTemp pair = newTemp(Ity_I32);
+            assign( pair, binop(Iop_Or32,
+                                binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
+                                mkexpr(oldV)) );
+            setFlags_D1_D2_ND( ARMG_CC_OP_MULL, resLo, resHi, pair, condT );
+         }
+         DIP("%cmull%c%s r%u, r%u, r%u, r%u\n",
+             isS ? 's' : 'u', bitS ? 's' : ' ',
+             nCC(INSN_COND), rDlo, rDhi, rM, rS);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   // SMLAL, UMLAL
+   if (BITS8(0,0,0,0,1,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
+       && INSN(7,4) == BITS4(1,0,0,1)) {
+      UInt bitS = (insn >> 20) & 1; /* 20:20 */
+      UInt rDhi = INSN(19,16);
+      UInt rDlo = INSN(15,12);
+      UInt rS   = INSN(11,8);
+      UInt rM   = INSN(3,0);
+      UInt isS  = (INSN(27,20) >> 2) & 1; /* 22:22 */
+      if (rDhi == 15 || rDlo == 15 || rM == 15 || rS == 15 || rDhi == rDlo)  {
+         /* Unpredictable; don't decode; fall through */
+      } else {
+         IRTemp argL  = newTemp(Ity_I32);
+         IRTemp argR  = newTemp(Ity_I32);
+         IRTemp old   = newTemp(Ity_I64);
+         IRTemp res   = newTemp(Ity_I64);
+         IRTemp resHi = newTemp(Ity_I32);
+         IRTemp resLo = newTemp(Ity_I32);
+         IRTemp oldC  = IRTemp_INVALID;
+         IRTemp oldV  = IRTemp_INVALID;
+         IROp   mulOp = isS ? Iop_MullS32 : Iop_MullU32;
+         assign( argL, getIReg(rM));
+         assign( argR, getIReg(rS));
+         assign( old, binop(Iop_32HLto64, getIReg(rDhi), getIReg(rDlo)) );
+         assign( res, binop(Iop_Add64,
+                            mkexpr(old),
+                            binop(mulOp, mkexpr(argL), mkexpr(argR))) );
+         assign( resHi, unop(Iop_64HIto32, mkexpr(res)) );
+         assign( resLo, unop(Iop_64to32, mkexpr(res)) );
+         if (bitS) {
+            oldC = newTemp(Ity_I32);
+            assign(oldC, mk_armg_calculate_flag_c());
+            oldV = newTemp(Ity_I32);
+            assign(oldV, mk_armg_calculate_flag_v());
+         }
+         // now update guest state
+         putIReg( rDhi, mkexpr(resHi), condT, Ijk_Boring );
+         putIReg( rDlo, mkexpr(resLo), condT, Ijk_Boring );
+         if (bitS) {
+            IRTemp pair = newTemp(Ity_I32);
+            assign( pair, binop(Iop_Or32,
+                                binop(Iop_Shl32, mkexpr(oldC), mkU8(1)),
+                                mkexpr(oldV)) );
+            setFlags_D1_D2_ND( ARMG_CC_OP_MULL, resLo, resHi, pair, condT );
+         }
+         DIP("%cmlal%c%s r%u, r%u, r%u, r%u\n",
+             isS ? 's' : 'u', bitS ? 's' : ' ', nCC(INSN_COND),
+             rDlo, rDhi, rM, rS);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   /* --------------------- Msr etc --------------------- */
+
+   // MSR (immediate form, flags only)
+   if (BITS8(0,0,1,1,0,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
+       && INSN(15,12) == BITS4(1,1,1,1)) {
+      UInt bitR = (insn >> 22) & 1;
+      if (bitR == 0 && INSN(19,16) == BITS4(1,0,0,0)) {
+         UInt   imm = (INSN(11,0) >> 0) & 0xFF;
+         UInt   rot = 2 * ((INSN(11,0) >> 8) & 0xF);
+         IRTemp immT = newTemp(Ity_I32);
+         vassert(rot <= 30);
+         imm = ROR32(imm, rot);
+         imm &= 0xFF000000;
+         imm &= (ARMG_CC_MASK_N | ARMG_CC_MASK_Z 
+                 | ARMG_CC_MASK_V | ARMG_CC_MASK_C);
+         assign( immT, mkU32(imm & 0xF0000000) );
+         setFlags_D1(ARMG_CC_OP_COPY, immT, condT);
+         DIP("msr%s cpsr_f, #0x%08x\n", nCC(INSN_COND), imm);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   // MRS
+   if (BITS8(0,0,0,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
+       && INSN(19,16) == BITS4(1,1,1,1)
+       && INSN(11,0) == 0) {
+      UInt bitR = (insn >> 22) & 1;
+      UInt rD   = INSN(15,12);
+      if (bitR == 0 && rD != 15) {
+         IRTemp res = newTemp(Ity_I32);
+         assign( res, mk_armg_calculate_flags_nzcv() );
+         putIReg( rD, mkexpr(res), condT, Ijk_Boring );
+         DIP("mrs%s r%u, cpsr\n", nCC(INSN_COND), rD);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   /* --------------------- Svc --------------------- */
+   if (BITS8(1,1,1,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,0,0))) {
+      UInt imm24 = (insn >> 0) & 0xFFFFFF;
+      if (imm24 == 0) {
+         /* A syscall.  We can't do this conditionally, hence: */
+         if (condT != IRTemp_INVALID) {
+            mk_skip_to_next_if_cond_is_false( condT );
+         }
+         // AL after here
+         irsb->next     = mkU32( guest_R15_curr_instr + 4 );
+         irsb->jumpkind = Ijk_Sys_syscall;
+         dres.whatNext  = Dis_StopHere;
+         DIP("svc%s #0x%08x\n", nCC(INSN_COND), imm24);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   /* ------------------------ swp ------------------------ */
+
+   // SWP, SWPB
+   if (BITS8(0,0,0,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
+       && BITS4(0,0,0,0) == INSN(11,8)
+       && BITS4(1,0,0,1) == INSN(7,4)) {
+      UInt   rN   = INSN(19,16);
+      UInt   rD   = INSN(15,12);
+      UInt   rM   = INSN(3,0);
+      IRTemp tRn  = newTemp(Ity_I32);
+      IRTemp tNew = newTemp(Ity_I32);
+      IRTemp tOld = IRTemp_INVALID;
+      IRTemp tSC1 = newTemp(Ity_I1);
+      UInt   isB  = (insn >> 22) & 1;
+
+      if (rD == 15 || rN == 15 || rM == 15 || rN == rM || rN == rD) {
+         /* undecodable; fall through */
+      } else {
+         /* make unconditional */
+         if (condT != IRTemp_INVALID) {
+            mk_skip_to_next_if_cond_is_false( condT );
+            condT = IRTemp_INVALID;
+         }
+         /* Ok, now we're unconditional.  Generate a LL-SC loop. */
+         assign(tRn, getIReg(rN));
+         assign(tNew, getIReg(rM));
+         if (isB) {
+            /* swpb */
+            tOld = newTemp(Ity_I8);
+            stmt( IRStmt_LLSC(Iend_LE, tOld, mkexpr(tRn),
+                              NULL/*=>isLL*/) );
+            stmt( IRStmt_LLSC(Iend_LE, tSC1, mkexpr(tRn),
+                              unop(Iop_32to8, mkexpr(tNew))) );
+         } else {
+            /* swp */
+            tOld = newTemp(Ity_I32);
+            stmt( IRStmt_LLSC(Iend_LE, tOld, mkexpr(tRn),
+                              NULL/*=>isLL*/) );
+            stmt( IRStmt_LLSC(Iend_LE, tSC1, mkexpr(tRn),
+                              mkexpr(tNew)) );
+         }
+         stmt( IRStmt_Exit(unop(Iop_Not1, mkexpr(tSC1)),
+                           /*Ijk_NoRedir*/Ijk_Boring,
+                           IRConst_U32(guest_R15_curr_instr)) );
+         putIReg(rD, isB ? unop(Iop_8Uto32, mkexpr(tOld)) : mkexpr(tOld),
+                     IRTemp_INVALID, Ijk_Boring);
+         DIP("swp%s%s r%u, r%u, [r%u]\n",
+             isB ? "b" : "", nCC(INSN_COND), rD, rM, rN);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   /* ----------------------------------------------------------- */
+   /* -- VFP instructions -- double precision (mostly)         -- */
+   /* ----------------------------------------------------------- */
+
+   /* --------------------- fldmx, fstmx --------------------- */
    /*
-     Branch, Branch and Link
+                                 31   27   23   19 15 11   7   0
+                                         P U WL
+      C4-100, C5-26  1  FSTMX    cond 1100 1000 Rn Dd 1011 offset
+      C4-100, C5-28  2  FSTMIAX  cond 1100 1010 Rn Dd 1011 offset
+      C4-100, C5-30  3  FSTMDBX  cond 1101 0010 Rn Dd 1011 offset
+
+      C4-42, C5-26   1  FLDMX    cond 1100 1001 Rn Dd 1011 offset
+      C4-42, C5-28   2  FLDMIAX  cond 1100 1011 Rn Dd 1011 offset
+      C4-42, C5-30   3  FLDMDBX  cond 1101 0011 Rn Dd 1011 offset
+
+      Regs transferred: Dd .. D(d + (offset-3)/2)
+      offset must be odd, must not imply a reg > 15
+      IA/DB: Rn is changed by (4 + 8 x # regs transferred)
+
+      case coding:
+         1  at-Rn   (access at Rn)
+         2  ia-Rn   (access at Rn, then Rn += 4+8n)
+         3  db-Rn   (Rn -= 4+8n,   then access at Rn)
    */
-   case 0xA: case 0xB:  // B, BL
-      // B(L): L=1 => return address stored in link register (R14)
-      dis_branch(theInstr);
-      whatNext = Dis_StopHere;
-      break;
-      
-      
+   if (BITS8(1,1,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,1,0,0))
+       && INSN(11,8) == BITS4(1,0,1,1)) {
+      UInt bP     = (insn >> 24) & 1;
+      UInt bU     = (insn >> 23) & 1;
+      UInt bW     = (insn >> 21) & 1;
+      UInt bL     = (insn >> 20) & 1;
+      UInt offset = (insn >> 0) & 0xFF;
+      UInt rN     = INSN(19,16);
+      UInt dD     = INSN(15,12);
+      UInt nRegs  = (offset - 1) / 2;
+      Int  i;
+
+      /**/ if (bP == 0 && bU == 1 && bW == 0) {
+         vassert(0); //ATC
+         summary = 1;
+      }
+      else if (bP == 0 && bU == 1 && bW == 1) {
+         summary = 2;
+      }
+      else if (bP == 1 && bU == 0 && bW == 1) {
+         summary = 3;
+      }
+      else goto after_vfp_fldmx_fstmx;
+
+      /* no writebacks to r15 allowed */
+      if (rN == 15 && (summary == 2 || summary == 3))
+         goto after_vfp_fldmx_fstmx;
+
+      /* offset must be odd, and specify at least one register */
+      if (0 == (offset & 1) || offset < 3)
+         goto after_vfp_fldmx_fstmx;
+
+      /* can't transfer regs after D15 */
+      if (dD + nRegs - 1 >= 16)
+         goto after_vfp_fldmx_fstmx;
+
+      /* Now, we can't do a conditional load or store, since that very
+         likely will generate an exception.  So we have to take a side
+         exit at this point if the condition is false. */
+      if (condT != IRTemp_INVALID) {
+         mk_skip_to_next_if_cond_is_false( condT );
+         condT = IRTemp_INVALID;
+      }
+      /* Ok, now we're unconditional.  Do the load or store. */
+
+      /* get the old Rn value */
+      IRTemp rnT = newTemp(Ity_I32);
+      assign(rnT, getIReg(rN));
+
+      /* make a new value for Rn, post-insn */
+      IRTemp rnTnew = IRTemp_INVALID;
+      if (summary == 2 || summary == 3) {
+         rnTnew = newTemp(Ity_I32);
+         assign(rnTnew, binop(summary == 2 ? Iop_Add32 : Iop_Sub32,
+                              mkexpr(rnT),
+                              mkU32(4 + 8 * nRegs)));
+      }
+
+      /* decide on the base transfer address */
+      IRTemp taT = newTemp(Ity_I32);
+      assign(taT,  summary == 3 ? mkexpr(rnTnew) : mkexpr(rnT));
+
+      /* update Rn if necessary -- in case 3, we're moving it down, so
+         update before any memory reference, in order to keep Memcheck
+         and V's stack-extending logic (on linux) happy */
+      if (summary == 3)
+         putIReg(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
+
+      /* generate the transfers */
+      for (i = 0; i < nRegs; i++) {
+         IRExpr* addr = binop(Iop_Add32, mkexpr(taT), mkU32(8*i));
+         if (bL) {
+            putDReg(dD + i, loadLE(Ity_F64, addr), IRTemp_INVALID);
+         } else {
+            storeLE(addr, getDReg(dD + i));
+         }
+      }
+
+      /* update Rn if necessary -- in case 2, we're moving it up, so
+         update after any memory reference, in order to keep Memcheck
+         and V's stack-extending logic (on linux) happy */
+      if (summary == 2)
+         putIReg(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
+
+      HChar* nm = bL==1 ? "ld" : "st";
+      switch (summary) {
+         case 1:  DIP("f%smx%s r%u, {d%u-d%u}\n", 
+                      nm, nCC(INSN_COND), rN, dD, dD + nRegs - 1);
+                  break;
+         case 2:  DIP("f%smiax%s r%u!, {d%u-d%u}\n", 
+                      nm, nCC(INSN_COND), rN, dD, dD + nRegs - 1);
+                  break;
+         case 3:  DIP("f%smdbx%s r%u!, {d%u-d%u}\n", 
+                      nm, nCC(INSN_COND), rN, dD, dD + nRegs - 1);
+                  break;
+         default: vassert(0);
+      }
+
+
+      goto decode_success;
+      /* FIXME alignment constraints? */
+   }
+
+  after_vfp_fldmx_fstmx:
+
+   /* --------------------- fldmd, fstmd --------------------- */
    /*
-     Co-processor instructions
+                                 31   27   23   19 15 11   7   0
+                                         P U WL
+      C4-96, C5-26   1  FSTMD    cond 1100 1000 Rn Dd 1011 offset
+      C4-96, C5-28   2  FSTMDIA  cond 1100 1010 Rn Dd 1011 offset
+      C4-96, C5-30   3  FSTMDDB  cond 1101 0010 Rn Dd 1011 offset
+
+      C4-38, C5-26   1  FLDMD    cond 1100 1001 Rn Dd 1011 offset
+      C4-38, C5-28   2  FLDMIAD  cond 1100 1011 Rn Dd 1011 offset
+      C4-38, C5-30   3  FLDMDBD  cond 1101 0011 Rn Dd 1011 offset
+
+      Regs transferred: Dd .. D(d + (offset-2)/2)
+      offset must be even, must not imply a reg > 15
+      IA/DB: Rn is changed by (8 x # regs transferred)
+
+      case coding:
+         1  at-Rn   (access at Rn)
+         2  ia-Rn   (access at Rn, then Rn += 8n)
+         3  db-Rn   (Rn -= 8n,     then access at Rn)
    */
-   case 0xC: case 0xD:  // co-pro load/store & double reg trxfrs
-      goto decode_failure;
-      
-   case 0xE:
-      if ((opc2 & 0x1) == 0x0) { // co-pro data processing
-         goto decode_failure;
-      } else {                   // co-pro register transfers
-         goto decode_failure;
+   if (BITS8(1,1,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,1,0,0))
+       && INSN(11,8) == BITS4(1,0,1,1)) {
+      UInt bP     = (insn >> 24) & 1;
+      UInt bU     = (insn >> 23) & 1;
+      UInt bW     = (insn >> 21) & 1;
+      UInt bL     = (insn >> 20) & 1;
+      UInt offset = (insn >> 0) & 0xFF;
+      UInt rN     = INSN(19,16);
+      UInt dD     = INSN(15,12);
+      UInt nRegs  = offset / 2;
+      Int  i;
+
+      /**/ if (bP == 0 && bU == 1 && bW == 0) {
+         vassert(0); //ATC
+         summary = 1;
+      }
+      else if (bP == 0 && bU == 1 && bW == 1) {
+         summary = 2;
+      }
+      else if (bP == 1 && bU == 0 && bW == 1) {
+         summary = 3;
+      }
+      else goto after_vfp_fldmd_fstmd;
+
+      /* no writebacks to r15 allowed */
+      if (rN == 15 && (summary == 2 || summary == 3))
+         goto after_vfp_fldmd_fstmd;
+
+      /* offset must be even, and specify at least one register */
+      if (1 == (offset & 1) || offset < 2)
+         goto after_vfp_fldmd_fstmd;
+
+      /* can't transfer regs after D15 */
+      if (dD + nRegs - 1 >= 16)
+         goto after_vfp_fldmd_fstmd;
+
+      /* Now, we can't do a conditional load or store, since that very
+         likely will generate an exception.  So we have to take a side
+         exit at this point if the condition is false. */
+      if (condT != IRTemp_INVALID) {
+         mk_skip_to_next_if_cond_is_false( condT );
+         condT = IRTemp_INVALID;
+      }
+      /* Ok, now we're unconditional.  Do the load or store. */
+
+      /* get the old Rn value */
+      IRTemp rnT = newTemp(Ity_I32);
+      assign(rnT, getIReg(rN));
+
+      /* make a new value for Rn, post-insn */
+      IRTemp rnTnew = IRTemp_INVALID;
+      if (summary == 2 || summary == 3) {
+         rnTnew = newTemp(Ity_I32);
+         assign(rnTnew, binop(summary == 2 ? Iop_Add32 : Iop_Sub32,
+                              mkexpr(rnT),
+                              mkU32(8 * nRegs)));
+      }
+
+      /* decide on the base transfer address */
+      IRTemp taT = newTemp(Ity_I32);
+      assign(taT, summary == 3 ? mkexpr(rnTnew) : mkexpr(rnT));
+
+      /* update Rn if necessary -- in case 3, we're moving it down, so
+         update before any memory reference, in order to keep Memcheck
+         and V's stack-extending logic (on linux) happy */
+      if (summary == 3)
+         putIReg(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
+
+      /* generate the transfers */
+      for (i = 0; i < nRegs; i++) {
+         IRExpr* addr = binop(Iop_Add32, mkexpr(taT), mkU32(8*i));
+         if (bL) {
+            putDReg(dD + i, loadLE(Ity_F64, addr), IRTemp_INVALID);
+         } else {
+            storeLE(addr, getDReg(dD + i));
+         }
+      }
+
+      /* update Rn if necessary -- in case 2, we're moving it up, so
+         update after any memory reference, in order to keep Memcheck
+         and V's stack-extending logic (on linux) happy */
+      if (summary == 2)
+         putIReg(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
+
+      HChar* nm = bL==1 ? "ld" : "st";
+      switch (summary) {
+         case 1:  DIP("f%smd%s r%u, {d%u-d%u}\n", 
+                      nm, nCC(INSN_COND), rN, dD, dD + nRegs - 1);
+                  break;
+         case 2:  DIP("f%smiad%s r%u!, {d%u-d%u}\n", 
+                      nm, nCC(INSN_COND), rN, dD, dD + nRegs - 1);
+                  break;
+         case 3:  DIP("f%smdbd%s r%u!, {d%u-d%u}\n", 
+                      nm, nCC(INSN_COND), rN, dD, dD + nRegs - 1);
+                  break;
+         default: vassert(0);
+      }
+
+      goto decode_success;
+      /* FIXME alignment constraints? */
+   }
+
+  after_vfp_fldmd_fstmd:
+
+   /* ------------------- fmrx, fmxr ------------------- */
+   if (BITS8(1,1,1,0,1,1,1,1) == INSN(27,20)
+       && BITS4(1,0,1,0) == INSN(11,8)
+       && BITS8(0,0,0,1,0,0,0,0) == (insn & 0xFF)) {
+      UInt rD  = INSN(15,12);
+      UInt reg = INSN(19,16);
+      if (reg == BITS4(0,0,0,1)) {
+         if (rD == 15) {
+            IRTemp nzcvT = newTemp(Ity_I32);
+            /* When rD is 15, we are copying the top 4 bits of FPSCR
+               into CPSR.  That is, set the flags thunk to COPY and
+               install FPSCR[31:28] as the value to copy. */
+            assign(nzcvT, binop(Iop_And32,
+                                IRExpr_Get(OFFB_FPSCR, Ity_I32),
+                                mkU32(0xF0000000)));
+            setFlags_D1(ARMG_CC_OP_COPY, nzcvT, condT);
+            DIP("fmstat%s\n", nCC(INSN_COND));
+         } else {
+            /* Otherwise, merely transfer FPSCR to r0 .. r14. */
+            putIReg(rD, IRExpr_Get(OFFB_FPSCR, Ity_I32), 
+                        condT, Ijk_Boring);
+            DIP("fmrx%s r%u, fpscr\n", nCC(INSN_COND), rD);
+         }
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   if (BITS8(1,1,1,0,1,1,1,0) == INSN(27,20)
+       && BITS4(1,0,1,0) == INSN(11,8)
+       && BITS8(0,0,0,1,0,0,0,0) == (insn & 0xFF)) {
+      UInt rD  = INSN(15,12);
+      UInt reg = INSN(19,16);
+      if (reg == BITS4(0,0,0,1)) {
+         putMiscReg32(OFFB_FPSCR, getIReg(rD), condT);
+         DIP("fmxr%s fpscr, r%u\n", nCC(INSN_COND), rD);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   /* --------------------- vmov --------------------- */
+   // VMOV dM, rD, rN
+   if (0x0C400B10 == (insn & 0x0FF00FF0)) {
+      UInt dM = INSN(3,0);
+      UInt rD = INSN(15,12); /* lo32 */
+      UInt rN = INSN(19,16); /* hi32 */
+      if (rD == 15 || rN == 15) {
+         /* fall through */
+      } else {
+         putDReg(dM,
+                 unop(Iop_ReinterpI64asF64,
+                      binop(Iop_32HLto64, getIReg(rN), getIReg(rD))),
+                 condT);
+         DIP("vmov%s d%u, r%u, r%u\n", nCC(INSN_COND), dM, rD, rN);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   // VMOV rD, rN, dM
+   if (0x0C500B10 == (insn & 0x0FF00FF0)) {
+      UInt dM = INSN(3,0);
+      UInt rD = INSN(15,12); /* lo32 */
+      UInt rN = INSN(19,16); /* hi32 */
+      if (rD == 15 || rN == 15 || rD == rN) {
+         /* fall through */
+      } else {
+         IRTemp i64 = newTemp(Ity_I64);
+         assign(i64, unop(Iop_ReinterpF64asI64, getDReg(dM)));
+         putIReg(rN, unop(Iop_64HIto32, mkexpr(i64)), condT, Ijk_Boring);
+         putIReg(rD, unop(Iop_64to32,   mkexpr(i64)), condT, Ijk_Boring);
+         DIP("vmov%s r%u, r%u, d%u\n", nCC(INSN_COND), rD, rN, dM);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   /* --------------------- f{ld,st}d --------------------- */
+   // FLDD, FSTD
+   if (BITS8(1,1,0,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,1,1,0))
+       && BITS4(1,0,1,1) == INSN(11,8)) {
+      UInt dD     = INSN(15,12);
+      UInt rN     = INSN(19,16);
+      UInt offset = (insn & 0xFF) << 2;
+      UInt bU     = (insn >> 23) & 1; /* 1: +offset  0: -offset */
+      UInt bL     = (insn >> 20) & 1; /* 1: load  0: store */
+      /* make unconditional */
+      if (condT != IRTemp_INVALID) {
+         mk_skip_to_next_if_cond_is_false( condT );
+         condT = IRTemp_INVALID;
+      }
+      IRTemp ea = newTemp(Ity_I32);
+      assign(ea, binop(bU ? Iop_Add32 : Iop_Sub32,
+                       getIReg(rN), mkU32(offset)));
+      if (bL) {
+         putDReg(dD, loadLE(Ity_F64,mkexpr(ea)), IRTemp_INVALID);
+      } else {
+         storeLE(mkexpr(ea), getDReg(dD));
+      }
+      DIP("f%sd%s d%u, [r%u, %c#%u]\n",
+          bL ? "ld" : "st", nCC(INSN_COND), dD, rN,
+          bU ? '+' : '-', offset);
+      goto decode_success;
+   }
+
+   /* --------------------- dp insns (D) --------------------- */
+   if (BITS8(1,1,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,1,0,0))
+       && BITS4(1,0,1,1) == INSN(11,8)
+       && BITS4(0,0,0,0) == (INSN(7,4) & BITS4(1,0,1,1))) {
+      UInt    dM  = INSN(3,0);   /* argR */
+      UInt    dD  = INSN(15,12); /* dst/acc */
+      UInt    dN  = INSN(19,16); /* argL */
+      UInt    bP  = (insn >> 23) & 1;
+      UInt    bQ  = (insn >> 21) & 1;
+      UInt    bR  = (insn >> 20) & 1;
+      UInt    bS  = (insn >> 6) & 1;
+      UInt    opc = (bP << 3) | (bQ << 2) | (bR << 1) | bS;
+      IRExpr* rm  = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
+      switch (opc) {
+         case BITS4(0,0,0,0): /* MAC: d + n * m */
+            putDReg(dD, triop(Iop_AddF64, rm,
+                              getDReg(dD),
+                              triop(Iop_MulF64, rm, getDReg(dN),
+                                                    getDReg(dM))),
+                        condT);
+            DIP("fmacd%s d%u, d%u, d%u\n", nCC(INSN_COND), dD, dN, dM);
+            goto decode_success;
+         case BITS4(0,0,0,1): /* NMAC: d - n * m */
+            putDReg(dD, triop(Iop_SubF64, rm,
+                              getDReg(dD),
+                              triop(Iop_MulF64, rm, getDReg(dN),
+                                                    getDReg(dM))),
+                        condT);
+            DIP("fnmacd%s d%u, d%u, d%u\n", nCC(INSN_COND), dD, dN, dM);
+            goto decode_success;
+         case BITS4(0,0,1,0): /* MSC: - d + n * m */
+            putDReg(dD, triop(Iop_AddF64, rm,
+                              unop(Iop_NegF64, getDReg(dD)),
+                              triop(Iop_MulF64, rm, getDReg(dN),
+                                                    getDReg(dM))),
+                        condT);
+            DIP("fmscd%s d%u, d%u, d%u\n", nCC(INSN_COND), dD, dN, dM);
+            goto decode_success;
+         case BITS4(0,0,1,1): /* NMSC: - d - n * m */
+            putDReg(dD, triop(Iop_SubF64, rm,
+                              unop(Iop_NegF64, getDReg(dD)),
+                              triop(Iop_MulF64, rm, getDReg(dN),
+                                                    getDReg(dM))),
+                        condT);
+            DIP("fnmscd%s d%u, d%u, d%u\n", nCC(INSN_COND), dD, dN, dM);
+            goto decode_success;
+         case BITS4(0,1,0,0): /* MUL: n * m */
+            putDReg(dD, triop(Iop_MulF64, rm, getDReg(dN), getDReg(dM)),
+                        condT);
+            DIP("fmuld%s d%u, d%u, d%u\n", nCC(INSN_COND), dD, dN, dM);
+            goto decode_success;
+         case BITS4(0,1,0,1): /* NMUL: - n * m */
+            putDReg(dD, unop(Iop_NegF64,
+                             triop(Iop_MulF64, rm, getDReg(dN),
+                                                   getDReg(dM))),
+                    condT);
+            DIP("fnmuld%s d%u, d%u, d%u\n", nCC(INSN_COND), dD, dN, dM);
+            goto decode_success;
+         case BITS4(0,1,1,0): /* ADD: n + m */
+            putDReg(dD, triop(Iop_AddF64, rm, getDReg(dN), getDReg(dM)),
+                        condT);
+            DIP("faddd%s d%u, d%u, d%u\n", nCC(INSN_COND), dD, dN, dM);
+            goto decode_success;
+         case BITS4(0,1,1,1): /* SUB: n - m */
+            putDReg(dD, triop(Iop_SubF64, rm, getDReg(dN), getDReg(dM)),
+                        condT);
+            DIP("fsubd%s d%u, d%u, d%u\n", nCC(INSN_COND), dD, dN, dM);
+            goto decode_success;
+         case BITS4(1,0,0,0): /* DIV: n / m */
+            putDReg(dD, triop(Iop_DivF64, rm, getDReg(dN), getDReg(dM)),
+                        condT);
+            DIP("fdivd%s d%u, d%u, d%u\n", nCC(INSN_COND), dD, dN, dM);
+            goto decode_success;
+         default:
+            break;
+      }
+   }
+
+   /* --------------------- compares (D) --------------------- */
+   /*          31   27   23   19   15 11   7    3
+                 28   24   20   16 12    8    4    0 
+      FCMPD    cond 1110 1011 0100 Dd 1011 0100 Dm
+      FCMPED   cond 1110 1011 0100 Dd 1011 1100 Dm
+      FCMPZD   cond 1110 1011 0101 Dd 1011 0100 0000
+      FCMPZED  cond 1110 1011 0101 Dd 1011 1100 0000
+                                 Z         N
+
+      Z=0 Compare Dd vs Dm     and set FPSCR 31:28 accordingly
+      Z=1 Compare Dd vs zero
+
+      N=1 generates Invalid Operation exn if either arg is any kind of NaN
+      N=0 generates Invalid Operation exn if either arg is a signalling NaN
+      (Not that we pay any attention to N here)
+   */
+   if (BITS8(1,1,1,0,1,0,1,1) == INSN(27,20)
+       && BITS4(0,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
+       && BITS4(1,0,1,1) == INSN(11,8)
+       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,1,1))) {
+      UInt bZ = (insn >> 16) & 1;
+      UInt bN = (insn >> 7) & 1;
+      UInt dD = INSN(15,12);
+      UInt dM = INSN(3,0);
+      if (bZ && INSN(3,0) != 0) {
+         /* does not decode; fall through */
+      } else {
+         IRTemp argL = newTemp(Ity_F64);
+         IRTemp argR = newTemp(Ity_F64);
+         IRTemp irRes = newTemp(Ity_I32);
+         assign(argL, getDReg(dD));
+         assign(argR, bZ ? IRExpr_Const(IRConst_F64i(0)) : getDReg(dM));
+         assign(irRes, binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)));
+
+         IRTemp nzcv     = IRTemp_INVALID;
+         IRTemp oldFPSCR = newTemp(Ity_I32);
+         IRTemp newFPSCR = newTemp(Ity_I32);
+
+         /* This is where the fun starts.  We have to convert 'irRes'
+            from an IR-convention return result (IRCmpF64Result) to an
+            ARM-encoded (N,Z,C,V) group.  The final result is in the
+            bottom 4 bits of 'nzcv'. */
+         /* Map compare result from IR to ARM(nzcv) */
+         /*
+            FP cmp result | IR   | ARM(nzcv)
+            --------------------------------
+            UN              0x45   0011
+            LT              0x01   1000
+            GT              0x00   0010
+            EQ              0x40   0110
+         */
+         nzcv = mk_convert_IRCmpF64Result_to_NZCV(irRes);
+
+         /* And update FPSCR accordingly */
+         assign(oldFPSCR, IRExpr_Get(OFFB_FPSCR, Ity_I32));
+         assign(newFPSCR, 
+                binop(Iop_Or32, 
+                      binop(Iop_And32, mkexpr(oldFPSCR), mkU32(0x0FFFFFFF)),
+                      binop(Iop_Shl32, mkexpr(nzcv), mkU8(28))));
+
+         putMiscReg32(OFFB_FPSCR, mkexpr(newFPSCR), condT);
+
+         if (bZ) {
+            DIP("fcmpz%sd%s d%u\n", bN ? "e" : "", nCC(INSN_COND), dD);
+         } else {
+            DIP("fcmp%sd%s d%u, d%u\n", bN ? "e" : "", nCC(INSN_COND), dD, dM);
+         }
+         goto decode_success;
+      }
+      /* fall through */
+   }  
+
+   /* --------------------- unary (D) --------------------- */
+   if (BITS8(1,1,1,0,1,0,1,1) == INSN(27,20)
+       && BITS4(0,0,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
+       && BITS4(1,0,1,1) == INSN(11,8)
+       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,1,1))) {
+      UInt dD  = INSN(15,12);
+      UInt dM  = INSN(3,0);
+      UInt b16 = (insn >> 16) & 1;
+      UInt b7  = (insn >> 7) & 1;
+      /**/ if (b16 == 0 && b7 == 0) {
+         // FCPYD
+         putDReg(dD, getDReg(dM), condT);
+         DIP("fcpyd%s d%u, d%u\n", nCC(INSN_COND), dD, dM);
+         goto decode_success;
+      }
+      else if (b16 == 0 && b7 == 1) {
+         // FABSD
+         putDReg(dD, unop(Iop_AbsF64, getDReg(dM)), condT);
+         DIP("fabsd%s d%u, d%u\n", nCC(INSN_COND), dD, dM);
+         goto decode_success;
+      }
+      else if (b16 == 1 && b7 == 0) {
+         // FNEGD
+         putDReg(dD, unop(Iop_NegF64, getDReg(dM)), condT);
+         DIP("fnegd%s d%u, d%u\n", nCC(INSN_COND), dD, dM);
+         goto decode_success;
+      }
+      else if (b16 == 1 && b7 == 1) {
+         // FSQRTD
+         IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
+         putDReg(dD, binop(Iop_SqrtF64, rm, getDReg(dM)), condT);
+         DIP("fsqrtd%s d%u, d%u\n", nCC(INSN_COND), dD, dM);
+         goto decode_success;
       }
-      
-      
+      else
+         vassert(0);
+
+      /* fall through */
+   }
+
+   /* ----------------- I <-> D conversions ----------------- */
+
+   // F{S,U}ITOD dD, fM
+   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,1))
+       && BITS4(1,0,0,0) == (INSN(19,16) & BITS4(1,1,1,1))
+       && BITS4(1,0,1,1) == INSN(11,8)
+       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
+      UInt bM    = (insn >> 5) & 1;
+      UInt fM    = (INSN(3,0) << 1) | bM;
+      UInt dD    = INSN(15,12);
+      UInt syned = (insn >> 7) & 1;
+      if (syned) {
+         // FSITOD
+         putDReg(dD, unop(Iop_I32StoF64,
+                          unop(Iop_ReinterpF32asI32, getFReg(fM))),
+                 condT);
+         DIP("fsitod%s d%u, s%u\n", nCC(INSN_COND), dD, fM);
+      } else {
+         // FUITOD
+         putDReg(dD, unop(Iop_I32UtoF64,
+                          unop(Iop_ReinterpF32asI32, getFReg(fM))),
+                 condT);
+         DIP("fuitod%s d%u, s%u\n", nCC(INSN_COND), dD, fM);
+      }
+      goto decode_success;
+   }
+
+   // FTO{S,U}ID fD, dM
+   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
+       && BITS4(1,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
+       && BITS4(1,0,1,1) == INSN(11,8)
+       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,1,1))) {
+      UInt   bD    = (insn >> 22) & 1;
+      UInt   fD    = (INSN(15,12) << 1) | bD;
+      UInt   dM    = INSN(3,0);
+      UInt   bZ    = (insn >> 7) & 1;
+      UInt   syned = (insn >> 16) & 1;
+      IRTemp rmode = newTemp(Ity_I32);
+      assign(rmode, bZ ? mkU32(Irrm_ZERO)
+                       : mkexpr(mk_get_IR_rounding_mode()));
+      if (syned) {
+         // FTOSID
+         putFReg(fD, unop(Iop_ReinterpI32asF32,
+                          binop(Iop_F64toI32S, mkexpr(rmode),
+                                getDReg(dM))),
+                 condT);
+         DIP("ftosi%sd%s s%u, d%u\n", bZ ? "z" : "",
+             nCC(INSN_COND), fD, dM);
+      } else {
+         // FTOUID
+         putFReg(fD, unop(Iop_ReinterpI32asF32,
+                          binop(Iop_F64toI32U, mkexpr(rmode),
+                                getDReg(dM))),
+                 condT);
+         DIP("ftoui%sd%s s%u, d%u\n", bZ ? "z" : "",
+             nCC(INSN_COND), fD, dM);
+      }
+      goto decode_success;
+   }
+
+   /* ----------------------------------------------------------- */
+   /* -- VFP instructions -- single precision                  -- */
+   /* ----------------------------------------------------------- */
+
+   /* --------------------- fldms, fstms --------------------- */
    /*
-     Software Interrupt
+                                 31   27   23   19 15 11   7   0
+                                         P UDWL
+      C4-98, C5-26   1  FSTMD    cond 1100 1x00 Rn Fd 1010 offset
+      C4-98, C5-28   2  FSTMDIA  cond 1100 1x10 Rn Fd 1010 offset
+      C4-98, C5-30   3  FSTMDDB  cond 1101 0x10 Rn Fd 1010 offset
+
+      C4-40, C5-26   1  FLDMD    cond 1100 1x01 Rn Fd 1010 offset
+      C4-40, C5-26   2  FLDMIAD  cond 1100 1x11 Rn Fd 1010 offset
+      C4-40, C5-26   3  FLDMDBD  cond 1101 0x11 Rn Fd 1010 offset
+
+      Regs transferred: F(Fd:D) .. F(Fd:d + offset)
+      offset must not imply a reg > 15
+      IA/DB: Rn is changed by (4 x # regs transferred)
+
+      case coding:
+         1  at-Rn   (access at Rn)
+         2  ia-Rn   (access at Rn, then Rn += 4n)
+         3  db-Rn   (Rn -= 4n,     then access at Rn)
    */
-   case 0xF: // swi
-      goto decode_failure;
-      
-   default:
-   decode_failure:
+   if (BITS8(1,1,0,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,0,0,0,0,0))
+       && INSN(11,8) == BITS4(1,0,1,0)) {
+      UInt bP     = (insn >> 24) & 1;
+      UInt bU     = (insn >> 23) & 1;
+      UInt bW     = (insn >> 21) & 1;
+      UInt bL     = (insn >> 20) & 1;
+      UInt bD     = (insn >> 22) & 1;
+      UInt offset = (insn >> 0) & 0xFF;
+      UInt rN     = INSN(19,16);
+      UInt fD     = (INSN(15,12) << 1) | bD;
+      UInt nRegs  = offset;
+      Int  i;
+
+      /**/ if (bP == 0 && bU == 1 && bW == 0) {
+         vassert(0); //ATC
+         summary = 1;
+      }
+      else if (bP == 0 && bU == 1 && bW == 1) {
+         summary = 2;
+      }
+      else if (bP == 1 && bU == 0 && bW == 1) {
+         summary = 3;
+      }
+      else goto after_vfp_fldms_fstms;
+
+      /* no writebacks to r15 allowed */
+      if (rN == 15 && (summary == 2 || summary == 3))
+         goto after_vfp_fldms_fstms;
+
+      /* offset must specify at least one register */
+      if (offset < 1)
+         goto after_vfp_fldms_fstms;
+
+      /* can't transfer regs after S31 */
+      if (fD + nRegs - 1 >= 32)
+         goto after_vfp_fldms_fstms;
+
+      /* Now, we can't do a conditional load or store, since that very
+         likely will generate an exception.  So we have to take a side
+         exit at this point if the condition is false. */
+      if (condT != IRTemp_INVALID) {
+         mk_skip_to_next_if_cond_is_false( condT );
+         condT = IRTemp_INVALID;
+      }
+      /* Ok, now we're unconditional.  Do the load or store. */
+
+      /* get the old Rn value */
+      IRTemp rnT = newTemp(Ity_I32);
+      assign(rnT, getIReg(rN));
+
+      /* make a new value for Rn, post-insn */
+      IRTemp rnTnew = IRTemp_INVALID;
+      if (summary == 2 || summary == 3) {
+         rnTnew = newTemp(Ity_I32);
+         assign(rnTnew, binop(summary == 2 ? Iop_Add32 : Iop_Sub32,
+                              mkexpr(rnT),
+                              mkU32(4 * nRegs)));
+      }
+
+      /* decide on the base transfer address */
+      IRTemp taT = newTemp(Ity_I32);
+      assign(taT, summary == 3 ? mkexpr(rnTnew) : mkexpr(rnT));
+
+      /* update Rn if necessary -- in case 3, we're moving it down, so
+         update before any memory reference, in order to keep Memcheck
+         and V's stack-extending logic (on linux) happy */
+      if (summary == 3)
+         putIReg(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
+
+      /* generate the transfers */
+      for (i = 0; i < nRegs; i++) {
+         IRExpr* addr = binop(Iop_Add32, mkexpr(taT), mkU32(4*i));
+         if (bL) {
+            putFReg(fD + i, loadLE(Ity_F32, addr), IRTemp_INVALID);
+         } else {
+            storeLE(addr, getFReg(fD + i));
+         }
+      }
+
+      /* update Rn if necessary -- in case 2, we're moving it up, so
+         update after any memory reference, in order to keep Memcheck
+         and V's stack-extending logic (on linux) happy */
+      if (summary == 2)
+         putIReg(rN, mkexpr(rnTnew), IRTemp_INVALID, Ijk_Boring);
+
+      HChar* nm = bL==1 ? "ld" : "st";
+      switch (summary) {
+         case 1:  DIP("f%sms%s r%u, {s%u-s%u}\n", 
+                      nm, nCC(INSN_COND), rN, fD, fD + nRegs - 1);
+                  break;
+         case 2:  DIP("f%smias%s r%u!, {s%u-s%u}\n", 
+                      nm, nCC(INSN_COND), rN, fD, fD + nRegs - 1);
+                  break;
+         case 3:  DIP("f%smdbs%s r%u!, {s%u-s%u}\n", 
+                      nm, nCC(INSN_COND), rN, fD, fD + nRegs - 1);
+                  break;
+         default: vassert(0);
+      }
+
+      goto decode_success;
+      /* FIXME alignment constraints? */
+   }
+
+  after_vfp_fldms_fstms:
+
+   /* --------------------- fmsr, fmrs --------------------- */
+   if (BITS8(1,1,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,0))
+       && BITS4(1,0,1,0) == INSN(11,8)
+       && BITS4(0,0,0,0) == INSN(3,0)
+       && BITS4(0,0,0,1) == (INSN(7,4) & BITS4(0,1,1,1))) {
+      UInt rD  = INSN(15,12);
+      UInt b7  = (insn >> 7) & 1;
+      UInt fN  = (INSN(19,16) << 1) | b7;
+      UInt b20 = (insn >> 20) & 1;
+      if (rD == 15) {
+         /* fall through */
+         /* Let's assume that no sane person would want to do
+            floating-point transfers to or from the program counter,
+            and simply decline to decode the instruction.  The ARM ARM
+            doesn't seem to explicitly disallow this case, though. */
+      } else {
+         if (b20) {
+            putIReg(rD, unop(Iop_ReinterpF32asI32, getFReg(fN)),
+                        condT, Ijk_Boring);
+            DIP("fmrs%s r%u, s%u\n", nCC(INSN_COND), rD, fN);
+         } else {
+            putFReg(fN, unop(Iop_ReinterpI32asF32, getIReg(rD)), condT);
+            DIP("fmsr%s s%u, r%u\n", nCC(INSN_COND), fN, rD);
+         }
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   /* --------------------- f{ld,st}s --------------------- */
+   // FLDS, FSTS
+   if (BITS8(1,1,0,1,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,1,0))
+       && BITS4(1,0,1,0) == INSN(11,8)) {
+      UInt bD     = (insn >> 22) & 1;
+      UInt fD     = (INSN(15,12) << 1) | bD;
+      UInt rN     = INSN(19,16);
+      UInt offset = (insn & 0xFF) << 2;
+      UInt bU     = (insn >> 23) & 1; /* 1: +offset  0: -offset */
+      UInt bL     = (insn >> 20) & 1; /* 1: load  0: store */
+      /* make unconditional */
+      if (condT != IRTemp_INVALID) {
+         mk_skip_to_next_if_cond_is_false( condT );
+         condT = IRTemp_INVALID;
+      }
+      IRTemp ea = newTemp(Ity_I32);
+      assign(ea, binop(bU ? Iop_Add32 : Iop_Sub32,
+                       getIReg(rN), mkU32(offset)));
+      if (bL) {
+         putFReg(fD, loadLE(Ity_F32,mkexpr(ea)), IRTemp_INVALID);
+      } else {
+         storeLE(mkexpr(ea), getFReg(fD));
+      }
+      DIP("f%ss%s s%u, [r%u, %c#%u]\n",
+          bL ? "ld" : "st", nCC(INSN_COND), fD, rN,
+          bU ? '+' : '-', offset);
+      goto decode_success;
+   }
+
+   /* --------------------- dp insns (F) --------------------- */
+   if (BITS8(1,1,1,0,0,0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,0,0,0,0))
+       && BITS4(1,0,1,0) == INSN(11,8)
+       && BITS4(0,0,0,0) == (INSN(7,4) & BITS4(0,0,0,1))) {
+      UInt    bM  = (insn >> 5) & 1;
+      UInt    bD  = (insn >> 22) & 1;
+      UInt    bN  = (insn >> 7) & 1;
+      UInt    fM  = (INSN(3,0) << 1) | bM;   /* argR */
+      UInt    fD  = (INSN(15,12) << 1) | bD; /* dst/acc */
+      UInt    fN  = (INSN(19,16) << 1) | bN; /* argL */
+      UInt    bP  = (insn >> 23) & 1;
+      UInt    bQ  = (insn >> 21) & 1;
+      UInt    bR  = (insn >> 20) & 1;
+      UInt    bS  = (insn >> 6) & 1;
+      UInt    opc = (bP << 3) | (bQ << 2) | (bR << 1) | bS;
+      IRExpr* rm  = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
+      switch (opc) {
+         case BITS4(0,0,0,0): /* MAC: d + n * m */
+            putFReg(fD, triop(Iop_AddF32, rm,
+                              getFReg(fD),
+                              triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM))),
+                        condT);
+            DIP("fmacs%s s%u, s%u, s%u\n", nCC(INSN_COND), fD, fN, fM);
+            goto decode_success;
+         case BITS4(0,0,0,1): /* NMAC: d - n * m */
+            putFReg(fD, triop(Iop_SubF32, rm,
+                              getFReg(fD),
+                              triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM))),
+                        condT);
+            DIP("fnmacs%s s%u, s%u, s%u\n", nCC(INSN_COND), fD, fN, fM);
+            goto decode_success;
+         case BITS4(0,0,1,0): /* MSC: - d + n * m */
+            putFReg(fD, triop(Iop_AddF32, rm,
+                              unop(Iop_NegF32, getFReg(fD)),
+                              triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM))),
+                        condT);
+            DIP("fmscs%s s%u, s%u, s%u\n", nCC(INSN_COND), fD, fN, fM);
+            goto decode_success;
+         case BITS4(0,0,1,1): /* NMSC: - d - n * m */
+            break; //ATC
+         case BITS4(0,1,0,0): /* MUL: n * m */
+            putFReg(fD, triop(Iop_MulF32, rm, getFReg(fN), getFReg(fM)),
+                        condT);
+            DIP("fmuls%s s%u, s%u, s%u\n", nCC(INSN_COND), fD, fN, fM);
+            goto decode_success;
+         case BITS4(0,1,0,1): /* NMUL: - n * m */
+            putFReg(fD, unop(Iop_NegF32,
+                             triop(Iop_MulF32, rm, getFReg(fN),
+                                                   getFReg(fM))),
+                    condT);
+            DIP("fnmuls%s s%u, s%u, s%u\n", nCC(INSN_COND), fD, fN, fM);
+            goto decode_success;
+         case BITS4(0,1,1,0): /* ADD: n + m */
+            putFReg(fD, triop(Iop_AddF32, rm, getFReg(fN), getFReg(fM)),
+                        condT);
+            DIP("fadds%s s%u, s%u, s%u\n", nCC(INSN_COND), fD, fN, fM);
+            goto decode_success;
+         case BITS4(0,1,1,1): /* SUB: n - m */
+            putFReg(fD, triop(Iop_SubF32, rm, getFReg(fN), getFReg(fM)),
+                        condT);
+            DIP("fsubs%s s%u, s%u, s%u\n", nCC(INSN_COND), fD, fN, fM);
+            goto decode_success;
+         case BITS4(1,0,0,0): /* DIV: n / m */
+            putFReg(fD, triop(Iop_DivF32, rm, getFReg(fN), getFReg(fM)),
+                        condT);
+            DIP("fdivs%s s%u, s%u, s%u\n", nCC(INSN_COND), fD, fN, fM);
+            goto decode_success;
+         default:
+            break;
+      }
+   }
+
+   /* --------------------- compares (S) --------------------- */
+   /*          31   27   23   19   15 11   7    3
+                 28   24   20   16 12    8    4    0 
+      FCMPS    cond 1110 1D11 0100 Fd 1010 01M0 Fm
+      FCMPES   cond 1110 1D11 0100 Fd 1010 11M0 Fm
+      FCMPZS   cond 1110 1D11 0101 Fd 1010 0100 0000
+      FCMPZED  cond 1110 1D11 0101 Fd 1010 1100 0000
+                                 Z         N
+
+      Z=0 Compare Fd:D vs Fm:M     and set FPSCR 31:28 accordingly
+      Z=1 Compare Fd:D vs zero
+
+      N=1 generates Invalid Operation exn if either arg is any kind of NaN
+      N=0 generates Invalid Operation exn if either arg is a signalling NaN
+      (Not that we pay any attention to N here)
+   */
+   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
+       && BITS4(0,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
+       && BITS4(1,0,1,0) == INSN(11,8)
+       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
+      UInt bZ = (insn >> 16) & 1;
+      UInt bN = (insn >> 7) & 1;
+      UInt bD = (insn >> 22) & 1;
+      UInt bM = (insn >> 5) & 1;
+      UInt fD = (INSN(15,12) << 1) | bD;
+      UInt fM = (INSN(3,0) << 1) | bM;
+      if (bZ && (INSN(3,0) != 0 || (INSN(7,4) & 3) != 0)) {
+         /* does not decode; fall through */
+      } else {
+         IRTemp argL = newTemp(Ity_F64);
+         IRTemp argR = newTemp(Ity_F64);
+         IRTemp irRes = newTemp(Ity_I32);
+
+         assign(argL, unop(Iop_F32toF64, getFReg(fD)));
+         assign(argR, bZ ? IRExpr_Const(IRConst_F64i(0))
+                         : unop(Iop_F32toF64, getFReg(fM)));
+         assign(irRes, binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)));
+
+         IRTemp nzcv     = IRTemp_INVALID;
+         IRTemp oldFPSCR = newTemp(Ity_I32);
+         IRTemp newFPSCR = newTemp(Ity_I32);
+
+         /* This is where the fun starts.  We have to convert 'irRes'
+            from an IR-convention return result (IRCmpF64Result) to an
+            ARM-encoded (N,Z,C,V) group.  The final result is in the
+            bottom 4 bits of 'nzcv'. */
+         /* Map compare result from IR to ARM(nzcv) */
+         /*
+            FP cmp result | IR   | ARM(nzcv)
+            --------------------------------
+            UN              0x45   0011
+            LT              0x01   1000
+            GT              0x00   0010
+            EQ              0x40   0110
+         */
+         nzcv = mk_convert_IRCmpF64Result_to_NZCV(irRes);
+
+         /* And update FPSCR accordingly */
+         assign(oldFPSCR, IRExpr_Get(OFFB_FPSCR, Ity_I32));
+         assign(newFPSCR, 
+                binop(Iop_Or32, 
+                      binop(Iop_And32, mkexpr(oldFPSCR), mkU32(0x0FFFFFFF)),
+                      binop(Iop_Shl32, mkexpr(nzcv), mkU8(28))));
+
+         putMiscReg32(OFFB_FPSCR, mkexpr(newFPSCR), condT);
+
+         if (bZ) {
+            DIP("fcmpz%ss%s s%u\n", bN ? "e" : "", nCC(INSN_COND), fD);
+         } else {
+            DIP("fcmp%ss%s s%u, s%u\n", bN ? "e" : "",
+                nCC(INSN_COND), fD, fM);
+         }
+         goto decode_success;
+      }
+      /* fall through */
+   }  
+
+   /* --------------------- unary (S) --------------------- */
+   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
+       && BITS4(0,0,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
+       && BITS4(1,0,1,0) == INSN(11,8)
+       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
+      UInt bD = (insn >> 22) & 1;
+      UInt bM = (insn >> 5) & 1;
+      UInt fD  = (INSN(15,12) << 1) | bD;
+      UInt fM  = (INSN(3,0) << 1) | bM;
+      UInt b16 = (insn >> 16) & 1;
+      UInt b7  = (insn >> 7) & 1;
+      /**/ if (b16 == 0 && b7 == 0) {
+         // FCPYS
+         putFReg(fD, getFReg(fM), condT);
+         DIP("fcpys%s s%u, s%u\n", nCC(INSN_COND), fD, fM);
+         goto decode_success;
+      }
+      else if (b16 == 0 && b7 == 1) {
+         // FABSS
+         putFReg(fD, unop(Iop_AbsF32, getFReg(fM)), condT);
+         DIP("fabss%s s%u, s%u\n", nCC(INSN_COND), fD, fM);
+         goto decode_success;
+      }
+      else if (b16 == 1 && b7 == 0) {
+         // FNEGS
+         putFReg(fD, unop(Iop_NegF32, getFReg(fM)), condT);
+         DIP("fnegs%s s%u, s%u\n", nCC(INSN_COND), fD, fM);
+         goto decode_success;
+      }
+      else if (b16 == 1 && b7 == 1) {
+         // FSQRTS
+         IRExpr* rm = get_FAKE_roundingmode(); /* XXXROUNDINGFIXME */
+         putFReg(fD, binop(Iop_SqrtF32, rm, getFReg(fM)), condT);
+         DIP("fsqrts%s s%u, s%u\n", nCC(INSN_COND), fD, fM);
+         goto decode_success;
+      }
+      else
+         vassert(0);
+
+      /* fall through */
+   }
+
+   /* ----------------- I <-> S conversions ----------------- */
+
+   // F{S,U}ITOS fD, fM
+   /* These are more complex than FSITOD/FUITOD.  In the D cases, a 32
+      bit int will always fit within the 53 bit mantissa, so there's
+      no possibility of a loss of precision, but that's obviously not
+      the case here.  Hence this case possibly requires rounding, and
+      so it drags in the current rounding mode. */
+   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
+       && BITS4(1,0,0,0) == (INSN(19,16) & BITS4(1,1,1,1))
+       && BITS4(1,0,1,0) == INSN(11,8)
+       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
+      UInt bM    = (insn >> 5) & 1;
+      UInt bD    = (insn >> 22) & 1;
+      UInt fM    = (INSN(3,0) << 1) | bM;
+      UInt fD    = (INSN(15,12) << 1) | bD;
+      UInt syned = (insn >> 7) & 1;
+      IRTemp rmode = newTemp(Ity_I32);
+      assign(rmode, mkexpr(mk_get_IR_rounding_mode()));
+      if (syned) {
+         // FSITOS
+         putFReg(fD, binop(Iop_F64toF32,
+                           mkexpr(rmode),
+                           unop(Iop_I32StoF64,
+                                unop(Iop_ReinterpF32asI32, getFReg(fM)))),
+                 condT);
+         DIP("fsitos%s s%u, s%u\n", nCC(INSN_COND), fD, fM);
+      } else {
+         // FUITOS
+         putFReg(fD, binop(Iop_F64toF32,
+                           mkexpr(rmode),
+                           unop(Iop_I32UtoF64,
+                                unop(Iop_ReinterpF32asI32, getFReg(fM)))),
+                 condT);
+         DIP("fuitos%s s%u, s%u\n", nCC(INSN_COND), fD, fM);
+      }
+      goto decode_success;
+   }
+
+   // FTO{S,U}IS fD, fM
+   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
+       && BITS4(1,1,0,0) == (INSN(19,16) & BITS4(1,1,1,0))
+       && BITS4(1,0,1,0) == INSN(11,8)
+       && BITS4(0,1,0,0) == (INSN(7,4) & BITS4(0,1,0,1))) {
+      UInt   bM    = (insn >> 5) & 1;
+      UInt   bD    = (insn >> 22) & 1;
+      UInt   fD    = (INSN(15,12) << 1) | bD;
+      UInt   fM    = (INSN(3,0) << 1) | bM;
+      UInt   bZ    = (insn >> 7) & 1;
+      UInt   syned = (insn >> 16) & 1;
+      IRTemp rmode = newTemp(Ity_I32);
+      assign(rmode, bZ ? mkU32(Irrm_ZERO)
+                       : mkexpr(mk_get_IR_rounding_mode()));
+      if (syned) {
+         // FTOSIS
+         putFReg(fD, unop(Iop_ReinterpI32asF32,
+                          binop(Iop_F64toI32S, mkexpr(rmode),
+                                unop(Iop_F32toF64, getFReg(fM)))),
+                 condT);
+         DIP("ftosi%ss%s s%u, d%u\n", bZ ? "z" : "",
+             nCC(INSN_COND), fD, fM);
+         goto decode_success;
+      } else {
+         // FTOUIS
+         //putFReg(fD, unop(Iop_ReinterpI32asF32,
+         //                 binop(Iop_F64toI32U, mkexpr(rmode),
+         //                       unop(Iop_F32toF64, getFReg(fM)))),
+         //        condT);
+         //DIP("ftoui%ss%s s%u, d%u\n", bZ ? "z" : "",
+         //    nCC(INSN_COND), fD, fM);
+         //goto decode_success;
+      }
+   }
+
+   /* ----------------- S <-> D conversions ----------------- */
+
+   // FCVTDS
+   if (BITS8(1,1,1,0,1,0,1,1) == INSN(27,20)
+       && BITS4(0,1,1,1) == INSN(19,16)
+       && BITS4(1,0,1,0) == INSN(11,8)
+       && BITS4(1,1,0,0) == (INSN(7,4) & BITS4(1,1,0,1))) {
+      UInt dD = INSN(15,12);
+      UInt bM = (insn >> 5) & 1;
+      UInt fM = (INSN(3,0) << 1) | bM;
+      putDReg(dD, unop(Iop_F32toF64, getFReg(fM)), condT);
+      DIP("fcvtds%s d%u, s%u\n", nCC(INSN_COND), dD, fM);
+      goto decode_success;
+   }
+
+   // FCVTSD
+   if (BITS8(1,1,1,0,1,0,1,1) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,1))
+       && BITS4(0,1,1,1) == INSN(19,16)
+       && BITS4(1,0,1,1) == INSN(11,8)
+       && BITS4(1,1,0,0) == INSN(7,4)) {
+      UInt   bD    = (insn >> 22) & 1;
+      UInt   fD    = (INSN(15,12) << 1) | bD;
+      UInt   dM    = INSN(3,0);
+      IRTemp rmode = newTemp(Ity_I32);
+      assign(rmode, mkexpr(mk_get_IR_rounding_mode()));
+      putFReg(fD, binop(Iop_F64toF32, mkexpr(rmode), getDReg(dM)),
+                  condT);
+      DIP("fcvtsd%s s%u, d%u\n", nCC(INSN_COND), fD, dM);
+      goto decode_success;
+   }
+
+   /* ----------------------------------------------------------- */
+   /* -- ARMv6 instructions                                    -- */
+   /* ----------------------------------------------------------- */
+
+   /* --------------------- ldrex, strex --------------------- */
+
+   // LDREX
+   if (0x01900F9F == (insn & 0x0FF00FFF)) {
+      UInt rT = INSN(15,12);
+      UInt rN = INSN(19,16);
+      if (rT == 15 || rN == 15 || rT == 14 /* || (rT & 1)*/) {
+         /* undecodable; fall through */
+      } else {
+         IRTemp res;
+         /* make unconditional */
+         if (condT != IRTemp_INVALID) {
+            mk_skip_to_next_if_cond_is_false( condT );
+            condT = IRTemp_INVALID;
+         }
+         /* Ok, now we're unconditional.  Do the load. */
+         res = newTemp(Ity_I32);
+         stmt( IRStmt_LLSC(Iend_LE, res, getIReg(rN), NULL/*this is a load*/) );
+         putIReg(rT, mkexpr(res), IRTemp_INVALID, Ijk_Boring);
+         DIP("ldrex%s r%u, [r%u]\n", nCC(INSN_COND), rT, rN);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   // STREX
+   if (0x01800F90 == (insn & 0x0FF00FF0)) {
+      UInt rT = INSN(3,0);
+      UInt rN = INSN(19,16);
+      UInt rD = INSN(15,12);
+      if (rT == 15 || rN == 15 || rD == 15
+          || rT == 14 /* || (rT & 1)*/
+          || rD == rT || rN == rT) {
+         /* undecodable; fall through */
+      } else {
+         IRTemp resSC1, resSC32;
+
+         /* make unconditional */
+         if (condT != IRTemp_INVALID) {
+            mk_skip_to_next_if_cond_is_false( condT );
+            condT = IRTemp_INVALID;
+         }
+
+         /* Ok, now we're unconditional.  Do the store. */
+         resSC1 = newTemp(Ity_I1);
+         stmt( IRStmt_LLSC(Iend_LE, resSC1, getIReg(rN), getIReg(rT)) );
+
+         /* Set rD to 1 on failure, 0 on success.  Currently we have
+            resSC1 == 0 on failure, 1 on success. */
+         resSC32 = newTemp(Ity_I32);
+         assign(resSC32,
+                unop(Iop_1Uto32, unop(Iop_Not1, mkexpr(resSC1))));
+
+         putIReg(rD, mkexpr(resSC32),
+                     IRTemp_INVALID, Ijk_Boring);
+         DIP("strex%s r%u, r%u, [r%u]\n", nCC(INSN_COND), rD, rT, rN);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   /* --------------------- movw, movt --------------------- */
+   if (0x03000000 == (insn & 0x0FF00000)
+       || 0x03400000 == (insn & 0x0FF00000)) /* pray for CSE */ {
+      UInt rD    = INSN(15,12);
+      UInt imm16 = (insn & 0xFFF) | ((insn >> 4) & 0x0000F000);
+      UInt isT   = (insn >> 22) & 1;
+      if (rD == 15) {
+         /* forget it */
+      } else {
+         if (isT) {
+            putIReg(rD,
+                    binop(Iop_Or32,
+                          binop(Iop_And32, getIReg(rD), mkU32(0xFFFF)),
+                          mkU32(imm16 << 16)),
+                    condT, Ijk_Boring);
+            DIP("movt%s r%u, #0x%04x\n", nCC(INSN_COND), rD, imm16);
+            goto decode_success;
+         } else {
+            putIReg(rD, mkU32(imm16), condT, Ijk_Boring);
+            DIP("movw%s r%u, #0x%04x\n", nCC(INSN_COND), rD, imm16);
+            goto decode_success;
+         }
+      }
+      /* fall through */
+   }
+
+   /* ------------------- {u,s}xt{b,h}{,16} ------------------- */
+   if (BITS8(0,1,1,0,1, 0,0,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,0,0))
+       && BITS4(1,1,1,1) == INSN(19,16)
+       && BITS4(0,1,1,1) == INSN(7,4)
+       && BITS4(0,0, 0,0) == (INSN(11,8) & BITS4(0,0,1,1))) {
+      UInt subopc = INSN(27,20) & BITS8(0,0,0,0,0, 1,1,1);
+      if (subopc != BITS4(0,0,0,1) && subopc != BITS4(0,1,0,1)) {
+         Int    rot  = (INSN(11,8) >> 2) & 3;
+         UInt   rM   = INSN(3,0);
+         UInt   rD   = INSN(15,12);
+         IRTemp srcT = newTemp(Ity_I32);
+         IRTemp rotT = newTemp(Ity_I32);
+         IRTemp dstT = newTemp(Ity_I32);
+         HChar* nm   = "???";
+         assign(srcT, getIReg(rM));
+         assign(rotT, genROR32(srcT, 8 * rot)); /* 0, 8, 16 or 24 only */
+         switch (subopc) {
+            case BITS4(0,1,1,0): // UXTB
+               assign(dstT, unop(Iop_8Uto32, unop(Iop_32to8, mkexpr(rotT))));
+               nm = "uxtb";
+               break;
+            case BITS4(0,0,1,0): // SXTB
+               assign(dstT, unop(Iop_8Sto32, unop(Iop_32to8, mkexpr(rotT))));
+               nm = "sxtb";
+               break;
+            case BITS4(0,1,1,1): // UXTH
+               assign(dstT, unop(Iop_16Uto32, unop(Iop_32to16, mkexpr(rotT))));
+               nm = "uxth";
+               break;
+            case BITS4(0,0,1,1): // SXTH
+               assign(dstT, unop(Iop_16Sto32, unop(Iop_32to16, mkexpr(rotT))));
+               nm = "sxth";
+               break;
+            case BITS4(0,1,0,0): // UXTB16
+               assign(dstT, binop(Iop_And32, mkexpr(rotT), mkU32(0x00FF00FF)));
+               nm = "uxtb16";
+               break;
+            case BITS4(0,0,0,0): { // SXTB16
+               IRTemp lo32 = newTemp(Ity_I32);
+               IRTemp hi32 = newTemp(Ity_I32);
+               assign(lo32, binop(Iop_And32, mkexpr(rotT), mkU32(0xFF)));
+               assign(hi32, binop(Iop_Shr32, mkexpr(rotT), mkU8(16)));
+               assign(
+                  dstT,
+                  binop(Iop_Or32,
+                        binop(Iop_And32,
+                              unop(Iop_8Sto32,
+                                   unop(Iop_32to8, mkexpr(lo32))),
+                              mkU32(0xFFFF)),
+                        binop(Iop_Shl32,
+                              unop(Iop_8Sto32,
+                                   unop(Iop_32to8, mkexpr(hi32))),
+                              mkU8(16))
+               ));
+               nm = "uxtb16";
+               break;
+            }
+            default:
+               vassert(0); // guarded by "if" above
+         }
+         putIReg(rD, mkexpr(dstT), condT, Ijk_Boring);
+         DIP("%s%s r%u, r%u, ROR #%u\n", nm, nCC(INSN_COND), rD, rM, rot);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   /* ------------------- bfi, bfc ------------------- */
+   if (BITS8(0,1,1,1,1,1,0, 0) == (INSN(27,20) & BITS8(1,1,1,1,1,1,1,0))
+       && BITS4(0, 0,0,1) == (INSN(7,4) & BITS4(0,1,1,1))) {
+      UInt rD  = INSN(15,12);
+      UInt rN  = INSN(3,0);
+      UInt msb = (insn >> 16) & 0x1F; /* 20:16 */
+      UInt lsb = (insn >> 7) & 0x1F;  /* 11:7 */
+      if (rD == 15 || msb < lsb) {
+         /* undecodable; fall through */
+      } else {
+         IRTemp src    = newTemp(Ity_I32);
+         IRTemp olddst = newTemp(Ity_I32);
+         IRTemp newdst = newTemp(Ity_I32);
+         UInt   mask = 1 << (msb - lsb);
+         mask = (mask - 1) + mask;
+         vassert(mask != 0); // guaranteed by "msb < lsb" check above
+         mask <<= lsb;
+
+         assign(src, rN == 15 ? mkU32(0) : getIReg(rN));
+         assign(olddst, getIReg(rD));
+         assign(newdst,
+                binop(Iop_Or32,
+                   binop(Iop_And32,
+                         binop(Iop_Shl32, mkexpr(src), mkU8(lsb)), 
+                         mkU32(mask)),
+                   binop(Iop_And32,
+                         mkexpr(olddst),
+                         mkU32(~mask)))
+               );
+
+         putIReg(rD, mkexpr(newdst), condT, Ijk_Boring);
+
+         if (rN == 15) {
+            DIP("bfc%s r%u, #%u, #%u\n",
+                nCC(INSN_COND), rD, lsb, msb-lsb+1);
+         } else {
+            DIP("bfi%s r%u, r%u, #%u, #%u\n",
+                nCC(INSN_COND), rD, rN, lsb, msb-lsb+1);
+         }
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   /* ------------------- {u,s}bfx ------------------- */
+   if (BITS8(0,1,1,1,1,0,1,0) == (INSN(27,20) & BITS8(1,1,1,1,1,0,1,0))
+       && BITS4(0,1,0,1) == (INSN(7,4) & BITS4(0,1,1,1))) {
+      UInt rD  = INSN(15,12);
+      UInt rN  = INSN(3,0);
+      UInt wm1 = (insn >> 16) & 0x1F; /* 20:16 */
+      UInt lsb = (insn >> 7) & 0x1F;  /* 11:7 */
+      UInt msb = lsb + wm1;
+      UInt isU = (insn >> 22) & 1;    /* 22:22 */
+      if (rD == 15 || rN == 15 || msb >= 32) {
+         /* undecodable; fall through */
+      } else {
+         IRTemp src  = newTemp(Ity_I32);
+         IRTemp tmp  = newTemp(Ity_I32);
+         IRTemp res  = newTemp(Ity_I32);
+         UInt   mask = ((1 << wm1) - 1) + (1 << wm1);
+         vassert(msb >= 0 && msb <= 31);
+         vassert(mask != 0); // guaranteed by msb being in 0 .. 31 inclusive
+
+         assign(src, getIReg(rN));
+         assign(tmp, binop(Iop_And32,
+                           binop(Iop_Shr32, mkexpr(src), mkU8(lsb)),
+                           mkU32(mask)));
+         assign(res, binop(isU ? Iop_Shr32 : Iop_Sar32,
+                           binop(Iop_Shl32, mkexpr(tmp), mkU8(31-wm1)),
+                           mkU8(31-wm1)));
+
+         putIReg(rD, mkexpr(res), condT, Ijk_Boring);
+
+         DIP("%s%s r%u, r%u, #%u, #%u\n",
+             isU ? "ubfx" : "sbfx",
+             nCC(INSN_COND), rD, rN, lsb, wm1 + 1);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   /* ------------------- smul{b,t}{b,t} ------------- */
+   if (BITS8(0,0,0,1,0,1,1,0) == INSN(27,20)
+       && BITS4(0,0,0,0) == INSN(15,12)
+       && BITS4(1,0,0,0) == (INSN(7,4) & BITS4(1,0,0,1))) {
+      UInt rD  = INSN(19,16);
+      UInt rM  = INSN(11,8);
+      UInt rN  = INSN(3,0);
+      UInt bM = (insn >> 6) & 1;
+      UInt bN = (insn >> 5) & 1;
+      if (bN == 0 && bM == 1) goto decode_failure; //ATC
+      if (bN == 1 && bM == 0) goto decode_failure; //ATC
+      if (bN == 1 && bM == 1) goto decode_failure; //ATC
+      if (rD == 15 || rN == 15 || rM == 15) {
+         /* undecodable; fall through */
+      } else {
+         IRTemp srcL = newTemp(Ity_I32);
+         IRTemp srcR = newTemp(Ity_I32);
+         IRTemp res  = newTemp(Ity_I32);
+
+         /* Extract and sign extend the two 16-bit operands */
+         assign(srcL, binop(Iop_Sar32,
+                            binop(Iop_Shl32, getIReg(rN),
+                                             mkU8(bN ? 0 : 16)),
+                            mkU8(16)));
+         assign(srcR, binop(Iop_Sar32,
+                            binop(Iop_Shl32, getIReg(rM),
+                                             mkU8(bM ? 0 : 16)),
+                            mkU8(16)));
+
+         assign(res, binop(Iop_Mul32, mkexpr(srcL), mkexpr(srcR)));
+         putIReg(rD, mkexpr(res), condT, Ijk_Boring);
+
+         DIP("smul%c%c%s r%u, r%u, r%u\n",
+             bN ? 't' : 'b', bM ? 't' : 'b', nCC(INSN_COND), rD, rN, rM);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   /* --------------------- Load/store doubleword ------------- */
+   // LDRD STRD
+   /*                 31   27   23   19 15 11   7    3     # highest bit
+                        28   24   20 16 12    8    4    0
+      A5-36   1 | 16  cond 0001 U100 Rn Rd im4h 11S1 im4l
+      A5-38   1 | 32  cond 0001 U000 Rn Rd 0000 11S1 Rm
+      A5-40   2 | 16  cond 0001 U110 Rn Rd im4h 11S1 im4l
+      A5-42   2 | 32  cond 0001 U010 Rn Rd 0000 11S1 Rm
+      A5-44   3 | 16  cond 0000 U100 Rn Rd im4h 11S1 im4l
+      A5-46   3 | 32  cond 0000 U000 Rn Rd 0000 11S1 Rm
+   */
+   /* case coding:
+             1   at-ea               (access at ea)
+             2   at-ea-then-upd      (access at ea, then Rn = ea)
+             3   at-Rn-then-upd      (access at Rn, then Rn = ea)
+      ea coding
+             16  Rn +/- imm8
+             32  Rn +/- Rm
+   */
+   /* Quickly skip over all of this for hopefully most instructions */
+   if ((INSN(27,24) & BITS4(1,1,1,0)) != BITS4(0,0,0,0))
+      goto after_load_store_doubleword;
+
+   /* Check the "11S1" thing. */
+   if ((INSN(7,4) & BITS4(1,1,0,1)) != BITS4(1,1,0,1))
+      goto after_load_store_doubleword;
+
+   summary = 0;
+
+   /**/ if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(1,0,0)) {
+      summary = 1 | 16;
+   }
+   else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(0,0,0)) {
+      summary = 1 | 32;
+   }
+   else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(1,1,0)) {
+      summary = 2 | 16;
+   }
+   else if (INSN(27,24) == BITS4(0,0,0,1) && INSN(22,20) == BITS3(0,1,0)) {
+      summary = 2 | 32;
+   }
+   else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,20) == BITS3(1,0,0)) {
+      summary = 3 | 16;
+   }
+   else if (INSN(27,24) == BITS4(0,0,0,0) && INSN(22,20) == BITS3(0,0,0)) {
+      summary = 3 | 32;
+      goto decode_failure; //ATC
+   }
+   else goto after_load_store_doubleword;
+
+   { UInt rN   = (insn >> 16) & 0xF; /* 19:16 */
+     UInt rD   = (insn >> 12) & 0xF; /* 15:12 */
+     UInt rM   = (insn >> 0)  & 0xF; /*  3:0  */
+     UInt bU   = (insn >> 23) & 1;   /* 23 U=1 offset+, U=0 offset- */
+     UInt bS   = (insn >> 5) & 1;    /* S=1 store, S=0 load */
+     UInt imm8 = ((insn >> 4) & 0xF0) | (insn & 0xF); /* 11:8, 3:0 */
+
+     /* Require rD to be an even numbered register */
+     if ((rD & 1) != 0)
+        goto after_load_store_doubleword;
+
+     /* Require 11:8 == 0 for Rn +/- Rm cases */
+     if ((summary & 32) != 0 && (imm8 & 0xF0) != 0)
+        goto after_load_store_doubleword;
+
+     /* Skip some invalid cases, which would lead to two competing
+        updates to the same register, or which are otherwise
+        disallowed by the spec. */
+     switch (summary) {
+        case 1 | 16:
+           break;
+        case 1 | 32: 
+           if (rM == 15) goto after_load_store_doubleword;
+           break;
+        case 2 | 16: case 3 | 16:
+           if (rN == 15) goto after_load_store_doubleword;
+           if (bS == 0 && (rN == rD || rN == rD+1))
+              goto after_load_store_doubleword;
+           break;
+        case 2 | 32: case 3 | 32:
+           if (rM == 15) goto after_load_store_doubleword;
+           if (rN == 15) goto after_load_store_doubleword;
+           if (rN == rM) goto after_load_store_doubleword;
+           if (bS == 0 && (rN == rD || rN == rD+1))
+              goto after_load_store_doubleword;
+           break;
+        default:
+           vassert(0);
+     }
+
+     /* Now, we can't do a conditional load or store, since that very
+        likely will generate an exception.  So we have to take a side
+        exit at this point if the condition is false. */
+     if (condT != IRTemp_INVALID) {
+        mk_skip_to_next_if_cond_is_false( condT );
+        condT = IRTemp_INVALID;
+     }
+     /* Ok, now we're unconditional.  Do the load or store. */
+
+     /* compute the effective address.  Bind it to a tmp since we
+        may need to use it twice. */
+     IRExpr* eaE = NULL;
+     switch (summary & 0xF0) {
+        case 16:
+           eaE = mk_EA_reg_plusminus_imm8( rN, bU, imm8, dis_buf );
+           break;
+        case 32:
+           eaE = mk_EA_reg_plusminus_reg( rN, bU, rM, dis_buf );
+           break;
+     }
+     vassert(eaE);
+     IRTemp eaT = newTemp(Ity_I32);
+     assign(eaT, eaE);
+
+     /* get the old Rn value */
+     IRTemp rnT = newTemp(Ity_I32);
+     assign(rnT, getIReg(rN));
+
+     /* decide on the transfer address */
+     IRTemp taT = IRTemp_INVALID;
+     switch (summary & 0x0F) {
+        case 1: case 2: taT = eaT; break;
+        case 3:         taT = rnT; break;
+     }
+     vassert(taT != IRTemp_INVALID);
+
+     /* XXX deal with alignment constraints */
+     /* XXX: but the A8 doesn't seem to trap for misaligned loads, so,
+        ignore alignment issues for the time being. */
+
+     /* doubleword store  S 1
+        doubleword load   S 0
+     */
+     HChar* name = NULL;
+     /* generate the transfers */
+     if (bS == 1) { // doubleword store
+        storeLE( binop(Iop_Add32, mkexpr(taT), mkU32(0)), getIReg(rD+0) );
+        storeLE( binop(Iop_Add32, mkexpr(taT), mkU32(4)), getIReg(rD+1) );
+        name = "strd";
+     } else { // doubleword load
+        putIReg( rD+0,
+                 loadLE(Ity_I32, binop(Iop_Add32, mkexpr(taT), mkU32(0))),
+                 IRTemp_INVALID, Ijk_Boring );
+        putIReg( rD+1,
+                 loadLE(Ity_I32, binop(Iop_Add32, mkexpr(taT), mkU32(4))),
+                 IRTemp_INVALID, Ijk_Boring );
+        name = "ldrd";
+     }
+
+     /* Update Rn if necessary. */
+     switch (summary & 0x0F) {
+        case 2: case 3:
+           // should be assured by logic above:
+           if (bS == 0) {
+              vassert(rD+0 != rN); /* since we just wrote rD+0 */
+              vassert(rD+1 != rN); /* since we just wrote rD+1 */
+           }
+           putIReg( rN, mkexpr(eaT), IRTemp_INVALID, Ijk_Boring );
+           break;
+     }
+
+     switch (summary & 0x0F) {
+        case 1:  DIP("%s%s r%u, %s\n", name, nCC(INSN_COND), rD, dis_buf);
+                 break;
+        case 2:  DIP("%s%s r%u, %s! (at-EA-then-Rn=EA)\n",
+                     name, nCC(INSN_COND), rD, dis_buf);
+                 break;
+        case 3:  DIP("%s%s r%u, %s! (at-Rn-then-Rn=EA)\n",
+                     name, nCC(INSN_COND), rD, dis_buf);
+                 break;
+        default: vassert(0);
+     }
+
+     goto decode_success;
+   }
+
+  after_load_store_doubleword:
+
+   /* ------------------- sxtab ------------- */
+   if (BITS8(0,1,1,0,1,0,1,0) == INSN(27,20)
+       && BITS4(0,0,0,0) == (INSN(11,8) & BITS4(0,0,1,1))
+       && BITS4(0,1,1,1) == INSN(7,4)) {
+      UInt rN  = INSN(19,16);
+      UInt rD  = INSN(15,12);
+      UInt rM  = INSN(3,0);
+      UInt rot = (insn >> 10) & 3;
+      if (rN == 15/*it's SXTB*/ || rD == 15 || rM == 15) {
+         /* undecodable; fall through */
+      } else {
+         IRTemp srcL = newTemp(Ity_I32);
+         IRTemp srcR = newTemp(Ity_I32);
+         IRTemp res  = newTemp(Ity_I32);
+         assign(srcR, getIReg(rM));
+         assign(srcL, getIReg(rN));
+         assign(res,  binop(Iop_Add32,
+                            mkexpr(srcL),
+                            unop(Iop_8Sto32,
+                                 unop(Iop_32to8, 
+                                      genROR32(srcR, 8 * rot)))));
+         putIReg(rD, mkexpr(res), condT, Ijk_Boring);
+         DIP("sxtab%s r%u, r%u, r%u, ror #%u\n",
+             nCC(INSN_COND), rD, rN, rM, rot);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   /* ------------------- uxtah ------------- */
+   if (BITS8(0,1,1,0,1,1,1,1) == INSN(27,20)
+       && BITS4(0,0,0,0) == (INSN(11,8) & BITS4(0,0,1,1))
+       && BITS4(0,1,1,1) == INSN(7,4)) {
+      UInt rN  = INSN(19,16);
+      UInt rD  = INSN(15,12);
+      UInt rM  = INSN(3,0);
+      UInt rot = (insn >> 10) & 3;
+      if (rN == 15/*it's UXTH*/ || rD == 15 || rM == 15) {
+         /* undecodable; fall through */
+      } else {
+         IRTemp srcL = newTemp(Ity_I32);
+         IRTemp srcR = newTemp(Ity_I32);
+         IRTemp res  = newTemp(Ity_I32);
+         assign(srcR, getIReg(rM));
+         assign(srcL, getIReg(rN));
+         assign(res,  binop(Iop_Add32,
+                            mkexpr(srcL),
+                            unop(Iop_16Uto32,
+                                 unop(Iop_32to16, 
+                                      genROR32(srcR, 8 * rot)))));
+         putIReg(rD, mkexpr(res), condT, Ijk_Boring);
+
+         DIP("uxtah%s r%u, r%u, r%u, ror #%u\n",
+             nCC(INSN_COND), rD, rN, rM, rot);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   /* ----------------------------------------------------------- */
+   /* -- ARMv7 instructions                                    -- */
+   /* ----------------------------------------------------------- */
+
+   /* -------------- read CP15 TPIDRURO register ------------- */
+   /* mrc     p15, 0, r0, c13, c0, 3  up to
+      mrc     p15, 0, r14, c13, c0, 3
+   */
+   /* I don't know whether this is really v7-only.  But anyway, we
+      have to support it since arm-linux uses TPIDRURO as a thread
+      state register. */
+   if (0x0E1D0F70 == (insn & 0x0FFF0FFF)) {
+      UInt rD = INSN(15,12);
+      if (rD <= 14) {
+         /* skip r15, that's too stupid to handle */
+         putIReg(rD, IRExpr_Get(OFFB_TPIDRURO, Ity_I32),
+                     condT, Ijk_Boring);
+         DIP("mrc%s p15,0, r%u, c13, c0, 3\n", nCC(INSN_COND), rD);
+         goto decode_success;
+      }
+      /* fall through */
+   }
+
+   /* ----------------------------------------------------------- */
+   /* -- Undecodable                                           -- */
+   /* ----------------------------------------------------------- */
+
+   goto decode_failure;
+   /*NOTREACHED*/
+
+  decode_failure:
    /* All decode failures end up here. */
    vex_printf("disInstr(arm): unhandled instruction: "
-              "0x%x\n", theInstr);
-   vpanic("armToIR: unimplemented insn");
-   
-   } /* switch (opc) for the main (primary) opcode switch. */
-   
+              "0x%x\n", insn);
+   vex_printf("                 cond=%d(0x%x) 27:20=%u(0x%02x) "
+                                "4:4=%d "
+                                "3:0=%u(0x%x)\n",
+              (Int)INSN_COND, (UInt)INSN_COND,
+              (Int)INSN(27,20), (UInt)INSN(27,20),
+              (Int)INSN(4,4),
+              (Int)INSN(3,0), (UInt)INSN(3,0) );
+
+   /* Tell the dispatcher that this insn cannot be decoded, and so has
+      not been executed, and (is currently) the next to be executed.
+      R15 should be up-to-date since it made so at the start of each
+      insn, but nevertheless be paranoid and update it again right
+      now. */
+   vassert(0 == (guest_R15_curr_instr & 3));
+   llPutIReg( 15, mkU32(guest_R15_curr_instr) );
+   irsb->next     = mkU32(guest_R15_curr_instr);
+   irsb->jumpkind = Ijk_NoDecode;
+   dres.whatNext  = Dis_StopHere;
+   dres.len       = 0;
+   return dres;
+
   decode_success:
    /* All decode successes end up here. */
-//   vex_printf("disInstr(arm): success");
    DIP("\n");
-   
-   *size = 4;
-   return whatNext;
+
+   vassert(dres.len == 4 || dres.len == 20);
+
+   /* Now then.  Do we have an implicit jump to r15 to deal with? */
+   if (r15written) {
+      /* If we get jump to deal with, we assume that there's been no
+         other competing branch stuff previously generated for this
+         insn.  That's reasonable, in the sense that the ARM insn set
+         appears to declare as "Unpredictable" any instruction which
+         generates more than one possible new value for r15.  Hence
+         just assert.  The decoders themselves should check against
+         all such instructions which are thusly Unpredictable, and
+         decline to decode them.  Hence we should never get here if we
+         have competing new values for r15, and hence it is safe to
+         assert here. */
+      vassert(dres.whatNext == Dis_Continue);
+      vassert(irsb->next == NULL);
+      vassert(irsb->jumpkind = Ijk_Boring);
+      /* If r15 is unconditionally written, terminate the block by
+         jumping to it.  If it's conditionally written, still
+         terminate the block (a shame, but we can't do side exits to
+         arbitrary destinations), but first jump to the next
+         instruction if the condition doesn't hold. */
+      /* We can't use getIReg(15) to get the destination, since that
+         will produce r15+8, which isn't what we want.  Must use
+         llGetIReg(15) instead. */
+      if (r15guard == IRTemp_INVALID) {
+         /* unconditional */
+      } else {
+         /* conditional */
+         stmt( IRStmt_Exit( unop(Iop_32to1,
+                                 binop(Iop_Xor32,
+                                       mkexpr(r15guard), mkU32(1))),
+                            r15kind,
+                            IRConst_U32(guest_R15_curr_instr + 4)
+         ));
+      }
+      irsb->next     = llGetIReg(15);
+      irsb->jumpkind = r15kind;
+      dres.whatNext  = Dis_StopHere;
+   }
+
+   return dres;
+
+#  undef INSN
+#  undef INSN_COND
 }
 
 #undef DIP
 #undef DIS
 
+
+/*------------------------------------------------------------*/
+/*--- Top-level fn                                         ---*/
+/*------------------------------------------------------------*/
+
+/* Disassemble a single instruction into IR.  The instruction
+   is located in host memory at &guest_code[delta]. */
+
+DisResult disInstr_ARM ( IRSB*        irsb_IN,
+                         Bool         put_IP,
+                         Bool         (*resteerOkFn) ( void*, Addr64 ),
+                         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 == VexArchARM);
+   irsb                 = irsb_IN;
+   host_is_bigendian    = host_bigendian_IN;
+   guest_R15_curr_instr = (Addr32)guest_IP;
+
+   dres = disInstr_ARM_WRK ( put_IP, resteerOkFn, callback_opaque,
+                             &guest_code_IN[delta],
+                             archinfo, abiinfo );
+
+   return dres;
+}
+
+/* Test program for the conversion of IRCmpF64Result values to VFP
+   nzcv values.  See handling of FCMPD et al above. */
+/*
+UInt foo ( UInt x )
+{
+   UInt ix    = ((x >> 5) & 3) | (x & 1);
+   UInt termL = (((((ix ^ 1) << 30) - 1) >> 29) + 1);
+   UInt termR = (ix & (ix >> 1) & 1);
+   return termL  -  termR;
+}
+
+void try ( char* s, UInt ir, UInt req )
+{
+   UInt act = foo(ir);
+   printf("%s 0x%02x -> req %d%d%d%d act %d%d%d%d (0x%x)\n",
+          s, ir, (req >> 3) & 1, (req >> 2) & 1, 
+                 (req >> 1) & 1, (req >> 0) & 1, 
+                 (act >> 3) & 1, (act >> 2) & 1, 
+                 (act >> 1) & 1, (act >> 0) & 1, act);
+
+}
+
+int main ( void )
+{
+   printf("\n");
+   try("UN", 0x45, 0b0011);
+   try("LT", 0x01, 0b1000);
+   try("GT", 0x00, 0b0010);
+   try("EQ", 0x40, 0b0110);
+   printf("\n");
+   return 0;
+}
+*/
+
 /*--------------------------------------------------------------------*/
 /*--- end                                         guest_arm_toIR.c ---*/
 /*--------------------------------------------------------------------*/
index eda971d9d60050c443041c40d2d7a87d7822ea57..24e7dbb722424f94a8beb5ac4ea2778c19f49164 100644 (file)
@@ -6544,7 +6544,7 @@ static Bool dis_fp_round ( UInt theInstr )
    case 0x00E: // fctiw (Float Conv to Int, PPC32 p404)
       DIP("fctiw%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
       assign( r_tmp32,
-              binop(Iop_F64toI32, rm, mkexpr(frB)) );
+              binop(Iop_F64toI32S, rm, mkexpr(frB)) );
       assign( frD, unop( Iop_ReinterpI64asF64,
                          unop( Iop_32Uto64, mkexpr(r_tmp32))));
       /* FPRF is undefined after fctiw.  Leave unchanged. */
@@ -6554,7 +6554,7 @@ static Bool dis_fp_round ( UInt theInstr )
    case 0x00F: // fctiwz (Float Conv to Int, Round to Zero, PPC32 p405)
       DIP("fctiwz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
       assign( r_tmp32, 
-              binop(Iop_F64toI32, mkU32(Irrm_ZERO), mkexpr(frB) ));
+              binop(Iop_F64toI32S, mkU32(Irrm_ZERO), mkexpr(frB) ));
       assign( frD, unop( Iop_ReinterpI64asF64,
                          unop( Iop_32Uto64, mkexpr(r_tmp32))));
       /* FPRF is undefined after fctiwz.  Leave unchanged. */
@@ -6564,7 +6564,7 @@ static Bool dis_fp_round ( UInt theInstr )
    case 0x32E: // fctid (Float Conv to Int DWord, PPC64 p437)
       DIP("fctid%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
       assign( r_tmp64,
-              binop(Iop_F64toI64, rm, mkexpr(frB)) );
+              binop(Iop_F64toI64S, rm, mkexpr(frB)) );
       assign( frD, unop( Iop_ReinterpI64asF64, mkexpr(r_tmp64)) );
       /* FPRF is undefined after fctid.  Leave unchanged. */
       set_FPRF = False;
@@ -6573,7 +6573,7 @@ static Bool dis_fp_round ( UInt theInstr )
    case 0x32F: // fctidz (Float Conv to Int DWord, Round to Zero, PPC64 p437)
       DIP("fctidz%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
       assign( r_tmp64, 
-              binop(Iop_F64toI64, mkU32(Irrm_ZERO), mkexpr(frB)) );
+              binop(Iop_F64toI64S, mkU32(Irrm_ZERO), mkexpr(frB)) );
       assign( frD, unop( Iop_ReinterpI64asF64, mkexpr(r_tmp64)) );
       /* FPRF is undefined after fctidz.  Leave unchanged. */
       set_FPRF = False;
@@ -6583,7 +6583,7 @@ static Bool dis_fp_round ( UInt theInstr )
       DIP("fcfid%s fr%u,fr%u\n", flag_rC ? ".":"", frD_addr, frB_addr);
       assign( r_tmp64, unop( Iop_ReinterpF64asI64, mkexpr(frB)) );
       assign( frD, 
-              binop(Iop_I64toF64, rm, mkexpr(r_tmp64)) );
+              binop(Iop_I64StoF64, rm, mkexpr(r_tmp64)) );
       break;
 
    default:
index b5f462d32253fa943153a220e5de5f60f476011e..47e8d61a62ca9089810233eafaae8d05459cbb76 100644 (file)
    only taken if the CAS fails, that is, the location is contended,
    which is relatively unlikely.
 
+   XXXX: Nov 2009: handling of SWP on ARM suffers from the same
+   problem.
+
    Note also, the test for CAS success vs failure is done using
    Iop_CasCmp{EQ,NE}{8,16,32,64} rather than the ordinary
    Iop_Cmp{EQ,NE} equivalents.  This is so as to tell Memcheck that it
@@ -4380,7 +4383,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
                           binop(Iop_Shl32, 
                                 binop(Iop_CmpF64, 
                                       get_ST(0),
-                                      unop(Iop_I32toF64, 
+                                      unop(Iop_I32StoF64, 
                                            loadLE(Ity_I32,mkexpr(addr)))),
                                 mkU8(8)),
                           mkU32(0x4500)
@@ -4395,7 +4398,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
                           binop(Iop_Shl32, 
                                 binop(Iop_CmpF64, 
                                       get_ST(0),
-                                      unop(Iop_I32toF64, 
+                                      unop(Iop_I32StoF64, 
                                            loadLE(Ity_I32,mkexpr(addr)))),
                                 mkU8(8)),
                           mkU32(0x4500)
@@ -4428,7 +4431,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
                   triop(fop, 
                         get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
                         get_ST(0),
-                        unop(Iop_I32toF64,
+                        unop(Iop_I32StoF64,
                              loadLE(Ity_I32, mkexpr(addr)))));
                break;
 
@@ -4436,7 +4439,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
                put_ST_UNCHECKED(0, 
                   triop(fop, 
                         get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
-                        unop(Iop_I32toF64,
+                        unop(Iop_I32StoF64,
                              loadLE(Ity_I32, mkexpr(addr))),
                         get_ST(0)));
                break;
@@ -4528,27 +4531,27 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
             case 0: /* FILD m32int */
                DIP("fildl %s\n", dis_buf);
                fp_push();
-               put_ST(0, unop(Iop_I32toF64,
+               put_ST(0, unop(Iop_I32StoF64,
                               loadLE(Ity_I32, mkexpr(addr))));
                break;
 
             case 1: /* FISTTPL m32 (SSE3) */
                DIP("fisttpl %s\n", dis_buf);
                storeLE( mkexpr(addr), 
-                        binop(Iop_F64toI32, mkU32(Irrm_ZERO), get_ST(0)) );
+                        binop(Iop_F64toI32S, mkU32(Irrm_ZERO), get_ST(0)) );
                fp_pop();
                break;
 
             case 2: /* FIST m32 */
                DIP("fistl %s\n", dis_buf);
                storeLE( mkexpr(addr), 
-                        binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
+                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
                break;
 
             case 3: /* FISTP m32 */
                DIP("fistpl %s\n", dis_buf);
                storeLE( mkexpr(addr), 
-                        binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) );
+                        binop(Iop_F64toI32S, get_roundingmode(), get_ST(0)) );
                fp_pop();
                break;
 
@@ -4844,7 +4847,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
             case 1: /* FISTTPQ m64 (SSE3) */
                DIP("fistppll %s\n", dis_buf);
                storeLE( mkexpr(addr), 
-                        binop(Iop_F64toI64, mkU32(Irrm_ZERO), get_ST(0)) );
+                        binop(Iop_F64toI64S, mkU32(Irrm_ZERO), get_ST(0)) );
                fp_pop();
                break;
 
@@ -5069,7 +5072,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
                           binop(Iop_Shl32, 
                                 binop(Iop_CmpF64, 
                                       get_ST(0),
-                                      unop(Iop_I32toF64, 
+                                      unop(Iop_I32StoF64, 
                                          unop(Iop_16Sto32,
                                            loadLE(Ity_I16,mkexpr(addr))))),
                                 mkU8(8)),
@@ -5085,7 +5088,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
                           binop(Iop_Shl32, 
                                 binop(Iop_CmpF64, 
                                       get_ST(0),
-                                      unop(Iop_I32toF64, 
+                                      unop(Iop_I32StoF64, 
                                          unop(Iop_16Sto32,
                                               loadLE(Ity_I16,mkexpr(addr))))),
                                 mkU8(8)),
@@ -5119,7 +5122,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
                   triop(fop, 
                         get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
                         get_ST(0),
-                        unop(Iop_I32toF64,
+                        unop(Iop_I32StoF64,
                              unop(Iop_16Sto32, 
                                   loadLE(Ity_I16, mkexpr(addr))))));
                break;
@@ -5128,7 +5131,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
                put_ST_UNCHECKED(0, 
                   triop(fop, 
                         get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */
-                        unop(Iop_I32toF64,
+                        unop(Iop_I32StoF64,
                              unop(Iop_16Sto32, 
                                   loadLE(Ity_I16, mkexpr(addr)))),
                         get_ST(0)));
@@ -5206,7 +5209,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
             case 0: /* FILD m16int */
                DIP("fildw %s\n", dis_buf);
                fp_push();
-               put_ST(0, unop(Iop_I32toF64,
+               put_ST(0, unop(Iop_I32StoF64,
                               unop(Iop_16Sto32,
                                    loadLE(Ity_I16, mkexpr(addr)))));
                break;
@@ -5214,27 +5217,27 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
             case 1: /* FISTTPS m16 (SSE3) */
                DIP("fisttps %s\n", dis_buf);
                storeLE( mkexpr(addr), 
-                        binop(Iop_F64toI16, mkU32(Irrm_ZERO), get_ST(0)) );
+                        binop(Iop_F64toI16S, mkU32(Irrm_ZERO), get_ST(0)) );
                fp_pop();
                break;
 
             case 2: /* FIST m16 */
                DIP("fistp %s\n", dis_buf);
                storeLE( mkexpr(addr), 
-                        binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
+                        binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
                break;
 
             case 3: /* FISTP m16 */
                DIP("fistps %s\n", dis_buf);
                storeLE( mkexpr(addr), 
-                        binop(Iop_F64toI16, get_roundingmode(), get_ST(0)) );
+                        binop(Iop_F64toI16S, get_roundingmode(), get_ST(0)) );
                fp_pop();
                break;
 
             case 5: /* FILD m64 */
                DIP("fildll %s\n", dis_buf);
                fp_push();
-               put_ST(0, binop(Iop_I64toF64,
+               put_ST(0, binop(Iop_I64StoF64,
                                get_roundingmode(),
                                loadLE(Ity_I64, mkexpr(addr))));
                break;
@@ -5242,7 +5245,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
             case 7: /* FISTP m64 */
                DIP("fistpll %s\n", dis_buf);
                storeLE( mkexpr(addr), 
-                        binop(Iop_F64toI64, get_roundingmode(), get_ST(0)) );
+                        binop(Iop_F64toI64S, get_roundingmode(), get_ST(0)) );
                fp_pop();
                break;
 
@@ -8266,14 +8269,14 @@ DisResult disInstr_X86_WRK (
          gregOfRM(modrm), 0,
          binop(Iop_F64toF32, 
                mkexpr(rmode),
-               unop(Iop_I32toF64, 
+               unop(Iop_I32StoF64, 
                     unop(Iop_64to32, mkexpr(arg64)) )) );
 
       putXMMRegLane32F(
          gregOfRM(modrm), 1, 
          binop(Iop_F64toF32, 
                mkexpr(rmode),
-               unop(Iop_I32toF64,
+               unop(Iop_I32StoF64,
                     unop(Iop_64HIto32, mkexpr(arg64)) )) );
 
       goto decode_success;
@@ -8306,7 +8309,7 @@ DisResult disInstr_X86_WRK (
          gregOfRM(modrm), 0,
          binop(Iop_F64toF32,
                mkexpr(rmode),
-               unop(Iop_I32toF64, mkexpr(arg32)) ) );
+               unop(Iop_I32StoF64, mkexpr(arg32)) ) );
 
       goto decode_success;
    }
@@ -8353,10 +8356,10 @@ DisResult disInstr_X86_WRK (
       assign( 
          dst64,
          binop( Iop_32HLto64,
-                binop( Iop_F64toI32, 
+                binop( Iop_F64toI32S
                        mkexpr(rmode), 
                        unop( Iop_F32toF64, mkexpr(f32hi) ) ),
-                binop( Iop_F64toI32, 
+                binop( Iop_F64toI32S
                        mkexpr(rmode), 
                        unop( Iop_F32toF64, mkexpr(f32lo) ) )
               )
@@ -8400,7 +8403,7 @@ DisResult disInstr_X86_WRK (
       }
 
       putIReg(4, gregOfRM(modrm),
-                 binop( Iop_F64toI32, 
+                 binop( Iop_F64toI32S
                         mkexpr(rmode), 
                         unop( Iop_F32toF64, mkexpr(f32lo) ) )
       );
@@ -9311,12 +9314,12 @@ DisResult disInstr_X86_WRK (
 
       putXMMRegLane64F( 
          gregOfRM(modrm), 0,
-         unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)))
+         unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)))
       );
 
       putXMMRegLane64F(
          gregOfRM(modrm), 1, 
-         unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)))
+         unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)))
       );
 
       goto decode_success;
@@ -9347,7 +9350,7 @@ DisResult disInstr_X86_WRK (
 
 #     define CVT(_t)  binop( Iop_F64toF32,                    \
                              mkexpr(rmode),                   \
-                             unop(Iop_I32toF64,mkexpr(_t)))
+                             unop(Iop_I32StoF64,mkexpr(_t)))
       
       putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
       putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
@@ -9388,7 +9391,7 @@ DisResult disInstr_X86_WRK (
       assign( t1, unop(Iop_ReinterpI64asF64, 
                        unop(Iop_V128HIto64, mkexpr(argV))) );
       
-#     define CVT(_t)  binop( Iop_F64toI32                   \
+#     define CVT(_t)  binop( Iop_F64toI32S,                   \
                              mkexpr(rmode),                   \
                              mkexpr(_t) )
       
@@ -9444,8 +9447,8 @@ DisResult disInstr_X86_WRK (
       assign( 
          dst64,
          binop( Iop_32HLto64,
-                binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64hi) ),
-                binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo) )
+                binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64hi) ),
+                binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo) )
               )
       );
 
@@ -9520,12 +9523,12 @@ DisResult disInstr_X86_WRK (
 
       putXMMRegLane64F( 
          gregOfRM(modrm), 0,
-         unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)) )
+         unop(Iop_I32StoF64, unop(Iop_64to32, mkexpr(arg64)) )
       );
 
       putXMMRegLane64F( 
          gregOfRM(modrm), 1,
-         unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)) )
+         unop(Iop_I32StoF64, unop(Iop_64HIto32, mkexpr(arg64)) )
       );
 
       goto decode_success;
@@ -9557,7 +9560,7 @@ DisResult disInstr_X86_WRK (
       /* This is less than ideal.  If it turns out to be a performance
         bottleneck it can be improved. */
 #     define CVT(_t)                            \
-        binop( Iop_F64toI32                   \
+        binop( Iop_F64toI32S,                   \
                mkexpr(rmode),                   \
                unop( Iop_F32toF64,              \
                      unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
@@ -9637,7 +9640,7 @@ DisResult disInstr_X86_WRK (
       }
 
       putIReg(4, gregOfRM(modrm),
-                 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo)) );
+                 binop( Iop_F64toI32S, mkexpr(rmode), mkexpr(f64lo)) );
 
       goto decode_success;
    }
@@ -9694,7 +9697,7 @@ DisResult disInstr_X86_WRK (
 
       putXMMRegLane64F( 
          gregOfRM(modrm), 0,
-         unop(Iop_I32toF64, mkexpr(arg32)) );
+         unop(Iop_I32StoF64, mkexpr(arg32)) );
 
       goto decode_success;
    }
@@ -9754,7 +9757,7 @@ DisResult disInstr_X86_WRK (
       assign( t1, unop(Iop_ReinterpI64asF64, 
                        unop(Iop_V128HIto64, mkexpr(argV))) );
       
-#     define CVT(_t)  binop( Iop_F64toI32                   \
+#     define CVT(_t)  binop( Iop_F64toI32S,                   \
                              mkexpr(rmode),                   \
                              mkexpr(_t) )
       
@@ -9795,7 +9798,7 @@ DisResult disInstr_X86_WRK (
       /* This is less than ideal.  If it turns out to be a performance
         bottleneck it can be improved. */
 #     define CVT(_t)                            \
-        binop( Iop_F64toI32                   \
+        binop( Iop_F64toI32S,                   \
                mkexpr(rmode),                   \
                unop( Iop_F32toF64,              \
                      unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
index db65dc04f70766d2485d714a1c9f030cba850585..900407e29546694e0d512d30b47bab404e13b22f 100644 (file)
@@ -1280,9 +1280,9 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
          return dst;
       }
 
-      if (e->Iex.Binop.op == Iop_F64toI32
-          || e->Iex.Binop.op == Iop_F64toI64) {
-         Int  szD = e->Iex.Binop.op==Iop_F64toI32 ? 4 : 8;
+      if (e->Iex.Binop.op == Iop_F64toI32S
+          || e->Iex.Binop.op == Iop_F64toI64S) {
+         Int  szD = e->Iex.Binop.op==Iop_F64toI32S ? 4 : 8;
          HReg rf  = iselDblExpr(env, e->Iex.Binop.arg2);
          HReg dst = newVRegI(env);
          set_SSE_rounding_mode( env, e->Iex.Binop.arg1 );
@@ -3002,7 +3002,7 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
       return dst;
    }
 
-   if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64toF64) {
+   if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64StoF64) {
       HReg dst = newVRegV(env);
       HReg src = iselIntExpr_R(env, e->Iex.Binop.arg2);
       set_SSE_rounding_mode( env, e->Iex.Binop.arg1 );
@@ -3011,7 +3011,7 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
       return dst;
    }
 
-   if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_I32toF64) {
+   if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_I32StoF64) {
       HReg dst = newVRegV(env);
       HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
       set_SSE_rounding_default( env );
index 2735b2771fa09bba344c57ca26c8f6116a74219e..75a5870a0915c87423ff1749ca7db616daf56525 100644 (file)
    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"
    There are 16 general purpose regs.
 */
 
-
-/* --------- Registers. --------- */
-
 void ppHRegARM ( HReg reg )  {
    Int r;
-   static HChar* ireg32_names[16] 
-     = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8",
-        "r9", "r10", "r11", "r12", "r13", "r14", "r15" };
-
    /* Be generic for all virtual regs. */
    if (hregIsVirtual(reg)) {
       ppHReg(reg);
@@ -79,49 +67,104 @@ void ppHRegARM ( HReg reg )  {
       case HRcInt32:
          r = hregNumber(reg);
          vassert(r >= 0 && r < 16);
-         vex_printf("%s", ireg32_names[r]);
+         vex_printf("r%d", r);
+         return;
+      case HRcFlt64:
+         r = hregNumber(reg);
+         vassert(r >= 0 && r < 16);
+         vex_printf("d%d", r);
+         return;
+      case HRcFlt32:
+         r = hregNumber(reg);
+         vassert(r >= 0 && r < 32);
+         vex_printf("s%d", r);
          return;
       default:
          vpanic("ppHRegARM");
    }
 }
 
-HReg hregARM_R0 ( void ) { return mkHReg(0, HRcInt32, False); }
-HReg hregARM_R1 ( void ) { return mkHReg(1, HRcInt32, False); }
-HReg hregARM_R2 ( void ) { return mkHReg(2, HRcInt32, False); }
-HReg hregARM_R3 ( void ) { return mkHReg(3, HRcInt32, False); }
-HReg hregARM_R4 ( void ) { return mkHReg(4, HRcInt32, False); }
-HReg hregARM_R5 ( void ) { return mkHReg(5, HRcInt32, False); }
-HReg hregARM_R6 ( void ) { return mkHReg(6, HRcInt32, False); }
-HReg hregARM_R7 ( void ) { return mkHReg(7, HRcInt32, False); }
-HReg hregARM_R8 ( void ) { return mkHReg(8, HRcInt32, False); }
-HReg hregARM_R9 ( void ) { return mkHReg(9, HRcInt32, False); }
+HReg hregARM_R0  ( void ) { return mkHReg(0,  HRcInt32, False); }
+HReg hregARM_R1  ( void ) { return mkHReg(1,  HRcInt32, False); }
+HReg hregARM_R2  ( void ) { return mkHReg(2,  HRcInt32, False); }
+HReg hregARM_R3  ( void ) { return mkHReg(3,  HRcInt32, False); }
+HReg hregARM_R4  ( void ) { return mkHReg(4,  HRcInt32, False); }
+HReg hregARM_R5  ( void ) { return mkHReg(5,  HRcInt32, False); }
+HReg hregARM_R6  ( void ) { return mkHReg(6,  HRcInt32, False); }
+HReg hregARM_R7  ( void ) { return mkHReg(7,  HRcInt32, False); }
+HReg hregARM_R8  ( void ) { return mkHReg(8,  HRcInt32, False); }
+HReg hregARM_R9  ( void ) { return mkHReg(9,  HRcInt32, False); }
 HReg hregARM_R10 ( void ) { return mkHReg(10, HRcInt32, False); }
 HReg hregARM_R11 ( void ) { return mkHReg(11, HRcInt32, False); }
 HReg hregARM_R12 ( void ) { return mkHReg(12, HRcInt32, False); }
 HReg hregARM_R13 ( void ) { return mkHReg(13, HRcInt32, False); }
 HReg hregARM_R14 ( void ) { return mkHReg(14, HRcInt32, False); }
 HReg hregARM_R15 ( void ) { return mkHReg(15, HRcInt32, False); }
-
-void getAllocableRegs_ARM ( Int* nregs, HReg** arr ) {
-   *nregs = 20;
+HReg hregARM_D8  ( void ) { return mkHReg(8,  HRcFlt64, False); }
+HReg hregARM_D9  ( void ) { return mkHReg(9,  HRcFlt64, False); }
+HReg hregARM_D10 ( void ) { return mkHReg(10, HRcFlt64, False); }
+HReg hregARM_D11 ( void ) { return mkHReg(11, HRcFlt64, False); }
+HReg hregARM_D12 ( void ) { return mkHReg(12, HRcFlt64, False); }
+HReg hregARM_S26 ( void ) { return mkHReg(26, HRcFlt32, False); }
+HReg hregARM_S27 ( void ) { return mkHReg(27, HRcFlt32, False); }
+HReg hregARM_S28 ( void ) { return mkHReg(28, HRcFlt32, False); }
+HReg hregARM_S29 ( void ) { return mkHReg(29, HRcFlt32, False); }
+HReg hregARM_S30 ( void ) { return mkHReg(30, HRcFlt32, False); }
+
+void getAllocableRegs_ARM ( Int* nregs, HReg** arr )
+{
+   Int i = 0;
+   *nregs = 21;
    *arr = LibVEX_Alloc(*nregs * sizeof(HReg));
-   (*arr)[0] = hregARM_R0();
-   (*arr)[1] = hregARM_R1();
-   (*arr)[2] = hregARM_R2();
-   (*arr)[3] = hregARM_R3();
-   (*arr)[4] = hregARM_R4();
-   (*arr)[5] = hregARM_R5();
-   (*arr)[6] = hregARM_R6();
-   (*arr)[7] = hregARM_R7();
-   (*arr)[8] = hregARM_R8();
-   (*arr)[9] = hregARM_R9();
-   (*arr)[10] = hregARM_R10();
-   (*arr)[11] = hregARM_R11();
-   (*arr)[12] = hregARM_R12();
-   (*arr)[13] = hregARM_R13();
-   (*arr)[14] = hregARM_R14();
-   (*arr)[15] = hregARM_R15();
+   // callee saves ones are listed first, since we prefer them
+   // if they're available
+   (*arr)[i++] = hregARM_R4();
+   (*arr)[i++] = hregARM_R5();
+   (*arr)[i++] = hregARM_R6();
+   (*arr)[i++] = hregARM_R7();
+   (*arr)[i++] = hregARM_R10();
+   (*arr)[i++] = hregARM_R11();
+   // otherwise we'll have to slum it out with caller-saves ones
+   (*arr)[i++] = hregARM_R0();
+   (*arr)[i++] = hregARM_R1();
+   (*arr)[i++] = hregARM_R2();
+   (*arr)[i++] = hregARM_R3();
+   (*arr)[i++] = hregARM_R9();
+   // FP hreegisters.  Note: these are all callee-save.  Yay!
+   // Hence we don't need to mention them as trashed in
+   // getHRegUsage for ARMInstr_Call.
+   (*arr)[i++] = hregARM_D8();
+   (*arr)[i++] = hregARM_D9();
+   (*arr)[i++] = hregARM_D10();
+   (*arr)[i++] = hregARM_D11();
+   (*arr)[i++] = hregARM_D12();
+   (*arr)[i++] = hregARM_S26();
+   (*arr)[i++] = hregARM_S27();
+   (*arr)[i++] = hregARM_S28();
+   (*arr)[i++] = hregARM_S29();
+   (*arr)[i++] = hregARM_S30();
+   // unavail: r8 as GSP
+   // r12 'cos we're not sure what it's for
+   // r13 as SP
+   // r14 as LR
+   // r15 as PC
+   //
+   // All in all, we have 11 allocatable integer registers:
+   // 0 1 2 3 4 5 6 7 9 10 11 plus r8 dedicated as GSP.
+   // 12 13 14 and 15 are not under the allocator's control.
+   //
+   // Hence for the allocatable registers we have:
+   //
+   // callee-saved: 4 5 6 7 (8) 9 10 11
+   // caller-saved: 0 1 2 3
+   // Note 9 is ambiguous: the base EABI does not give an e/r-saved
+   // designation for it, but the Linux instantiation of the ABI
+   // specifies it as callee-saved.
+   //
+   // If the set of available registers changes or if the e/r status
+   // changes, be sure to re-check/sync the definition of
+   // getHRegUsage for ARMInstr_Call too.
+   vassert(i == *nregs);
 }
 
 
@@ -130,578 +173,1362 @@ void getAllocableRegs_ARM ( Int* nregs, HReg** arr ) {
 
 HChar* showARMCondCode ( ARMCondCode cond ) {
    switch (cond) {
-       case ARMccEQ:    return "eq";
-       case ARMccNE:    return "ne";
-       case ARMccHS:    return "hs";
-       case ARMccLO:    return "lo";
-       case ARMccMI:    return "mi";
-       case ARMccPL:    return "pl";
-       case ARMccVS:    return "vs";
-       case ARMccVC:    return "vc";
-       case ARMccHI:    return "hi";
-       case ARMccLS:    return "ls";
-       case ARMccGE:    return "ge";
-       case ARMccLT:    return "lt";
-       case ARMccGT:    return "gt";
-       case ARMccLE:    return "le";
-       case ARMccAL:    return "al"; // default
-       case ARMccNV:    return "nv";
+       case ARMcc_EQ:  return "eq";
+       case ARMcc_NE:  return "ne";
+       case ARMcc_HS:  return "hs";
+       case ARMcc_LO:  return "lo";
+       case ARMcc_MI:  return "mi";
+       case ARMcc_PL:  return "pl";
+       case ARMcc_VS:  return "vs";
+       case ARMcc_VC:  return "vc";
+       case ARMcc_HI:  return "hi";
+       case ARMcc_LS:  return "ls";
+       case ARMcc_GE:  return "ge";
+       case ARMcc_LT:  return "lt";
+       case ARMcc_GT:  return "gt";
+       case ARMcc_LE:  return "le";
+       case ARMcc_AL:  return "al"; // default
+       case ARMcc_NV:  return "nv";
        default: vpanic("showARMCondCode");
    }
 }
 
 
+/* --------- Mem AModes: Addressing Mode 1 --------- */
 
-
-/* --------- ARMAMode1: memory address expressions. --------- */
-
-ARMAMode1* ARMAMode1_I12A ( ARMImm12A imm ) {
-    ARMAMode1* am = LibVEX_Alloc(sizeof(ARMAMode1));
-    am->tag = ARMam1_I12A;
-    am->ARMam1.I12A.imm = imm;
-    return am;
+ARMAMode1* ARMAMode1_RI  ( HReg reg, Int simm13 ) {
+   ARMAMode1* am        = LibVEX_Alloc(sizeof(ARMAMode1));
+   am->tag              = ARMam1_RI;
+   am->ARMam1.RI.reg    = reg;
+   am->ARMam1.RI.simm13 = simm13;
+   vassert(-4095 <= simm13 && simm13 <= 4095);
+   return am;
 }
-ARMAMode1* ARMAMode1_ShlI ( HReg Rm, ARMImm5 imm ) {
-    ARMAMode1* am = LibVEX_Alloc(sizeof(ARMAMode1));
-    am->tag = ARMam1_ShlI;
-    am->ARMam1.ShlI.Rm = Rm;
-    am->ARMam1.ShlI.imm = imm;
-    return am;
+ARMAMode1* ARMAMode1_RRS ( HReg base, HReg index, UInt shift ) {
+   ARMAMode1* am        = LibVEX_Alloc(sizeof(ARMAMode1));
+   am->tag              = ARMam1_RRS;
+   am->ARMam1.RRS.base  = base;
+   am->ARMam1.RRS.index = index;
+   am->ARMam1.RRS.shift = shift;
+   vassert(0 <= shift && shift <= 3);
+   return am;
 }
-ARMAMode1* ARMAMode1_ShrI ( HReg Rm, ARMImm5 imm ) {
-    ARMAMode1* am = LibVEX_Alloc(sizeof(ARMAMode1));
-    am->tag = ARMam1_ShrI;
-    am->ARMam1.ShrI.Rm = Rm;
-    am->ARMam1.ShrI.imm = imm;
-    return am;
+
+void ppARMAMode1 ( ARMAMode1* am ) {
+   switch (am->tag) {
+      case ARMam1_RI:
+         vex_printf("%d(", am->ARMam1.RI.simm13);
+         ppHRegARM(am->ARMam1.RI.reg);
+         vex_printf(")");
+         break;
+      case ARMam1_RRS:
+         vex_printf("(");
+         ppHRegARM(am->ARMam1.RRS.base);
+         vex_printf(",");
+         ppHRegARM(am->ARMam1.RRS.index);
+         vex_printf(",%u)", am->ARMam1.RRS.shift);
+         break;
+      default:
+         vassert(0);
+   }
 }
-ARMAMode1* ARMAMode1_SarI ( HReg Rm, ARMImm5 imm ) {
-    ARMAMode1* am = LibVEX_Alloc(sizeof(ARMAMode1));
-    am->tag = ARMam1_SarI;
-    am->ARMam1.SarI.Rm = Rm;
-    am->ARMam1.SarI.imm = imm;
-    return am;
+
+static void addRegUsage_ARMAMode1 ( HRegUsage* u, ARMAMode1* am ) {
+   switch (am->tag) {
+      case ARMam1_RI:
+         addHRegUse(u, HRmRead, am->ARMam1.RI.reg);
+         return;
+      case ARMam1_RRS:
+         //    addHRegUse(u, HRmRead, am->ARMam1.RRS.base);
+         //    addHRegUse(u, HRmRead, am->ARMam1.RRS.index);
+         //   return;
+      default:
+         vpanic("addRegUsage_ARMAmode1");
+   }
 }
-ARMAMode1* ARMAMode1_ShlR ( HReg Rm, HReg Rs ) {
-    ARMAMode1* am = LibVEX_Alloc(sizeof(ARMAMode1));
-    am->tag = ARMam1_ShlR;
-    am->ARMam1.ShlR.Rm = Rm;
-    am->ARMam1.ShlR.Rs = Rs;
-    return am;
+
+static void mapRegs_ARMAMode1 ( HRegRemap* m, ARMAMode1* am ) {
+   switch (am->tag) {
+      case ARMam1_RI:
+         am->ARMam1.RI.reg = lookupHRegRemap(m, am->ARMam1.RI.reg);
+         return;
+      case ARMam1_RRS:
+         //am->ARMam1.RR.base =lookupHRegRemap(m, am->ARMam1.RR.base);
+         //am->ARMam1.RR.index = lookupHRegRemap(m, am->ARMam1.RR.index);
+         //return;
+      default:
+         vpanic("mapRegs_ARMAmode1");
+   }
 }
-ARMAMode1* ARMAMode1_ShrR ( HReg Rm, HReg Rs ) {
-    ARMAMode1* am = LibVEX_Alloc(sizeof(ARMAMode1));
-    am->tag = ARMam1_ShrR;
-    am->ARMam1.ShrR.Rm = Rm;
-    am->ARMam1.ShrR.Rs = Rs;
-    return am;
+
+
+/* --------- Mem AModes: Addressing Mode 2 --------- */
+
+ARMAMode2* ARMAMode2_RI ( HReg reg, Int simm9 ) {
+   ARMAMode2* am       = LibVEX_Alloc(sizeof(ARMAMode2));
+   am->tag             = ARMam2_RI;
+   am->ARMam2.RI.reg   = reg;
+   am->ARMam2.RI.simm9 = simm9;
+   vassert(-255 <= simm9 && simm9 <= 255);
+   return am;
 }
-ARMAMode1* ARMAMode1_SarR ( HReg Rm, HReg Rs ) {
-    ARMAMode1* am = LibVEX_Alloc(sizeof(ARMAMode1));
-    am->tag = ARMam1_SarR;
-    am->ARMam1.SarR.Rm = Rm;
-    am->ARMam1.SarR.Rs = Rs;
-    return am;
+ARMAMode2* ARMAMode2_RR ( HReg base, HReg index ) {
+   ARMAMode2* am       = LibVEX_Alloc(sizeof(ARMAMode2));
+   am->tag             = ARMam2_RR;
+   am->ARMam2.RR.base  = base;
+   am->ARMam2.RR.index = index;
+   return am;
 }
 
-ARMAMode1* dopyARMAMode1 ( ARMAMode1* am ) {
+void ppARMAMode2 ( ARMAMode2* am ) {
    switch (am->tag) {
-   case ARMam1_I12A:
-       return ARMAMode1_I12A( am->ARMam1.I12A.imm );
-   case ARMam1_ShlI:
-       return ARMAMode1_ShlI( am->ARMam1.ShlI.Rm, am->ARMam1.ShlI.imm );
-   case ARMam1_ShrI:
-       return ARMAMode1_ShrI( am->ARMam1.ShrI.Rm, am->ARMam1.ShrI.imm );
-   case ARMam1_SarI:
-       return ARMAMode1_SarI( am->ARMam1.SarI.Rm, am->ARMam1.SarI.imm );
-   case ARMam1_ShlR:
-       return ARMAMode1_ShlR( am->ARMam1.ShlR.Rm, am->ARMam1.ShlR.Rs );
-   case ARMam1_ShrR:
-       return ARMAMode1_ShrR( am->ARMam1.ShrR.Rm, am->ARMam1.ShrR.Rs );
-   case ARMam1_SarR:
-       return ARMAMode1_SarR( am->ARMam1.SarR.Rm, am->ARMam1.SarR.Rs );
-   default:
-       vpanic("dopyARMAMode1");
+      case ARMam2_RI:
+         vex_printf("%d(", am->ARMam2.RI.simm9);
+         ppHRegARM(am->ARMam2.RI.reg);
+         vex_printf(")");
+         break;
+      case ARMam2_RR:
+         vex_printf("(");
+         ppHRegARM(am->ARMam2.RR.base);
+         vex_printf(",");
+         ppHRegARM(am->ARMam2.RR.index);
+         vex_printf(")");
+         break;
+      default:
+         vassert(0);
    }
 }
 
-void ppARMAMode1 ( ARMAMode1* am ) {
+static void addRegUsage_ARMAMode2 ( HRegUsage* u, ARMAMode2* am ) {
    switch (am->tag) {
-   case ARMam1_I12A:
-   case ARMam1_ShlI:
-   case ARMam1_ShrI:
-   case ARMam1_SarI:
-   case ARMam1_ShlR:
-   case ARMam1_ShrR:
-   case ARMam1_SarR:
-       vex_printf("ppARMAMode1: Not implemented");
-       break;
-   default:
-       vpanic("ppARMAMode1");
+      case ARMam2_RI:
+         addHRegUse(u, HRmRead, am->ARMam2.RI.reg);
+         return;
+      case ARMam2_RR:
+         //    addHRegUse(u, HRmRead, am->ARMam2.RR.base);
+         //    addHRegUse(u, HRmRead, am->ARMam2.RR.index);
+         //   return;
+      default:
+         vpanic("addRegUsage_ARMAmode2");
    }
 }
 
-/*
-static void addRegUsage_ARMAMode1 ( HRegUsage* u, ARMAMode1* am ) {
-static void mapRegs_ARMAMode1 ( HRegRemap* m, ARMAMode1* am ) {
-*/
+static void mapRegs_ARMAMode2 ( HRegRemap* m, ARMAMode2* am ) {
+   switch (am->tag) {
+      case ARMam2_RI:
+         am->ARMam2.RI.reg = lookupHRegRemap(m, am->ARMam2.RI.reg);
+         return;
+      case ARMam2_RR:
+         //am->ARMam2.RR.base =lookupHRegRemap(m, am->ARMam2.RR.base);
+         //am->ARMam2.RR.index = lookupHRegRemap(m, am->ARMam2.RR.index);
+         //return;
+      default:
+         vpanic("mapRegs_ARMAmode2");
+   }
+}
 
 
-/* ------ ARMAMode1_I12A Helper function ------
-  Given imm32, find immed_8, rotate_imm.
-  ARM ARM A5-6: imm32 = immed_8 ROR (rotate_imm * 2)
-*/
-Bool mk_ARMImm12A ( UInt imm32, ARMImm12A* imm12a ) {
-//    UInt imm32_orig = imm32;
-    UInt shr=0, rot=0;
-    imm12a->imm = 0;
-    imm12a->rot = 0;
-    
-    // Easiest case: no shift needed
-    if (imm32 > 0xFF) {
-       // Next easiest: just a shift to the right needed
-       while ((imm32 & 1) == 0) { imm32 = imm32 >> 1;  shr++; }
-       rot = 32 - shr;
-
-       if (imm32 > 0xFF) {
-           // Hardest: Need to rol (some minimum amount)
-           // valid byte could be split over first and last bytes...
-           
-           // ROL 7 (worst case for still valid imm32):
-           imm32 = (imm32 << 7) | (imm32 << (32-7));
-           // ShR (reverse rol) if went too far:
-           while ((imm32 & 1) == 0) { imm32 = imm32 >> 1; shr++; }
-           rot = 7 - shr;   // if valid imm32, shr < 7
-           
-           if (imm32 > 0xFF) {  // Can't represent this value
-//             vex_printf("Error: Can't represent imm32: 0x%x", imm32_orig);
-               return False;
-           }
-       }
-    }
-    // Valid imm32 so far...
-
-    if (rot & 1) {
-       rot--;
-       imm32 = imm32 << 1;
-       if (imm32 > 0xFF) {
-           // Can't represent this value (can only shift even n)
-//         vex_printf("Error: Can't represent imm32: 0x%x\n", imm32_orig);
-           return False;
-       }
-    }
+/* --------- Mem AModes: Addressing Mode VFP --------- */
 
-    imm12a->imm = imm32;
-    imm12a->rot = rot / 2;
-    
-    vassert((imm12a->imm & 0xFF) == imm12a->imm);
-    vassert((imm12a->rot & 0xF ) == imm12a->rot);
-    return True;
+ARMAModeV* mkARMAModeV ( HReg reg, Int simm11 ) {
+   ARMAModeV* am = LibVEX_Alloc(sizeof(ARMAModeV));
+   vassert(simm11 >= -1020 && simm11 <= 1020);
+   vassert(0 == (simm11 & 3));
+   am->reg    = reg;
+   am->simm11 = simm11;
+   return am;
 }
 
+void ppARMAModeV ( ARMAModeV* am ) {
+   vex_printf("%d(", am->simm11);
+   ppHRegARM(am->reg);
+   vex_printf(")");
+}
 
+static void addRegUsage_ARMAModeV ( HRegUsage* u, ARMAModeV* am ) {
+   addHRegUse(u, HRmRead, am->reg);
+}
 
+static void mapRegs_ARMAModeV ( HRegRemap* m, ARMAModeV* am ) {
+   am->reg = lookupHRegRemap(m, am->reg);
+}
 
 
-/* --------- ARMAMode2: memory address expressions. --------- */
+/* --------- Reg or imm-8x4 operands --------- */
 
-ARMAMode2* ARMAMode2_RI ( HReg Rn, ARMImm12 imm ) {
-    ARMAMode2* am = LibVEX_Alloc(sizeof(ARMAMode2));
-    am->tag = ARMam2_RI;
-    am->ARMam2.RI.Rn = Rn;
-    am->ARMam2.RI.imm = imm;
-    return am;
+static UInt ROR32 ( UInt x, UInt sh ) {
+   vassert(sh >= 0 && sh < 32);
+   if (sh == 0)
+      return x;
+   else
+      return (x << (32-sh)) | (x >> sh);
 }
-ARMAMode2* ARMAMode2_RR ( HReg Rn, HReg Rm ) {
-    ARMAMode2* am = LibVEX_Alloc(sizeof(ARMAMode2));
-    am->tag = ARMam2_RR;
-    am->ARMam2.RR.Rn = Rn;
-    am->ARMam2.RR.Rm = Rm;
-    return am;
+
+ARMRI84* ARMRI84_I84 ( UShort imm8, UShort imm4 ) {
+   ARMRI84* ri84          = LibVEX_Alloc(sizeof(ARMRI84));
+   ri84->tag              = ARMri84_I84;
+   ri84->ARMri84.I84.imm8 = imm8;
+   ri84->ARMri84.I84.imm4 = imm4;
+   vassert(imm8 >= 0 && imm8 <= 255);
+   vassert(imm4 >= 0 && imm4 <= 15);
+   return ri84;
 }
-ARMAMode2* ARMAMode2_RRS ( HReg Rn, HReg Rm, ARMImm5 shift ) {
-    ARMAMode2* am = LibVEX_Alloc(sizeof(ARMAMode2));
-    am->tag = ARMam2_RRS;
-    am->ARMam2.RRS.Rn = Rn;
-    am->ARMam2.RRS.Rm = Rm;
-    am->ARMam2.RRS.shift = shift;
-    return am;
+ARMRI84* ARMRI84_R ( HReg reg ) {
+   ARMRI84* ri84       = LibVEX_Alloc(sizeof(ARMRI84));
+   ri84->tag           = ARMri84_R;
+   ri84->ARMri84.R.reg = reg;
+   return ri84;
 }
 
-ARMAMode2* dopyARMAMode2 ( ARMAMode2* am ) {
-   switch (am->tag) {
-   case ARMam2_RI:
-       return ARMAMode2_RI( am->ARMam2.RI.Rn, am->ARMam2.RI.imm );
-   case ARMam2_RR:
-       return ARMAMode2_RR( am->ARMam2.RR.Rn, am->ARMam2.RR.Rm );
-   case ARMam2_RRS:
-       return ARMAMode2_RRS( am->ARMam2.RRS.Rn, am->ARMam2.RRS.Rm,
-                            am->ARMam2.RRS.shift );
-   default:
-       vpanic("dopyARMAMode2");
+void ppARMRI84 ( ARMRI84* ri84 ) {
+   switch (ri84->tag) {
+      case ARMri84_I84:
+         vex_printf("0x%x", ROR32(ri84->ARMri84.I84.imm8,
+                                  2 * ri84->ARMri84.I84.imm4));
+         break;
+      case ARMri84_R:
+         ppHRegARM(ri84->ARMri84.R.reg);
+         break;
+      default:
+         vassert(0);
    }
 }
 
-void ppARMAMode2 ( ARMAMode2* am ) {
-   switch (am->tag) {
-   case ARMam2_RI:
-   case ARMam2_RR:
-   case ARMam2_RRS:
-       vex_printf("ppARMAMode2: Not implemented");
-       break;
-   default:
-       vpanic("ppARMAMode2");
+static void addRegUsage_ARMRI84 ( HRegUsage* u, ARMRI84* ri84 ) {
+   switch (ri84->tag) {
+      case ARMri84_I84:
+         return;
+      case ARMri84_R:
+         addHRegUse(u, HRmRead, ri84->ARMri84.R.reg);
+         return;
+      default:
+         vpanic("addRegUsage_ARMRI84");
    }
 }
 
-/*
-static void addRegUsage_ARMAMode2 ( HRegUsage* u, ARMAMode1* am ) {
-static void mapRegs_ARMAMode2 ( HRegRemap* m, ARMAMode1* am ) {
-*/
+static void mapRegs_ARMRI84 ( HRegRemap* m, ARMRI84* ri84 ) {
+   switch (ri84->tag) {
+      case ARMri84_I84:
+         return;
+      case ARMri84_R:
+         ri84->ARMri84.R.reg = lookupHRegRemap(m, ri84->ARMri84.R.reg);
+         return;
+      default:
+         vpanic("mapRegs_ARMRI84");
+   }
+}
 
 
-/* --------- ARMAMode3: memory address expressions. --------- */
+/* --------- Reg or imm5 operands --------- */
 
-ARMAMode3* ARMAMode3_RI ( HReg Rn, ARMImm8 imm ) {
-    ARMAMode3* am = LibVEX_Alloc(sizeof(ARMAMode3));
-    am->tag = ARMam3_RI;
-    am->ARMam3.RI.Rn = Rn;
-    am->ARMam3.RI.imm = imm;
-    return am;
+ARMRI5* ARMRI5_I5 ( UInt imm5 ) {
+   ARMRI5* ri5         = LibVEX_Alloc(sizeof(ARMRI5));
+   ri5->tag            = ARMri5_I5;
+   ri5->ARMri5.I5.imm5 = imm5;
+   vassert(imm5 > 0 && imm5 <= 31); // zero is not allowed
+   return ri5;
 }
-ARMAMode3* ARMAMode3_RR ( HReg Rn, HReg Rm ) {
-    ARMAMode3* am = LibVEX_Alloc(sizeof(ARMAMode3));
-    am->tag = ARMam3_RR;
-    am->ARMam3.RR.Rn = Rn;
-    am->ARMam3.RR.Rm = Rm;
-    return am;
+ARMRI5* ARMRI5_R ( HReg reg ) {
+   ARMRI5* ri5       = LibVEX_Alloc(sizeof(ARMRI5));
+   ri5->tag          = ARMri5_R;
+   ri5->ARMri5.R.reg = reg;
+   return ri5;
 }
 
-ARMAMode3* dopyARMAMode3 ( ARMAMode3* am ) {
-   switch (am->tag) {
-   case ARMam3_RI:
-       return ARMAMode3_RI( am->ARMam3.RI.Rn, am->ARMam3.RI.imm );
-   case ARMam3_RR:
-       return ARMAMode3_RR( am->ARMam3.RR.Rn, am->ARMam3.RR.Rm );
-   default:
-       vpanic("dopyARMAMode3");
+void ppARMRI5 ( ARMRI5* ri5 ) {
+   switch (ri5->tag) {
+      case ARMri5_I5:
+         vex_printf("%u", ri5->ARMri5.I5.imm5);
+         break;
+      case ARMri5_R:
+         ppHRegARM(ri5->ARMri5.R.reg);
+         break;
+      default:
+         vassert(0);
    }
 }
 
-void ppARMAMode3 ( ARMAMode3* am ) {
-   switch (am->tag) {
-   case ARMam3_RI:
-   case ARMam3_RR:
-       vex_printf("ppARMAMode3: Not implemented");
-       break;
-   default:
-       vpanic("ppARMAMode3");
+static void addRegUsage_ARMRI5 ( HRegUsage* u, ARMRI5* ri5 ) {
+   switch (ri5->tag) {
+      case ARMri5_I5:
+         return;
+      case ARMri5_R:
+         addHRegUse(u, HRmRead, ri5->ARMri5.R.reg);
+         return;
+      default:
+         vpanic("addRegUsage_ARMRI5");
    }
 }
 
-/*
-static void addRegUsage_ARMAMode1 ( HRegUsage* u, ARMAMode2* am ) {
-static void mapRegs_ARMAMode2 ( HRegRemap* m, ARMAMode2* am ) {
-*/
-
-/* ------ Branch destination ------ */
-
-ARMBranchDest* ARMBranchDest_Imm ( ARMImm24 imm24 ) {
-   ARMBranchDest* branch_dest = LibVEX_Alloc(sizeof(ARMBranchDest));
-   branch_dest->tag = ARMbdImm;
-   branch_dest->ARMbd.Imm.imm24 = imm24;
-   return branch_dest;
-}
-ARMBranchDest* ARMBranchDest_Reg ( HReg reg ) {
-   ARMBranchDest* branch_dest = LibVEX_Alloc(sizeof(ARMBranchDest));
-   branch_dest->tag = ARMbdReg;
-   branch_dest->ARMbd.Reg.reg = reg;
-   return branch_dest;
-}
-
-void ppARMBranchDest ( ARMBranchDest* branch_dest ) {
-    switch (branch_dest->tag) {
-    case ARMbdImm:
-    case ARMbdReg:
-       vex_printf("ppARMBranchDest: Not implemented");
-       break;
-    default:
-       vpanic("ppX86RM");
-    }
+static void mapRegs_ARMRI5 ( HRegRemap* m, ARMRI5* ri5 ) {
+   switch (ri5->tag) {
+      case ARMri5_I5:
+         return;
+      case ARMri5_R:
+         ri5->ARMri5.R.reg = lookupHRegRemap(m, ri5->ARMri5.R.reg);
+         return;
+      default:
+         vpanic("mapRegs_ARMRI5");
+   }
 }
 
 
-
-
 /* --------- Instructions. --------- */
 
 HChar* showARMAluOp ( ARMAluOp op ) {
-    switch (op) {
-    case ARMalu_AND:  return "and";
-    case ARMalu_ORR:  return "orr";
-    case ARMalu_EOR:  return "eor";
-    case ARMalu_SUB:  return "sub";
-    case ARMalu_RSB:  return "rsb";
-    case ARMalu_ADD:  return "add";
-    case ARMalu_ADC:  return "adc";
-    case ARMalu_SBC:  return "sbc";
-    case ARMalu_RSC:  return "rsc";
-    case ARMalu_TST:  return "tst";
-    case ARMalu_TEQ:  return "teq";
-    case ARMalu_CMP:  return "cmp";
-    case ARMalu_CMN:  return "cmn";
-    case ARMalu_MOV:  return "mov";
-    case ARMalu_MVN:  return "mvn";
-    case ARMalu_BIC:  return "bic";
-    default: vpanic("showARMAluOp");
-    }
+   switch (op) {
+      case ARMalu_ADD:  return "add";
+      case ARMalu_ADDS: return "adds";
+      case ARMalu_ADC:  return "adc";
+      case ARMalu_SUB:  return "sub";
+      case ARMalu_SUBS: return "subs";
+      case ARMalu_SBC:  return "sbc";
+      case ARMalu_AND:  return "and";
+      case ARMalu_BIC:  return "bic";
+      case ARMalu_OR:   return "orr";
+      case ARMalu_XOR:  return "xor";
+      default: vpanic("showARMAluOp");
+   }
 }
 
-/* --- Addressing Mode 1 --- */
-ARMInstr* ARMInstr_DPCmp ( ARMAluOp op, HReg Rn,
-                          ARMAMode1* shifter_op ) {
-    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
-    i->tag = ARMin_DPCmp;
-    i->ARMin.DPCmp.op = op;
-    i->ARMin.DPCmp.Rn = Rn;
-    i->ARMin.DPCmp.shifter_op = shifter_op;
-    return i;
-}
-
-ARMInstr* ARMInstr_DPInstr1 ( ARMAluOp op, HReg Rd,
-                             ARMAMode1* shifter_op ) {
-    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
-    i->tag = ARMin_DPInstr1;
-    i->ARMin.DPInstr1.op = op;
-    i->ARMin.DPInstr1.Rd = Rd;
-    i->ARMin.DPInstr1.shifter_op = shifter_op;
-    return i;
-}
-
-ARMInstr* ARMInstr_DPInstr2 ( ARMAluOp op, HReg Rd, HReg Rn,
-                             ARMAMode1* shifter_op ) {
-    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
-    i->tag = ARMin_DPInstr2;
-    i->ARMin.DPInstr2.op = op;
-    i->ARMin.DPInstr2.Rd = Rd;
-    i->ARMin.DPInstr2.Rn = Rn;
-    i->ARMin.DPInstr2.shifter_op = shifter_op;
-    return i;
+HChar* showARMShiftOp ( ARMShiftOp op ) {
+   switch (op) {
+      case ARMsh_SHL: return "shl";
+      case ARMsh_SHR: return "shr";
+      case ARMsh_SAR: return "sar";
+      default: vpanic("showARMShiftOp");
+   }
 }
 
-/* --- Addressing Mode 2 --- */
-ARMInstr* ARMInstr_LoadUB ( HReg Rd, ARMAMode2* addr_mode ) {
-    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
-    i->tag = ARMin_LoadUB;
-    i->ARMin.LoadUB.Rd = Rd;
-    i->ARMin.LoadUB.addr_mode = addr_mode;
-    return i;
+HChar* showARMUnaryOp ( ARMUnaryOp op ) {
+   switch (op) {
+      case ARMun_NEG: return "neg";
+      case ARMun_NOT: return "not";
+      case ARMun_CLZ: return "clz";
+      default: vpanic("showARMUnaryOp");
+   }
 }
 
-ARMInstr* ARMInstr_StoreB ( HReg Rd, ARMAMode2* addr_mode ) {
-    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
-    i->tag = ARMin_StoreB;
-    i->ARMin.StoreB.Rd = Rd;
-    i->ARMin.StoreB.addr_mode = addr_mode;
-    return i;
+HChar* showARMMulOp ( ARMMulOp op ) {
+   switch (op) {
+      case ARMmul_PLAIN: return "mul";
+      case ARMmul_ZX:    return "umull";
+      case ARMmul_SX:    return "smull";
+      default: vpanic("showARMMulOp");
+   }
 }
 
-ARMInstr* ARMInstr_LoadW ( HReg Rd, ARMAMode2* addr_mode ) {
-    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
-    i->tag = ARMin_LoadW;
-    i->ARMin.LoadW.Rd = Rd;
-    i->ARMin.LoadW.addr_mode = addr_mode;
-    return i;
+HChar* showARMVfpOp ( ARMVfpOp op ) {
+   switch (op) {
+      case ARMvfp_ADD: return "add";
+      case ARMvfp_SUB: return "sub";
+      case ARMvfp_MUL: return "mul";
+      case ARMvfp_DIV: return "div";
+      default: vpanic("showARMVfpOp");
+   }
 }
 
-ARMInstr* ARMInstr_StoreW ( HReg Rd, ARMAMode2* addr_mode ) {
-    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
-    i->tag = ARMin_StoreW;
-    i->ARMin.StoreW.Rd = Rd;
-    i->ARMin.StoreW.addr_mode = addr_mode;
-    return i;
+HChar* showARMVfpUnaryOp ( ARMVfpUnaryOp op ) {
+   switch (op) {
+      case ARMvfpu_COPY: return "cpy";
+      case ARMvfpu_NEG:  return "neg";
+      case ARMvfpu_ABS:  return "abs";
+      case ARMvfpu_SQRT: return "sqrt";
+      default: vpanic("showARMVfpUnaryOp");
+   }
 }
 
-/* --- Addressing Mode 3 --- */
-ARMInstr* ARMInstr_LoadSB ( HReg Rd, ARMAMode3* addr_mode ) {
-    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
-    i->tag = ARMin_LoadSB;
-    i->ARMin.LoadSB.Rd = Rd;
-    i->ARMin.LoadSB.addr_mode = addr_mode;
-    return i;
+ARMInstr* ARMInstr_Alu ( ARMAluOp op,
+                         HReg dst, HReg argL, ARMRI84* argR ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag            = ARMin_Alu;
+   i->ARMin.Alu.op   = op;
+   i->ARMin.Alu.dst  = dst;
+   i->ARMin.Alu.argL = argL;
+   i->ARMin.Alu.argR = argR;
+   return i;
 }
-
-ARMInstr* ARMInstr_LoadUH ( HReg Rd, ARMAMode3* addr_mode ) {
-    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
-    i->tag = ARMin_LoadUH;
-    i->ARMin.LoadUH.Rd = Rd;
-    i->ARMin.LoadUH.addr_mode = addr_mode;
-    return i;
+ARMInstr* ARMInstr_Shift  ( ARMShiftOp op,
+                            HReg dst, HReg argL, ARMRI5* argR ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag              = ARMin_Shift;
+   i->ARMin.Shift.op   = op;
+   i->ARMin.Shift.dst  = dst;
+   i->ARMin.Shift.argL = argL;
+   i->ARMin.Shift.argR = argR;
+   return i;
 }
-
-ARMInstr* ARMInstr_LoadSH ( HReg Rd, ARMAMode3* addr_mode ) {
-    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
-    i->tag = ARMin_LoadSH;
-    i->ARMin.LoadSH.Rd = Rd;
-    i->ARMin.LoadSH.addr_mode = addr_mode;
-    return i;
+ARMInstr* ARMInstr_Unary ( ARMUnaryOp op, HReg dst, HReg src ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag             = ARMin_Unary;
+   i->ARMin.Unary.op  = op;
+   i->ARMin.Unary.dst = dst;
+   i->ARMin.Unary.src = src;
+   return i;
 }
-
-ARMInstr* ARMInstr_StoreH ( HReg Rd, ARMAMode3* addr_mode ) {
-    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
-    i->tag = ARMin_StoreH;
-    i->ARMin.StoreH.Rd = Rd;
-    i->ARMin.StoreH.addr_mode = addr_mode;
-    return i;
+ARMInstr* ARMInstr_CmpOrTst ( Bool isCmp, HReg argL, ARMRI84* argR ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag                  = ARMin_CmpOrTst;
+   i->ARMin.CmpOrTst.isCmp = isCmp;
+   i->ARMin.CmpOrTst.argL  = argL;
+   i->ARMin.CmpOrTst.argR  = argR;
+   return i;
 }
-
-/* --- Branch --- */
-ARMInstr* ARMInstr_Branch ( ARMCondCode cond, ARMBranchDest* dest ) {
-    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
-    i->tag = ARMin_Branch;
-    i->ARMin.Branch.cond = cond;
-    i->ARMin.Branch.dest = dest;
-    return i;
+ARMInstr* ARMInstr_Mov ( HReg dst, ARMRI84* src ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag           = ARMin_Mov;
+   i->ARMin.Mov.dst = dst;
+   i->ARMin.Mov.src = src;
+   return i;
 }
-
-ARMInstr* ARMInstr_BranchL ( ARMCondCode cond, ARMBranchDest* dest ) {
-    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
-    i->tag = ARMin_BranchL;
-    i->ARMin.BranchL.dest = dest;
-    return i;
-}
-
-/* --- Literal --- */
-ARMInstr* ARMInstr_Literal ( HReg reg, UInt imm ) {
-    ARMInstr* i       = LibVEX_Alloc(sizeof(ARMInstr));
-    i->tag = ARMin_Literal;
-    i->ARMin.Literal.reg = reg;
-    i->ARMin.Literal.imm = imm;
-    return i;
+ARMInstr* ARMInstr_Imm32  ( HReg dst, UInt imm32 ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag               = ARMin_Imm32;
+   i->ARMin.Imm32.dst   = dst;
+   i->ARMin.Imm32.imm32 = imm32;
+   return i;
+}
+ARMInstr* ARMInstr_LdSt32 ( Bool isLoad, HReg rD, ARMAMode1* amode ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag                 = ARMin_LdSt32;
+   i->ARMin.LdSt32.isLoad = isLoad;
+   i->ARMin.LdSt32.rD     = rD;
+   i->ARMin.LdSt32.amode  = amode;
+   return i;
+}
+ARMInstr* ARMInstr_LdSt16 ( Bool isLoad, Bool signedLoad,
+                            HReg rD, ARMAMode2* amode ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag                     = ARMin_LdSt16;
+   i->ARMin.LdSt16.isLoad     = isLoad;
+   i->ARMin.LdSt16.signedLoad = signedLoad;
+   i->ARMin.LdSt16.rD         = rD;
+   i->ARMin.LdSt16.amode      = amode;
+   return i;
+}
+ARMInstr* ARMInstr_LdSt8U ( Bool isLoad, HReg rD, ARMAMode1* amode ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag                 = ARMin_LdSt8U;
+   i->ARMin.LdSt8U.isLoad = isLoad;
+   i->ARMin.LdSt8U.rD     = rD;
+   i->ARMin.LdSt8U.amode  = amode;
+   return i;
+}
+//extern ARMInstr* ARMInstr_Ld8S   ( HReg, ARMAMode2* );
+ARMInstr* ARMInstr_Goto ( IRJumpKind jk, ARMCondCode cond, HReg gnext ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag              = ARMin_Goto;
+   i->ARMin.Goto.jk    = jk;
+   i->ARMin.Goto.cond  = cond;
+   i->ARMin.Goto.gnext = gnext;
+   return i;
+}
+ARMInstr* ARMInstr_CMov ( ARMCondCode cond, HReg dst, ARMRI84* src ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag             = ARMin_CMov;
+   i->ARMin.CMov.cond = cond;
+   i->ARMin.CMov.dst  = dst;
+   i->ARMin.CMov.src  = src;
+   vassert(cond != ARMcc_AL);
+   return i;
+}
+ARMInstr* ARMInstr_Call ( ARMCondCode cond, HWord target, Int nArgRegs ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag                 = ARMin_Call;
+   i->ARMin.Call.cond     = cond;
+   i->ARMin.Call.target   = target;
+   i->ARMin.Call.nArgRegs = nArgRegs;
+   return i;
+}
+ARMInstr* ARMInstr_Mul ( ARMMulOp op ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag          = ARMin_Mul;
+   i->ARMin.Mul.op = op;
+   return i;
+}
+ARMInstr* ARMInstr_LdrEX ( Int szB ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag             = ARMin_LdrEX;
+   i->ARMin.LdrEX.szB = szB;
+   vassert(szB == 4 || szB == 1);
+   return i;
+}
+ARMInstr* ARMInstr_StrEX ( Int szB ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag             = ARMin_StrEX;
+   i->ARMin.StrEX.szB = szB;
+   vassert(szB == 4 || szB == 1);
+   return i;
+}
+ARMInstr* ARMInstr_VLdStD ( Bool isLoad, HReg dD, ARMAModeV* am ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag                 = ARMin_VLdStD;
+   i->ARMin.VLdStD.isLoad = isLoad;
+   i->ARMin.VLdStD.dD     = dD;
+   i->ARMin.VLdStD.amode  = am;
+   return i;
+}
+ARMInstr* ARMInstr_VLdStS ( Bool isLoad, HReg fD, ARMAModeV* am ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag                 = ARMin_VLdStS;
+   i->ARMin.VLdStS.isLoad = isLoad;
+   i->ARMin.VLdStS.fD     = fD;
+   i->ARMin.VLdStS.amode  = am;
+   return i;
+}
+ARMInstr* ARMInstr_VAluD ( ARMVfpOp op, HReg dst, HReg argL, HReg argR ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag              = ARMin_VAluD;
+   i->ARMin.VAluD.op   = op;
+   i->ARMin.VAluD.dst  = dst;
+   i->ARMin.VAluD.argL = argL;
+   i->ARMin.VAluD.argR = argR;
+   return i;
+}
+ARMInstr* ARMInstr_VAluS ( ARMVfpOp op, HReg dst, HReg argL, HReg argR ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag              = ARMin_VAluS;
+   i->ARMin.VAluS.op   = op;
+   i->ARMin.VAluS.dst  = dst;
+   i->ARMin.VAluS.argL = argL;
+   i->ARMin.VAluS.argR = argR;
+   return i;
+}
+ARMInstr* ARMInstr_VUnaryD ( ARMVfpUnaryOp op, HReg dst, HReg src ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag               = ARMin_VUnaryD;
+   i->ARMin.VUnaryD.op  = op;
+   i->ARMin.VUnaryD.dst = dst;
+   i->ARMin.VUnaryD.src = src;
+   return i;
+}
+ARMInstr* ARMInstr_VUnaryS ( ARMVfpUnaryOp op, HReg dst, HReg src ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag               = ARMin_VUnaryS;
+   i->ARMin.VUnaryS.op  = op;
+   i->ARMin.VUnaryS.dst = dst;
+   i->ARMin.VUnaryS.src = src;
+   return i;
+}
+ARMInstr* ARMInstr_VCmpD ( HReg argL, HReg argR ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag              = ARMin_VCmpD;
+   i->ARMin.VCmpD.argL = argL;
+   i->ARMin.VCmpD.argR = argR;
+   return i;
+}
+ARMInstr* ARMInstr_VCMovD ( ARMCondCode cond, HReg dst, HReg src ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag               = ARMin_VCMovD;
+   i->ARMin.VCMovD.cond = cond;
+   i->ARMin.VCMovD.dst  = dst;
+   i->ARMin.VCMovD.src  = src;
+   vassert(cond != ARMcc_AL);
+   return i;
+}
+ARMInstr* ARMInstr_VCMovS ( ARMCondCode cond, HReg dst, HReg src ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag               = ARMin_VCMovS;
+   i->ARMin.VCMovS.cond = cond;
+   i->ARMin.VCMovS.dst  = dst;
+   i->ARMin.VCMovS.src  = src;
+   vassert(cond != ARMcc_AL);
+   return i;
+}
+ARMInstr* ARMInstr_VCvtSD ( Bool sToD, HReg dst, HReg src ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag               = ARMin_VCvtSD;
+   i->ARMin.VCvtSD.sToD = sToD;
+   i->ARMin.VCvtSD.dst  = dst;
+   i->ARMin.VCvtSD.src  = src;
+   return i;
+}
+ARMInstr* ARMInstr_VXferD ( Bool toD, HReg dD, HReg rHi, HReg rLo ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag              = ARMin_VXferD;
+   i->ARMin.VXferD.toD = toD;
+   i->ARMin.VXferD.dD  = dD;
+   i->ARMin.VXferD.rHi = rHi;
+   i->ARMin.VXferD.rLo = rLo;
+   return i;
+}
+ARMInstr* ARMInstr_VXferS ( Bool toS, HReg fD, HReg rLo ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag              = ARMin_VXferS;
+   i->ARMin.VXferS.toS = toS;
+   i->ARMin.VXferS.fD  = fD;
+   i->ARMin.VXferS.rLo = rLo;
+   return i;
+}
+ARMInstr* ARMInstr_VCvtID ( Bool iToD, Bool syned,
+                            HReg dst, HReg src ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag                = ARMin_VCvtID;
+   i->ARMin.VCvtID.iToD  = iToD;
+   i->ARMin.VCvtID.syned = syned;
+   i->ARMin.VCvtID.dst   = dst;
+   i->ARMin.VCvtID.src   = src;
+   return i;
+}
+ARMInstr* ARMInstr_FPSCR ( Bool toFPSCR, HReg iReg ) {
+   ARMInstr* i = LibVEX_Alloc(sizeof(ARMInstr));
+   i->tag                 = ARMin_FPSCR;
+   i->ARMin.FPSCR.toFPSCR = toFPSCR;
+   i->ARMin.FPSCR.iReg    = iReg;
+   return i;
 }
-
 
 void ppARMInstr ( ARMInstr* i ) {
-    switch (i->tag) {
-    case ARMin_DPCmp:
-    case ARMin_DPInstr1:
-    case ARMin_DPInstr2:
-    case ARMin_LoadUB:
-    case ARMin_StoreB:
-    case ARMin_LoadW:
-    case ARMin_StoreW:
-    case ARMin_LoadSB:
-    case ARMin_LoadUH:
-    case ARMin_LoadSH:
-    case ARMin_StoreH:
-    case ARMin_Branch:
-    case ARMin_BranchL:
-    case ARMin_Literal:
-       vex_printf("ppARMInstr: Not implemented");
-       break;
-
-    default:
-       vpanic("ppARMInstr");
-    }
+   switch (i->tag) {
+      case ARMin_Alu:
+         vex_printf("%-4s  ", showARMAluOp(i->ARMin.Alu.op));
+         ppHRegARM(i->ARMin.Alu.dst);
+         vex_printf(", ");
+         ppHRegARM(i->ARMin.Alu.argL);
+         vex_printf(", ");
+         ppARMRI84(i->ARMin.Alu.argR);
+         return;
+      case ARMin_Shift:
+         vex_printf("%s   ", showARMShiftOp(i->ARMin.Shift.op));
+         ppHRegARM(i->ARMin.Shift.dst);
+         vex_printf(", ");
+         ppHRegARM(i->ARMin.Shift.argL);
+         vex_printf(", ");
+         ppARMRI5(i->ARMin.Shift.argR);
+         return;
+      case ARMin_Unary:
+         vex_printf("%s   ", showARMUnaryOp(i->ARMin.Unary.op));
+         ppHRegARM(i->ARMin.Unary.dst);
+         vex_printf(", ");
+         ppHRegARM(i->ARMin.Unary.src);
+         return;
+      case ARMin_CmpOrTst:
+         vex_printf("%s   ", i->ARMin.CmpOrTst.isCmp ? "cmp" : "tst");
+         ppHRegARM(i->ARMin.CmpOrTst.argL);
+         vex_printf(", ");
+         ppARMRI84(i->ARMin.CmpOrTst.argR);
+         return;
+      case ARMin_Mov:
+         vex_printf("mov   ");
+         ppHRegARM(i->ARMin.Mov.dst);
+         vex_printf(", ");
+         ppARMRI84(i->ARMin.Mov.src);
+         return;
+      case ARMin_Imm32:
+         vex_printf("imm   ");
+         ppHRegARM(i->ARMin.Imm32.dst);
+         vex_printf(", 0x%x", i->ARMin.Imm32.imm32);
+         return;
+      case ARMin_LdSt32:
+         if (i->ARMin.LdSt32.isLoad) {
+            vex_printf("ldr   ");
+            ppHRegARM(i->ARMin.LdSt32.rD);
+            vex_printf(", ");
+            ppARMAMode1(i->ARMin.LdSt32.amode);
+         } else {
+            vex_printf("str   ");
+            ppARMAMode1(i->ARMin.LdSt32.amode);
+            vex_printf(", ");
+            ppHRegARM(i->ARMin.LdSt32.rD);
+         }
+         return;
+      case ARMin_LdSt16:
+         if (i->ARMin.LdSt16.isLoad) {
+            vex_printf("%s", i->ARMin.LdSt16.signedLoad 
+                                ? "ldrsh " : "ldrh  " );
+            ppHRegARM(i->ARMin.LdSt16.rD);
+            vex_printf(", ");
+            ppARMAMode2(i->ARMin.LdSt16.amode);
+         } else {
+            vex_printf("strh  ");
+            ppARMAMode2(i->ARMin.LdSt16.amode);
+            vex_printf(", ");
+            ppHRegARM(i->ARMin.LdSt16.rD);
+         }
+         return;
+      case ARMin_LdSt8U:
+         if (i->ARMin.LdSt8U.isLoad) {
+            vex_printf("ldrb  ");
+            ppHRegARM(i->ARMin.LdSt8U.rD);
+            vex_printf(", ");
+            ppARMAMode1(i->ARMin.LdSt8U.amode);
+         } else {
+            vex_printf("strb  ");
+            ppARMAMode1(i->ARMin.LdSt8U.amode);
+            vex_printf(", ");
+            ppHRegARM(i->ARMin.LdSt8U.rD);
+         }
+         return;
+      case ARMin_Ld8S:
+         goto unhandled;
+      case ARMin_Goto:
+         if (i->ARMin.Goto.cond != ARMcc_AL) {
+            vex_printf("if (%%cpsr.%s) { ",
+                       showARMCondCode(i->ARMin.Goto.cond));
+         } else {
+            vex_printf("if (1) { ");
+         }
+         if (i->ARMin.Goto.jk != Ijk_Boring
+             && i->ARMin.Goto.jk != Ijk_Call
+             && i->ARMin.Goto.jk != Ijk_Ret) {
+            vex_printf("mov r8, $");
+            ppIRJumpKind(i->ARMin.Goto.jk);
+            vex_printf(" ; ");
+         }
+         vex_printf("mov r0, ");
+         ppHRegARM(i->ARMin.Goto.gnext);
+         vex_printf(" ; bx r14");
+         if (i->ARMin.Goto.cond != ARMcc_AL) {
+            vex_printf(" }");
+         } else {
+            vex_printf(" }");
+         }
+         return;
+      case ARMin_CMov:
+         vex_printf("mov%s ", showARMCondCode(i->ARMin.CMov.cond));
+         ppHRegARM(i->ARMin.CMov.dst);
+         vex_printf(", ");
+         ppARMRI84(i->ARMin.CMov.src);
+         return;
+      case ARMin_Call:
+         vex_printf("call%s  ",
+                    i->ARMin.Call.cond==ARMcc_AL
+                       ? "" : showARMCondCode(i->ARMin.Call.cond));
+         vex_printf("0x%lx [nArgRegs=%d]",
+                    i->ARMin.Call.target, i->ARMin.Call.nArgRegs);
+         return;
+      case ARMin_Mul:
+         vex_printf("%-5s ", showARMMulOp(i->ARMin.Mul.op));
+         if (i->ARMin.Mul.op == ARMmul_PLAIN) {
+            vex_printf("r0, r2, r3");
+         } else {
+            vex_printf("r1:r0, r2, r3");
+         }
+         return;
+      case ARMin_LdrEX:
+         vex_printf("ldrex%s ", i->ARMin.LdrEX.szB == 1 ? "b"
+                                : i->ARMin.LdrEX.szB == 2 ? "h" : "");
+         vex_printf("r0, [r1]");
+         return;
+      case ARMin_StrEX:
+         vex_printf("strex%s ", i->ARMin.StrEX.szB == 1 ? "b"
+                                : i->ARMin.StrEX.szB == 2 ? "h" : "");
+         vex_printf("r0, r1, [r2]");
+         return;
+      case ARMin_VLdStD:
+         if (i->ARMin.VLdStD.isLoad) {
+            vex_printf("fldd  ");
+            ppHRegARM(i->ARMin.VLdStD.dD);
+            vex_printf(", ");
+            ppARMAModeV(i->ARMin.VLdStD.amode);
+         } else {
+            vex_printf("fstd  ");
+            ppARMAModeV(i->ARMin.VLdStD.amode);
+            vex_printf(", ");
+            ppHRegARM(i->ARMin.VLdStD.dD);
+         }
+         return;
+      case ARMin_VLdStS:
+         if (i->ARMin.VLdStS.isLoad) {
+            vex_printf("flds  ");
+            ppHRegARM(i->ARMin.VLdStS.fD);
+            vex_printf(", ");
+            ppARMAModeV(i->ARMin.VLdStS.amode);
+         } else {
+            vex_printf("fsts  ");
+            ppARMAModeV(i->ARMin.VLdStS.amode);
+            vex_printf(", ");
+            ppHRegARM(i->ARMin.VLdStS.fD);
+         }
+         return;
+      case ARMin_VAluD:
+         vex_printf("f%-3sd ", showARMVfpOp(i->ARMin.VAluD.op));
+         ppHRegARM(i->ARMin.VAluD.dst);
+         vex_printf(", ");
+         ppHRegARM(i->ARMin.VAluD.argL);
+         vex_printf(", ");
+         ppHRegARM(i->ARMin.VAluD.argR);
+         return;
+      case ARMin_VAluS:
+         vex_printf("f%-3ss ", showARMVfpOp(i->ARMin.VAluS.op));
+         ppHRegARM(i->ARMin.VAluS.dst);
+         vex_printf(", ");
+         ppHRegARM(i->ARMin.VAluS.argL);
+         vex_printf(", ");
+         ppHRegARM(i->ARMin.VAluS.argR);
+         return;
+      case ARMin_VUnaryD:
+         vex_printf("f%-3sd ", showARMVfpUnaryOp(i->ARMin.VUnaryD.op));
+         ppHRegARM(i->ARMin.VUnaryD.dst);
+         vex_printf(", ");
+         ppHRegARM(i->ARMin.VUnaryD.src);
+         return;
+      case ARMin_VUnaryS:
+         vex_printf("f%-3ss ", showARMVfpUnaryOp(i->ARMin.VUnaryS.op));
+         ppHRegARM(i->ARMin.VUnaryS.dst);
+         vex_printf(", ");
+         ppHRegARM(i->ARMin.VUnaryS.src);
+         return;
+      case ARMin_VCmpD:
+         vex_printf("fcmpd ");
+         ppHRegARM(i->ARMin.VCmpD.argL);
+         vex_printf(", ");
+         ppHRegARM(i->ARMin.VCmpD.argR);
+         vex_printf(" ; fmstat");
+         return;
+      case ARMin_VCMovD:
+         vex_printf("fcpyd%s ", showARMCondCode(i->ARMin.VCMovD.cond));
+         ppHRegARM(i->ARMin.VCMovD.dst);
+         vex_printf(", ");
+         ppHRegARM(i->ARMin.VCMovD.src);
+         return;
+      case ARMin_VCMovS:
+         vex_printf("fcpys%s ", showARMCondCode(i->ARMin.VCMovS.cond));
+         ppHRegARM(i->ARMin.VCMovS.dst);
+         vex_printf(", ");
+         ppHRegARM(i->ARMin.VCMovS.src);
+         return;
+      case ARMin_VCvtSD:
+         vex_printf("fcvt%s ", i->ARMin.VCvtSD.sToD ? "ds" : "sd");
+         ppHRegARM(i->ARMin.VCvtSD.dst);
+         vex_printf(", ");
+         ppHRegARM(i->ARMin.VCvtSD.src);
+         return;
+      case ARMin_VXferD:
+         vex_printf("vmov  ");
+         if (i->ARMin.VXferD.toD) {
+            ppHRegARM(i->ARMin.VXferD.dD);
+            vex_printf(", ");
+            ppHRegARM(i->ARMin.VXferD.rLo);
+            vex_printf(", ");
+            ppHRegARM(i->ARMin.VXferD.rHi);
+         } else {
+            ppHRegARM(i->ARMin.VXferD.rLo);
+            vex_printf(", ");
+            ppHRegARM(i->ARMin.VXferD.rHi);
+            vex_printf(", ");
+            ppHRegARM(i->ARMin.VXferD.dD);
+         }
+         return;
+      case ARMin_VXferS:
+         vex_printf("vmov  ");
+         if (i->ARMin.VXferS.toS) {
+            ppHRegARM(i->ARMin.VXferS.fD);
+            vex_printf(", ");
+            ppHRegARM(i->ARMin.VXferS.rLo);
+         } else {
+            ppHRegARM(i->ARMin.VXferS.rLo);
+            vex_printf(", ");
+            ppHRegARM(i->ARMin.VXferS.fD);
+         }
+         return;
+      case ARMin_VCvtID: {
+         HChar* nm = "?";
+         if (i->ARMin.VCvtID.iToD) {
+            nm = i->ARMin.VCvtID.syned ? "fsitod" : "fuitod";
+         } else {
+            nm = i->ARMin.VCvtID.syned ? "ftosid" : "ftouid";
+         }
+         vex_printf("%s ", nm);
+         ppHRegARM(i->ARMin.VCvtID.dst);
+         vex_printf(", ");
+         ppHRegARM(i->ARMin.VCvtID.src);
+         return;
+      }
+      case ARMin_FPSCR:
+         if (i->ARMin.FPSCR.toFPSCR) {
+            vex_printf("fmxr  fpscr, ");
+            ppHRegARM(i->ARMin.FPSCR.iReg);
+         } else {
+            vex_printf("fmrx  ");
+            ppHRegARM(i->ARMin.FPSCR.iReg);
+            vex_printf(", fpscr");
+         }
+         return;
+      unhandled:
+         vex_printf("ppARMInstr: unhandled case (tag %d)", (Int)i->tag);
+         vpanic("ppARMInstr(1)");
+         return;
+      default:
+         vpanic("ppARMInstr(2)");
+   }
 }
 
 
-
-
 /* --------- Helpers for register allocation. --------- */
 
-void getRegUsage_ARMInstr ( HRegUsage* u, ARMInstr* i ) {
-//    Bool unary;
-    initHRegUsage(u);
-    switch (i->tag) {
-    case ARMin_DPCmp:
-    case ARMin_DPInstr1:
-    case ARMin_DPInstr2:
-    case ARMin_LoadUB:
-    case ARMin_StoreB:
-    case ARMin_LoadW:
-    case ARMin_StoreW:
-    case ARMin_LoadSB:
-    case ARMin_LoadUH:
-    case ARMin_LoadSH:
-    case ARMin_StoreH:
-    case ARMin_Branch:
-    case ARMin_BranchL:
-    case ARMin_Literal:
-
-    default:
-       ppARMInstr(i);
-       vpanic("getRegUsage_ARMInstr");
-    }
+void getRegUsage_ARMInstr ( HRegUsage* u, ARMInstr* i, Bool mode64 )
+{
+   vassert(mode64 == False);
+   initHRegUsage(u);
+   switch (i->tag) {
+      case ARMin_Alu:
+         addHRegUse(u, HRmWrite, i->ARMin.Alu.dst);
+         addHRegUse(u, HRmRead, i->ARMin.Alu.argL);
+         addRegUsage_ARMRI84(u, i->ARMin.Alu.argR);
+         return;
+      case ARMin_Shift:
+         addHRegUse(u, HRmWrite, i->ARMin.Shift.dst);
+         addHRegUse(u, HRmRead, i->ARMin.Shift.argL);
+         addRegUsage_ARMRI5(u, i->ARMin.Shift.argR);
+         return;
+      case ARMin_Unary:
+         addHRegUse(u, HRmWrite, i->ARMin.Unary.dst);
+         addHRegUse(u, HRmRead, i->ARMin.Unary.src);
+         return;
+      case ARMin_CmpOrTst:
+         addHRegUse(u, HRmRead, i->ARMin.CmpOrTst.argL);
+         addRegUsage_ARMRI84(u, i->ARMin.CmpOrTst.argR);
+         return;
+      case ARMin_Mov:
+         addHRegUse(u, HRmWrite, i->ARMin.Mov.dst);
+         addRegUsage_ARMRI84(u, i->ARMin.Mov.src);
+         return;
+      case ARMin_Imm32:
+         addHRegUse(u, HRmWrite, i->ARMin.Imm32.dst);
+         return;
+      case ARMin_LdSt32:
+         addRegUsage_ARMAMode1(u, i->ARMin.LdSt32.amode);
+         if (i->ARMin.LdSt32.isLoad) {
+            addHRegUse(u, HRmWrite, i->ARMin.LdSt32.rD);
+         } else {
+            addHRegUse(u, HRmRead, i->ARMin.LdSt32.rD);
+         }
+         return;
+      case ARMin_LdSt16:
+         addRegUsage_ARMAMode2(u, i->ARMin.LdSt16.amode);
+         if (i->ARMin.LdSt16.isLoad) {
+            addHRegUse(u, HRmWrite, i->ARMin.LdSt16.rD);
+         } else {
+            addHRegUse(u, HRmRead, i->ARMin.LdSt16.rD);
+         }
+         return;
+      case ARMin_LdSt8U:
+         addRegUsage_ARMAMode1(u, i->ARMin.LdSt8U.amode);
+         if (i->ARMin.LdSt8U.isLoad) {
+            addHRegUse(u, HRmWrite, i->ARMin.LdSt8U.rD);
+         } else {
+            addHRegUse(u, HRmRead, i->ARMin.LdSt8U.rD);
+         }
+         return;
+      case ARMin_Ld8S:
+         goto unhandled;
+      case ARMin_Goto:
+         /* reads the reg holding the next guest addr */
+         addHRegUse(u, HRmRead, i->ARMin.Goto.gnext);
+         /* writes it to the standard integer return register */
+         addHRegUse(u, HRmWrite, hregARM_R0());
+         /* possibly messes with the baseblock pointer */
+         if (i->ARMin.Goto.jk != Ijk_Boring
+             && i->ARMin.Goto.jk != Ijk_Call
+             && i->ARMin.Goto.jk != Ijk_Ret)
+            /* note, this is irrelevant since r8 is not actually
+               available to the allocator.  But still .. */
+            addHRegUse(u, HRmWrite, hregARM_R8());
+         return;
+      case ARMin_CMov:
+         addHRegUse(u, HRmWrite, i->ARMin.CMov.dst);
+         addHRegUse(u, HRmRead,  i->ARMin.CMov.dst);
+         addRegUsage_ARMRI84(u, i->ARMin.CMov.src);
+         return;
+      case ARMin_Call:
+         /* logic and comments copied/modified from x86 back end */
+         /* This is a bit subtle. */
+         /* First off, claim it trashes all the caller-saved regs
+            which fall within the register allocator's jurisdiction.
+            These I believe to be r0,1,2,3.  If it turns out that r9
+            is also caller-saved, then we'll have to add that here
+            too. */
+         addHRegUse(u, HRmWrite, hregARM_R0());
+         addHRegUse(u, HRmWrite, hregARM_R1());
+         addHRegUse(u, HRmWrite, hregARM_R2());
+         addHRegUse(u, HRmWrite, hregARM_R3());
+         /* Now we have to state any parameter-carrying registers
+            which might be read.  This depends on nArgRegs. */
+         switch (i->ARMin.Call.nArgRegs) {
+            case 4: addHRegUse(u, HRmRead, hregARM_R3()); /*fallthru*/
+            case 3: addHRegUse(u, HRmRead, hregARM_R2()); /*fallthru*/
+            case 2: addHRegUse(u, HRmRead, hregARM_R1()); /*fallthru*/
+            case 1: addHRegUse(u, HRmRead, hregARM_R0()); break;
+            case 0: break;
+            default: vpanic("getRegUsage_ARM:Call:regparms");
+         }
+         /* Finally, there is the issue that the insn trashes a
+            register because the literal target address has to be
+            loaded into a register.  Fortunately, for the nArgRegs=
+            0/1/2/3 case, we can use r0, r1, r2 or r3 respectively, so
+            this does not cause any further damage.  For the
+            nArgRegs=4 case, we'll have to choose another register
+            arbitrarily since all the caller saved regs are used for
+            parameters, and so we might as well choose r11.
+            */
+         if (i->ARMin.Call.nArgRegs == 4)
+            addHRegUse(u, HRmWrite, hregARM_R11());
+         /* Upshot of this is that the assembler really must observe
+            the here-stated convention of which register to use as an
+            address temporary, depending on nArgRegs: 0==r0,
+            1==r1, 2==r2, 3==r3, 4==r11 */
+         return;
+      case ARMin_Mul:
+         addHRegUse(u, HRmRead, hregARM_R2());
+         addHRegUse(u, HRmRead, hregARM_R3());
+         addHRegUse(u, HRmWrite, hregARM_R0());
+         if (i->ARMin.Mul.op != ARMmul_PLAIN)
+            addHRegUse(u, HRmWrite, hregARM_R1());
+         return;
+      case ARMin_LdrEX:
+         addHRegUse(u, HRmWrite, hregARM_R0());
+         addHRegUse(u, HRmRead, hregARM_R1());
+         return;
+      case ARMin_StrEX:
+         addHRegUse(u, HRmWrite, hregARM_R0());
+         addHRegUse(u, HRmRead, hregARM_R1());
+         addHRegUse(u, HRmRead, hregARM_R2());
+         return;
+      case ARMin_VLdStD:
+         addRegUsage_ARMAModeV(u, i->ARMin.VLdStD.amode);
+         if (i->ARMin.VLdStD.isLoad) {
+            addHRegUse(u, HRmWrite, i->ARMin.VLdStD.dD);
+         } else {
+            addHRegUse(u, HRmRead, i->ARMin.VLdStD.dD);
+         }
+         return;
+      case ARMin_VLdStS:
+         addRegUsage_ARMAModeV(u, i->ARMin.VLdStS.amode);
+         if (i->ARMin.VLdStS.isLoad) {
+            addHRegUse(u, HRmWrite, i->ARMin.VLdStS.fD);
+         } else {
+            addHRegUse(u, HRmRead, i->ARMin.VLdStS.fD);
+         }
+         return;
+      case ARMin_VAluD:
+         addHRegUse(u, HRmWrite, i->ARMin.VAluD.dst);
+         addHRegUse(u, HRmRead, i->ARMin.VAluD.argL);
+         addHRegUse(u, HRmRead, i->ARMin.VAluD.argR);
+         return;
+      case ARMin_VAluS:
+         addHRegUse(u, HRmWrite, i->ARMin.VAluS.dst);
+         addHRegUse(u, HRmRead, i->ARMin.VAluS.argL);
+         addHRegUse(u, HRmRead, i->ARMin.VAluS.argR);
+         return;
+      case ARMin_VUnaryD:
+         addHRegUse(u, HRmWrite, i->ARMin.VUnaryD.dst);
+         addHRegUse(u, HRmRead, i->ARMin.VUnaryD.src);
+         return;
+      case ARMin_VUnaryS:
+         addHRegUse(u, HRmWrite, i->ARMin.VUnaryS.dst);
+         addHRegUse(u, HRmRead, i->ARMin.VUnaryS.src);
+         return;
+      case ARMin_VCmpD:
+         addHRegUse(u, HRmRead, i->ARMin.VCmpD.argL);
+         addHRegUse(u, HRmRead, i->ARMin.VCmpD.argR);
+         return;
+      case ARMin_VCMovD:
+         addHRegUse(u, HRmWrite, i->ARMin.VCMovD.dst);
+         addHRegUse(u, HRmRead,  i->ARMin.VCMovD.dst);
+         addHRegUse(u, HRmRead,  i->ARMin.VCMovD.src);
+         return;
+      case ARMin_VCMovS:
+         addHRegUse(u, HRmWrite, i->ARMin.VCMovS.dst);
+         addHRegUse(u, HRmRead,  i->ARMin.VCMovS.dst);
+         addHRegUse(u, HRmRead,  i->ARMin.VCMovS.src);
+         return;
+      case ARMin_VCvtSD:
+         addHRegUse(u, HRmWrite, i->ARMin.VCvtSD.dst);
+         addHRegUse(u, HRmRead,  i->ARMin.VCvtSD.src);
+         return;
+      case ARMin_VXferD:
+         if (i->ARMin.VXferD.toD) {
+            addHRegUse(u, HRmWrite, i->ARMin.VXferD.dD);
+            addHRegUse(u, HRmRead,  i->ARMin.VXferD.rHi);
+            addHRegUse(u, HRmRead,  i->ARMin.VXferD.rLo);
+         } else {
+            addHRegUse(u, HRmRead,  i->ARMin.VXferD.dD);
+            addHRegUse(u, HRmWrite, i->ARMin.VXferD.rHi);
+            addHRegUse(u, HRmWrite, i->ARMin.VXferD.rLo);
+         }
+         return;
+      case ARMin_VXferS:
+         if (i->ARMin.VXferS.toS) {
+            addHRegUse(u, HRmWrite, i->ARMin.VXferS.fD);
+            addHRegUse(u, HRmRead,  i->ARMin.VXferS.rLo);
+         } else {
+            addHRegUse(u, HRmRead,  i->ARMin.VXferS.fD);
+            addHRegUse(u, HRmWrite, i->ARMin.VXferS.rLo);
+         }
+         return;
+      case ARMin_VCvtID:
+         addHRegUse(u, HRmWrite, i->ARMin.VCvtID.dst);
+         addHRegUse(u, HRmRead,  i->ARMin.VCvtID.src);
+         return;
+      case ARMin_FPSCR:
+         if (i->ARMin.FPSCR.toFPSCR)
+            addHRegUse(u, HRmRead, i->ARMin.FPSCR.iReg);
+         else
+            addHRegUse(u, HRmWrite, i->ARMin.FPSCR.iReg);
+         return;
+      unhandled:
+      default:
+         ppARMInstr(i);
+         vpanic("getRegUsage_ARMInstr");
+   }
 }
 
 
-/* local helper */
-#if 0
-static void mapReg(HRegRemap* m, HReg* r) {
-   *r = lookupHRegRemap(m, *r);
-}
-#endif
-
-void mapRegs_ARMInstr ( HRegRemap* m, ARMInstr* i ) {
-    switch (i->tag) {
-    case ARMin_DPCmp:
-    case ARMin_DPInstr1:
-    case ARMin_DPInstr2:
-    case ARMin_LoadUB:
-    case ARMin_StoreB:
-    case ARMin_LoadW:
-    case ARMin_StoreW:
-    case ARMin_LoadSB:
-    case ARMin_LoadUH:
-    case ARMin_LoadSH:
-    case ARMin_StoreH:
-    case ARMin_Branch:
-    case ARMin_BranchL:
-    case ARMin_Literal:
-
-    default:
-       ppARMInstr(i);
-       vpanic("getRegUsage_ARMInstr");
-    }
+void mapRegs_ARMInstr ( HRegRemap* m, ARMInstr* i, Bool mode64 )
+{
+   vassert(mode64 == False);
+   switch (i->tag) {
+      case ARMin_Alu:
+         i->ARMin.Alu.dst = lookupHRegRemap(m, i->ARMin.Alu.dst);
+         i->ARMin.Alu.argL = lookupHRegRemap(m, i->ARMin.Alu.argL);
+         mapRegs_ARMRI84(m, i->ARMin.Alu.argR);
+         return;
+      case ARMin_Shift:
+         i->ARMin.Shift.dst = lookupHRegRemap(m, i->ARMin.Shift.dst);
+         i->ARMin.Shift.argL = lookupHRegRemap(m, i->ARMin.Shift.argL);
+         mapRegs_ARMRI5(m, i->ARMin.Shift.argR);
+         return;
+      case ARMin_Unary:
+         i->ARMin.Unary.dst = lookupHRegRemap(m, i->ARMin.Unary.dst);
+         i->ARMin.Unary.src = lookupHRegRemap(m, i->ARMin.Unary.src);
+         return;
+      case ARMin_CmpOrTst:
+         i->ARMin.CmpOrTst.argL = lookupHRegRemap(m, i->ARMin.CmpOrTst.argL);
+         mapRegs_ARMRI84(m, i->ARMin.CmpOrTst.argR);
+         return;
+      case ARMin_Mov:
+         i->ARMin.Mov.dst = lookupHRegRemap(m, i->ARMin.Mov.dst);
+         mapRegs_ARMRI84(m, i->ARMin.Mov.src);
+         return;
+      case ARMin_Imm32:
+         i->ARMin.Imm32.dst = lookupHRegRemap(m, i->ARMin.Imm32.dst);
+         return;
+      case ARMin_LdSt32:
+         i->ARMin.LdSt32.rD = lookupHRegRemap(m, i->ARMin.LdSt32.rD);
+         mapRegs_ARMAMode1(m, i->ARMin.LdSt32.amode);
+         return;
+      case ARMin_LdSt16:
+         i->ARMin.LdSt16.rD = lookupHRegRemap(m, i->ARMin.LdSt16.rD);
+         mapRegs_ARMAMode2(m, i->ARMin.LdSt16.amode);
+         return;
+      case ARMin_LdSt8U:
+         i->ARMin.LdSt8U.rD = lookupHRegRemap(m, i->ARMin.LdSt8U.rD);
+         mapRegs_ARMAMode1(m, i->ARMin.LdSt8U.amode);
+         return;
+      case ARMin_Ld8S:
+         goto unhandled;
+      case ARMin_Goto:
+         i->ARMin.Goto.gnext = lookupHRegRemap(m, i->ARMin.Goto.gnext);
+         return;
+      case ARMin_CMov:
+         i->ARMin.CMov.dst = lookupHRegRemap(m, i->ARMin.CMov.dst);
+         mapRegs_ARMRI84(m, i->ARMin.CMov.src);
+         return;
+      case ARMin_Call:
+         return;
+      case ARMin_Mul:
+         return;
+      case ARMin_LdrEX:
+         return;
+      case ARMin_StrEX:
+         return;
+      case ARMin_VLdStD:
+         i->ARMin.VLdStD.dD = lookupHRegRemap(m, i->ARMin.VLdStD.dD);
+         mapRegs_ARMAModeV(m, i->ARMin.VLdStD.amode);
+         return;
+      case ARMin_VLdStS:
+         i->ARMin.VLdStS.fD = lookupHRegRemap(m, i->ARMin.VLdStS.fD);
+         mapRegs_ARMAModeV(m, i->ARMin.VLdStS.amode);
+         return;
+      case ARMin_VAluD:
+         i->ARMin.VAluD.dst  = lookupHRegRemap(m, i->ARMin.VAluD.dst);
+         i->ARMin.VAluD.argL = lookupHRegRemap(m, i->ARMin.VAluD.argL);
+         i->ARMin.VAluD.argR = lookupHRegRemap(m, i->ARMin.VAluD.argR);
+         return;
+      case ARMin_VAluS:
+         i->ARMin.VAluS.dst  = lookupHRegRemap(m, i->ARMin.VAluS.dst);
+         i->ARMin.VAluS.argL = lookupHRegRemap(m, i->ARMin.VAluS.argL);
+         i->ARMin.VAluS.argR = lookupHRegRemap(m, i->ARMin.VAluS.argR);
+         return;
+      case ARMin_VUnaryD:
+         i->ARMin.VUnaryD.dst = lookupHRegRemap(m, i->ARMin.VUnaryD.dst);
+         i->ARMin.VUnaryD.src = lookupHRegRemap(m, i->ARMin.VUnaryD.src);
+         return;
+      case ARMin_VUnaryS:
+         i->ARMin.VUnaryS.dst = lookupHRegRemap(m, i->ARMin.VUnaryS.dst);
+         i->ARMin.VUnaryS.src = lookupHRegRemap(m, i->ARMin.VUnaryS.src);
+         return;
+      case ARMin_VCmpD:
+         i->ARMin.VCmpD.argL = lookupHRegRemap(m, i->ARMin.VCmpD.argL);
+         i->ARMin.VCmpD.argR = lookupHRegRemap(m, i->ARMin.VCmpD.argR);
+         return;
+      case ARMin_VCMovD:
+         i->ARMin.VCMovD.dst = lookupHRegRemap(m, i->ARMin.VCMovD.dst);
+         i->ARMin.VCMovD.src = lookupHRegRemap(m, i->ARMin.VCMovD.src);
+         return;
+      case ARMin_VCMovS:
+         i->ARMin.VCMovS.dst = lookupHRegRemap(m, i->ARMin.VCMovS.dst);
+         i->ARMin.VCMovS.src = lookupHRegRemap(m, i->ARMin.VCMovS.src);
+         return;
+      case ARMin_VCvtSD:
+         i->ARMin.VCvtSD.dst = lookupHRegRemap(m, i->ARMin.VCvtSD.dst);
+         i->ARMin.VCvtSD.src = lookupHRegRemap(m, i->ARMin.VCvtSD.src);
+         return;
+      case ARMin_VXferD:
+         i->ARMin.VXferD.dD  = lookupHRegRemap(m, i->ARMin.VXferD.dD);
+         i->ARMin.VXferD.rHi = lookupHRegRemap(m, i->ARMin.VXferD.rHi);
+         i->ARMin.VXferD.rLo = lookupHRegRemap(m, i->ARMin.VXferD.rLo);
+         return;
+      case ARMin_VXferS:
+         i->ARMin.VXferS.fD  = lookupHRegRemap(m, i->ARMin.VXferS.fD);
+         i->ARMin.VXferS.rLo = lookupHRegRemap(m, i->ARMin.VXferS.rLo);
+         return;
+      case ARMin_VCvtID:
+         i->ARMin.VCvtID.dst = lookupHRegRemap(m, i->ARMin.VCvtID.dst);
+         i->ARMin.VCvtID.src = lookupHRegRemap(m, i->ARMin.VCvtID.src);
+         return;
+      case ARMin_FPSCR:
+         i->ARMin.FPSCR.iReg = lookupHRegRemap(m, i->ARMin.FPSCR.iReg);
+         return;
+      unhandled:
+      default:
+         ppARMInstr(i);
+         vpanic("mapRegs_ARMInstr");
+   }
 }
 
 /* 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_ARMInstr ( ARMInstr* i, HReg* src, HReg* dst ) {
-    return False;  // No optimisations for now...
+Bool isMove_ARMInstr ( ARMInstr* i, HReg* src, HReg* dst )
+{
+   /* Moves between integer regs */
+   switch (i->tag) {
+      case ARMin_Mov:
+         if (i->ARMin.Mov.src->tag == ARMri84_R) {
+            *src = i->ARMin.Mov.src->ARMri84.R.reg;
+            *dst = i->ARMin.Mov.dst;
+            return True;
+         }
+         break;
+      case ARMin_VUnaryD:
+         if (i->ARMin.VUnaryD.op == ARMvfpu_COPY) {
+            *src = i->ARMin.VUnaryD.src;
+            *dst = i->ARMin.VUnaryD.dst;
+            return True;
+         }
+         break;
+      case ARMin_VUnaryS:
+         if (i->ARMin.VUnaryS.op == ARMvfpu_COPY) {
+            *src = i->ARMin.VUnaryS.src;
+            *dst = i->ARMin.VUnaryS.dst;
+            return True;
+         }
+         break;
+      default:
+         break;
+   }
+
+   // todo: float, vector moves
+   return False;
 }
 
 
-/* Generate x86 spill/reload instructions under the direction of the
+/* Generate arm spill/reload instructions under the direction of the
    register allocator.  Note it's critical these don't write the
    condition codes. */
 
-ARMInstr* genSpill_ARM ( HReg rreg, Int offsetB ) {
-//   ARMAMode1* am;
+void genSpill_ARM ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2,
+                    HReg rreg, Int offsetB, Bool mode64 )
+{
+   HRegClass rclass;
    vassert(offsetB >= 0);
    vassert(!hregIsVirtual(rreg));
-
-   switch (hregClass(rreg)) {
-
-   default: 
-       ppHRegClass(hregClass(rreg));
-       vpanic("genSpill_ARM: unimplemented regclass");
+   vassert(mode64 == False);
+   *i1 = *i2 = NULL;
+   rclass = hregClass(rreg);
+   switch (rclass) {
+      case HRcInt32:
+         vassert(offsetB <= 4095);
+         *i1 = ARMInstr_LdSt32( False/*!isLoad*/, 
+                                rreg, 
+                                ARMAMode1_RI(hregARM_R8(), offsetB) );
+         return;
+      case HRcFlt32:
+      case HRcFlt64: {
+         HReg r8   = hregARM_R8();  /* baseblock */
+         HReg r12  = hregARM_R12(); /* spill temp */
+         HReg base = r8;
+         vassert(0 == (offsetB & 3));
+         if (offsetB >= 1024) {
+            *i1 = ARMInstr_Alu(ARMalu_ADD, r12, r8,
+                               ARMRI84_I84(1,11)); /* 1024 */
+            offsetB -= 1024;
+            base = r12;
+         }
+         vassert(offsetB <= 1020);
+         if (rclass == HRcFlt32) {
+            *i2 = ARMInstr_VLdStS( False/*!isLoad*/,
+                                   rreg,
+                                   mkARMAModeV(base, offsetB) );
+         } else {
+            *i2 = ARMInstr_VLdStD( False/*!isLoad*/,
+                                   rreg,
+                                   mkARMAModeV(base, offsetB) );
+         }
+         return;
+      }
+      default: 
+         ppHRegClass(rclass);
+         vpanic("genSpill_ARM: unimplemented regclass");
    }
 }
 
-ARMInstr* genReload_ARM ( HReg rreg, Int offsetB ) {
-//   ARMAMode1* am;
+void genReload_ARM ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2,
+                     HReg rreg, Int offsetB, Bool mode64 )
+{
+   HRegClass rclass;
    vassert(offsetB >= 0);
    vassert(!hregIsVirtual(rreg));
-
-   switch (hregClass(rreg)) {
-
-   default: 
-       ppHRegClass(hregClass(rreg));
-       vpanic("genReload_ARM: unimplemented regclass");
+   vassert(mode64 == False);
+   *i1 = *i2 = NULL;
+   rclass = hregClass(rreg);
+   switch (rclass) {
+      case HRcInt32:
+         vassert(offsetB <= 4095);
+         *i1 = ARMInstr_LdSt32( True/*isLoad*/, 
+                                rreg, 
+                                ARMAMode1_RI(hregARM_R8(), offsetB) );
+         return;
+      case HRcFlt32:
+      case HRcFlt64: {
+         HReg r8   = hregARM_R8();  /* baseblock */
+         HReg r12  = hregARM_R12(); /* spill temp */
+         HReg base = r8;
+         vassert(0 == (offsetB & 3));
+         if (offsetB >= 1024) {
+            *i1 = ARMInstr_Alu(ARMalu_ADD, r12, r8,
+                               ARMRI84_I84(1,11)); /* 1024 */
+            offsetB -= 1024;
+            base = r12;
+         }
+         vassert(offsetB <= 1020);
+         if (rclass == HRcFlt32) {
+            *i2 = ARMInstr_VLdStS( True/*isLoad*/,
+                                   rreg,
+                                   mkARMAModeV(base, offsetB) );
+         } else {
+            *i2 = ARMInstr_VLdStD( True/*isLoad*/,
+                                   rreg,
+                                   mkARMAModeV(base, offsetB) );
+         }
+         return;
+      }
+      default: 
+         ppHRegClass(rclass);
+         vpanic("genReload_ARM: unimplemented regclass");
    }
 }
 
@@ -710,43 +1537,778 @@ ARMInstr* genReload_ARM ( HReg rreg, Int offsetB ) {
    Note that buf is not the insn's final place, and therefore it is
    imperative to emit position-independent code. */
 
-Int emit_ARMInstr ( UChar* buf, Int nbuf, ARMInstr* i ) {
-//    UInt irno, opc, opc_rr, subopc_imm, opc_imma, opc_cl, opc_imm, subopc;
-    
-//    UInt   xtra;
-    UChar* p = &buf[0];
-//    UChar* ptmp;
-    vassert(nbuf >= 32);
-
-    switch (i->tag) {
-    case ARMin_DPCmp:
-    case ARMin_DPInstr1:
-    case ARMin_DPInstr2:
-    case ARMin_LoadUB:
-    case ARMin_StoreB:
-    case ARMin_LoadW:
-    case ARMin_StoreW:
-    case ARMin_LoadSB:
-    case ARMin_LoadUH:
-    case ARMin_LoadSH:
-    case ARMin_StoreH:
-    case ARMin_Branch:
-    case ARMin_BranchL:
-    case ARMin_Literal:
-    default: 
-       goto bad;
+static inline UChar iregNo ( HReg r )
+{
+   UInt n;
+   vassert(hregClass(r) == HRcInt32);
+   vassert(!hregIsVirtual(r));
+   n = hregNumber(r);
+   vassert(n <= 15);
+   return toUChar(n);
+}
+
+static inline UChar dregNo ( HReg r )
+{
+   UInt n;
+   vassert(hregClass(r) == HRcFlt64);
+   vassert(!hregIsVirtual(r));
+   n = hregNumber(r);
+   vassert(n <= 15);
+   return toUChar(n);
+}
+
+static inline UChar fregNo ( HReg r )
+{
+   UInt n;
+   vassert(hregClass(r) == HRcFlt32);
+   vassert(!hregIsVirtual(r));
+   n = hregNumber(r);
+   vassert(n <= 31);
+   return toUChar(n);
+}
+
+#define BITS4(zzb3,zzb2,zzb1,zzb0) \
+   (((zzb3) << 3) | ((zzb2) << 2) | ((zzb1) << 1) | (zzb0))
+#define X0000  BITS4(0,0,0,0)
+#define X0001  BITS4(0,0,0,1)
+#define X0010  BITS4(0,0,1,0)
+#define X0011  BITS4(0,0,1,1)
+#define X0100  BITS4(0,1,0,0)
+#define X0101  BITS4(0,1,0,1)
+#define X0110  BITS4(0,1,1,0)
+#define X0111  BITS4(0,1,1,1)
+#define X1000  BITS4(1,0,0,0)
+#define X1001  BITS4(1,0,0,1)
+#define X1010  BITS4(1,0,1,0)
+#define X1011  BITS4(1,0,1,1)
+#define X1100  BITS4(1,1,0,0)
+#define X1101  BITS4(1,1,0,1)
+#define X1110  BITS4(1,1,1,0)
+#define X1111  BITS4(1,1,1,1)
+
+#define XXXXX___(zzx7,zzx6,zzx5,zzx4,zzx3) \
+   ((((zzx7) & 0xF) << 28) | (((zzx6) & 0xF) << 24) |  \
+    (((zzx5) & 0xF) << 20) | (((zzx4) & 0xF) << 16) |  \
+    (((zzx3) & 0xF) << 12))
+
+#define XXXXXX__(zzx7,zzx6,zzx5,zzx4,zzx3,zzx2)        \
+   ((((zzx7) & 0xF) << 28) | (((zzx6) & 0xF) << 24) |  \
+    (((zzx5) & 0xF) << 20) | (((zzx4) & 0xF) << 16) |  \
+    (((zzx3) & 0xF) << 12) | (((zzx2) & 0xF) <<  8))
+
+#define XXXXX__X(zzx7,zzx6,zzx5,zzx4,zzx3,zzx0)        \
+   ((((zzx7) & 0xF) << 28) | (((zzx6) & 0xF) << 24) |  \
+    (((zzx5) & 0xF) << 20) | (((zzx4) & 0xF) << 16) |  \
+    (((zzx3) & 0xF) << 12) | (((zzx0) & 0xF) <<  0))
+
+#define XXX___XX(zzx7,zzx6,zzx5,zzx1,zzx0) \
+  ((((zzx7) & 0xF) << 28) | (((zzx6) & 0xF) << 24) | \
+   (((zzx5) & 0xF) << 20) | (((zzx1) & 0xF) << 4) | \
+   (((zzx0) & 0xF) << 0))
+
+#define XXXXXXXX(zzx7,zzx6,zzx5,zzx4,zzx3,zzx2,zzx1,zzx0)  \
+   ((((zzx7) & 0xF) << 28) | (((zzx6) & 0xF) << 24) |  \
+    (((zzx5) & 0xF) << 20) | (((zzx4) & 0xF) << 16) |  \
+    (((zzx3) & 0xF) << 12) | (((zzx2) & 0xF) <<  8) |  \
+    (((zzx1) & 0xF) <<  4) | (((zzx0) & 0xF) <<  0))
+
+/* Generate a skeletal insn that involves an a RI84 shifter operand.
+   Returns a word which is all zeroes apart from bits 25 and 11..0,
+   since it is those that encode the shifter operand (at least to the
+   extent that we care about it.) */
+static UInt skeletal_RI84 ( ARMRI84* ri )
+{
+   UInt instr;
+   if (ri->tag == ARMri84_I84) {
+      vassert(0 == (ri->ARMri84.I84.imm4 & ~0x0F));
+      vassert(0 == (ri->ARMri84.I84.imm8 & ~0xFF));
+      instr = 1 << 25;
+      instr |= (ri->ARMri84.I84.imm4 << 8);
+      instr |= ri->ARMri84.I84.imm8;
+   } else {
+      instr = 0 << 25;
+      instr |= iregNo(ri->ARMri84.R.reg);
+   }
+   return instr;
+}
+
+/* Ditto for RI5.  Resulting word is zeroes apart from bit 4 and bits
+   11..7. */
+static UInt skeletal_RI5 ( ARMRI5* ri )
+{
+   UInt instr;
+   if (ri->tag == ARMri5_I5) {
+      UInt imm5 = ri->ARMri5.I5.imm5;
+      vassert(imm5 >= 1 && imm5 <= 31);
+      instr = 0 << 4;
+      instr |= imm5 << 7;
+   } else {
+      instr = 1 << 4;
+      instr |= iregNo(ri->ARMri5.R.reg) << 8;
+   }
+   return instr;
+}
+
+
+/* Get an immediate into a register, using only that 
+   register.  (very lame..) */
+static UInt* imm32_to_iregNo ( UInt* p, Int rD, UInt imm32 )
+{
+   UInt instr;
+   vassert(rD >= 0 && rD <= 14); // r15 not good to mess with!
+#if 0
+   if (0 == (imm32 & ~0xFF)) {
+      /* mov with a immediate shifter operand of (0, imm32) (??) */
+      instr = XXXXXX__(X1110,X0011,X1010,X0000,rD,X0000);
+      instr |= imm32;
+      *p++ = instr;
+   } else {
+      // this is very bad; causes Dcache pollution
+      // ldr  rD, [pc]
+      instr = XXXXX___(X1110,X0101,X1001,X1111,rD);
+      *p++ = instr;
+      // b .+8
+      instr = 0xEA000000;
+      *p++ = instr;
+      // .word imm32
+      *p++ = imm32;
+   }
+#else
+   /* Generate movw rD, #low16.  Then, if the high 16 are
+      nonzero, generate movt rD, #high16. */
+   UInt lo16 = imm32 & 0xFFFF;
+   UInt hi16 = (imm32 >> 16) & 0xFFFF;
+   instr = XXXXXXXX(0xE, 0x3, 0x0, (lo16 >> 12) & 0xF, rD,
+                    (lo16 >> 8) & 0xF, (lo16 >> 4) & 0xF,
+                    lo16 & 0xF);
+   *p++ = instr;
+   if (hi16 != 0) {
+      instr = XXXXXXXX(0xE, 0x3, 0x4, (hi16 >> 12) & 0xF, rD,
+                       (hi16 >> 8) & 0xF, (hi16 >> 4) & 0xF,
+                       hi16 & 0xF);
+      *p++ = instr;
+   }
+#endif
+   return p;
+}
+
+
+Int emit_ARMInstr ( UChar* buf, Int nbuf, ARMInstr* i,
+                    Bool mode64, void* dispatch ) 
+{
+   UInt* p = (UInt*)buf;
+   vassert(nbuf >= 32);
+   vassert(mode64 == False);
+   vassert(0 == (((HWord)buf) & 3));
+   /* since we branch to lr(r13) to get back to dispatch: */
+   vassert(dispatch == NULL);
+
+   switch (i->tag) {
+      case ARMin_Alu: {
+         UInt     instr, subopc;
+         UInt     rD   = iregNo(i->ARMin.Alu.dst);
+         UInt     rN   = iregNo(i->ARMin.Alu.argL);
+         ARMRI84* argR = i->ARMin.Alu.argR;
+         switch (i->ARMin.Alu.op) {
+            case ARMalu_ADDS: /* fallthru */
+            case ARMalu_ADD:  subopc = X0100; break;
+            case ARMalu_ADC:  subopc = X0101; break;
+            case ARMalu_SUBS: /* fallthru */
+            case ARMalu_SUB:  subopc = X0010; break;
+            case ARMalu_SBC:  subopc = X0110; break;
+            case ARMalu_AND:  subopc = X0000; break;
+            case ARMalu_BIC:  subopc = X1110; break;
+            case ARMalu_OR:   subopc = X1100; break;
+            case ARMalu_XOR:  subopc = X0001; break;
+            default: goto bad;
+         }
+         instr = skeletal_RI84(argR);
+         instr |= XXXXX___(X1110, (1 & (subopc >> 3)),
+                           (subopc << 1) & 0xF, rN, rD);
+         if (i->ARMin.Alu.op == ARMalu_ADDS || i->ARMin.Alu.op == ARMalu_SUBS) {
+            instr |= 1<<20;  /* set the S bit */
+         }
+         *p++ = instr;
+         goto done;
+      }
+      case ARMin_Shift: {
+         UInt    instr, subopc;
+         HReg    rD   = iregNo(i->ARMin.Shift.dst);
+         HReg    rM   = iregNo(i->ARMin.Shift.argL);
+         ARMRI5* argR = i->ARMin.Shift.argR;
+         switch (i->ARMin.Shift.op) {
+            case ARMsh_SHL: subopc = X0000; break;
+            case ARMsh_SHR: subopc = X0001; break;
+            case ARMsh_SAR: subopc = X0010; break;
+            default: goto bad;
+         }
+         instr = skeletal_RI5(argR);
+         instr |= XXXXX__X(X1110,X0001,X1010,X0000,rD, /* _ _ */ rM);
+         instr |= (subopc & 3) << 5;
+         *p++ = instr;
+         goto done;
+      }
+      case ARMin_Unary: {
+         UInt instr;
+         HReg rDst = iregNo(i->ARMin.Unary.dst);
+         HReg rSrc = iregNo(i->ARMin.Unary.src);
+         switch (i->ARMin.Unary.op) {
+            case ARMun_CLZ:
+               instr = XXXXXXXX(X1110,X0001,X0110,X1111,
+                                rDst,X1111,X0001,rSrc);
+               *p++ = instr;
+               goto done;
+            case ARMun_NEG: /* RSB rD,rS,#0 */
+               instr = XXXXX___(X1110,0x2,0x6,rSrc,rDst);
+               *p++ = instr;
+               goto done;
+            case ARMun_NOT: {
+               UInt subopc = X1111; /* MVN */
+               instr = rSrc;
+               instr |= XXXXX___(X1110, (1 & (subopc >> 3)),
+                                 (subopc << 1) & 0xF, 0, rDst);
+               *p++ = instr;
+               goto done;
+            }
+            default:
+               break;
+         }
+         goto bad;
+      }
+      case ARMin_CmpOrTst: {
+         UInt instr  = skeletal_RI84(i->ARMin.CmpOrTst.argR);
+         UInt subopc = i->ARMin.CmpOrTst.isCmp ? X1010 : X1000;
+         UInt SBZ    = 0;
+         instr |= XXXXX___(X1110, (1 & (subopc >> 3)),
+                           ((subopc << 1) & 0xF) | 1,
+                           i->ARMin.CmpOrTst.argL, SBZ );
+         *p++ = instr;
+         goto done;
+      }
+      case ARMin_Mov: {
+         UInt instr  = skeletal_RI84(i->ARMin.Mov.src);
+         UInt subopc = X1101; /* MOV */
+         UInt SBZ    = 0;
+         instr |= XXXXX___(X1110, (1 & (subopc >> 3)),
+                           (subopc << 1) & 0xF, SBZ, i->ARMin.Mov.dst);
+         *p++ = instr;
+         goto done;
+      }
+      case ARMin_Imm32: {
+         p = imm32_to_iregNo( (UInt*)p, iregNo(i->ARMin.Imm32.dst),
+                                        i->ARMin.Imm32.imm32 );
+         goto done;
+      }
+      case ARMin_LdSt32:
+      case ARMin_LdSt8U: {
+         UInt       bL, bB;
+         HReg       rD;
+         ARMAMode1* am;
+         if (i->tag == ARMin_LdSt32) {
+            bB = 0;
+            bL = i->ARMin.LdSt32.isLoad ? 1 : 0;
+            am = i->ARMin.LdSt32.amode;
+            rD = i->ARMin.LdSt32.rD;
+         } else {
+            bB = 1;
+            bL = i->ARMin.LdSt8U.isLoad ? 1 : 0;
+            am = i->ARMin.LdSt8U.amode;
+            rD = i->ARMin.LdSt8U.rD;
+         }
+         if (am->tag == ARMam1_RI) {
+            Int  simm12;
+            UInt instr, bP;
+            if (am->ARMam1.RI.simm13 < 0) {
+               bP = 0;
+               simm12 = -am->ARMam1.RI.simm13;
+            } else {
+               bP = 1;
+               simm12 = am->ARMam1.RI.simm13;
+            }
+            vassert(simm12 >= 0 && simm12 <= 4095);
+            instr = XXXXX___(X1110,X0101,BITS4(bP,bB,0,bL),
+                             iregNo(am->ARMam1.RI.reg),
+                             iregNo(rD));
+            instr |= simm12;
+            *p++ = instr;
+            goto done;
+         } else {
+            // RR case
+            goto bad;
+         }
+      }
+      case ARMin_LdSt16: {
+         HReg       rD = i->ARMin.LdSt16.rD;
+         UInt       bS = i->ARMin.LdSt16.signedLoad ? 1 : 0;
+         UInt       bL = i->ARMin.LdSt16.isLoad ? 1 : 0;
+         ARMAMode2* am = i->ARMin.LdSt16.amode;
+         if (am->tag == ARMam2_RI) {
+            HReg rN = am->ARMam2.RI.reg;
+            Int  simm8;
+            UInt bP, imm8hi, imm8lo, instr;
+            if (am->ARMam2.RI.simm9 < 0) {
+               bP = 0;
+               simm8 = -am->ARMam2.RI.simm9;
+            } else {
+               bP = 1;
+               simm8 = am->ARMam2.RI.simm9;
+            }
+            vassert(simm8 >= 0 && simm8 <= 255);
+            imm8hi = (simm8 >> 4) & 0xF;
+            imm8lo = simm8 & 0xF;
+            vassert(!(bL == 0 && bS == 1)); // "! signed store"
+            /**/ if (bL == 0 && bS == 0) {
+               // strh
+               instr = XXXXXXXX(X1110,X0001, BITS4(bP,1,0,0), iregNo(rN),
+                                iregNo(rD), imm8hi, X1011, imm8lo);
+               *p++ = instr;
+               goto done;
+            }
+            else if (bL == 1 && bS == 0) {
+               // ldrh
+               instr = XXXXXXXX(X1110,X0001, BITS4(bP,1,0,1), iregNo(rN),
+                                iregNo(rD), imm8hi, X1011, imm8lo);
+               *p++ = instr;
+               goto done;
+            }
+            else if (bL == 1 && bS == 1) {
+               goto bad;
+            }
+            else vassert(0); // ill-constructed insn
+         } else {
+            // RR case
+            goto bad;
+         }
+      }
+      case ARMin_Ld8S:
+         goto bad;
+      case ARMin_Goto: {
+         UInt        instr;
+         IRJumpKind  jk    = i->ARMin.Goto.jk;
+         ARMCondCode cond  = i->ARMin.Goto.cond;
+         UInt        rnext = iregNo(i->ARMin.Goto.gnext);
+         Int         trc   = -1;
+         switch (jk) {
+            case Ijk_Ret: case Ijk_Call: case Ijk_Boring:
+               break; /* no need to set GST in these common cases */
+            case Ijk_ClientReq:
+               trc = VEX_TRC_JMP_CLIENTREQ; break;
+            case Ijk_Sys_int128:
+            case Ijk_Sys_int129:
+            case Ijk_Sys_int130:
+            case Ijk_Yield:
+            case Ijk_EmWarn:
+            case Ijk_MapFail:
+               goto unhandled_jk;
+            case Ijk_NoDecode:
+               trc = VEX_TRC_JMP_NODECODE; break;
+            case Ijk_TInval:
+               trc = VEX_TRC_JMP_TINVAL; break;
+            case Ijk_NoRedir:
+               trc = VEX_TRC_JMP_NOREDIR; break;
+            case Ijk_Sys_sysenter:
+            case Ijk_SigTRAP:
+            case Ijk_SigSEGV:
+               goto unhandled_jk;
+            case Ijk_Sys_syscall:
+               trc = VEX_TRC_JMP_SYS_SYSCALL; break;
+            unhandled_jk:
+            default:
+               goto bad;
+         }
+         if (trc != -1) {
+            // mov{cond} r8, #trc
+            vassert(trc >= 0 && trc <= 255);
+            instr = (cond << 28) | 0x03A08000 | (0xFF & (UInt)trc);
+            *p++ = instr;
+         }
+         // mov{cond} r0, rnext
+         if (rnext != 0) {
+            instr = (cond << 28) | 0x01A00000 | rnext;
+            *p++ = instr;
+         }
+         // bx{cond} r14
+         instr =(cond << 28) | 0x012FFF1E;
+         *p++ = instr;
+         goto done;
+      }
+      case ARMin_CMov: {
+         UInt instr  = skeletal_RI84(i->ARMin.CMov.src);
+         UInt subopc = X1101; /* MOV */
+         UInt SBZ    = 0;
+         instr |= XXXXX___(i->ARMin.CMov.cond, (1 & (subopc >> 3)),
+                           (subopc << 1) & 0xF, SBZ, i->ARMin.CMov.dst);
+         *p++ = instr;
+         goto done;
+      }
+      case ARMin_Call: {
+         UInt instr;
+         /* Decide on a scratch reg used to hold to the call address.
+            This has to be done as per the comments in getRegUsage. */
+         Int scratchNo;
+         switch (i->ARMin.Call.nArgRegs) {
+            case 0:  scratchNo = 0;  break;
+            case 1:  scratchNo = 1;  break;
+            case 2:  scratchNo = 2;  break;
+            case 3:  scratchNo = 3;  break;
+            case 4:  scratchNo = 11; break;
+            default: vassert(0);
+         }
+         // r"scratchNo" = &target
+         p = imm32_to_iregNo( (UInt*)p,
+                              scratchNo, (UInt)i->ARMin.Call.target );
+         // blx{cond} r"scratchNo"
+         instr = XXX___XX(i->ARMin.Call.cond, X0001, X0010, /*___*/
+                          X0011, scratchNo);
+         instr |= 0xFFF << 8; // stick in the SBOnes
+         *p++ = instr;
+         goto done;
+      }
+      case ARMin_Mul: {
+         /* E0000392   mul     r0, r2, r3
+            E0810392   umull   r0(LO), r1(HI), r2, r3
+            E0C10392   smull   r0(LO), r1(HI), r2, r3
+         */
+         switch (i->ARMin.Mul.op) {
+            case ARMmul_PLAIN: *p++ = 0xE0000392; goto done;
+            case ARMmul_ZX:    *p++ = 0xE0810392; goto done;
+            case ARMmul_SX:    *p++ = 0xE0C10392; goto done;
+            default: vassert(0);
+         }
+         goto bad;
+      }
+      case ARMin_LdrEX: {
+         /* E1910F9F   ldrex    r0, [r1]
+            E1F10F9F   ldrexh   r0, [r1]
+            E1D10F9F   ldrexb   r0, [r1]
+         */
+         switch (i->ARMin.LdrEX.szB) {
+            case 4: *p++ = 0xE1910F9F; goto done;
+            //case 2: *p++ = 0xE1F10F9F; goto done;
+            case 1: *p++ = 0xE1D10F9F; goto done;
+            default: break;
+         }
+         goto bad;
+      }
+      case ARMin_StrEX: {
+         /* E1820F91   strex   r0, r1, [r2]
+            E1E20F91   strexh  r0, r1, [r2]
+            E1C20F91   strexb  r0, r1, [r2]
+         */
+         switch (i->ARMin.StrEX.szB) {
+            case 4: *p++ = 0xE1820F91; goto done;
+            //case 2: *p++ = 0xE1E20F91; goto done;
+            case 1: *p++ = 0xE1C20F91; goto done;
+            default: break;
+         }
+         goto bad;
+      }
+      case ARMin_VLdStD: {
+         UInt dD     = dregNo(i->ARMin.VLdStD.dD);
+         UInt rN     = iregNo(i->ARMin.VLdStD.amode->reg);
+         Int  simm11 = i->ARMin.VLdStD.amode->simm11;
+         UInt off8   = simm11 >= 0 ? simm11 : ((UInt)(-simm11));
+         UInt bU     = simm11 >= 0 ? 1 : 0;
+         UInt bL     = i->ARMin.VLdStD.isLoad ? 1 : 0;
+         UInt insn;
+         vassert(0 == (off8 & 3));
+         off8 >>= 2;
+         vassert(0 == (off8 & 0xFFFFFF00));
+         insn = XXXXXX__(0xE,X1101,BITS4(bU,0,0,bL),rN,dD,X1011);
+         insn |= off8;
+         *p++ = insn;
+         goto done;
+      }
+      case ARMin_VLdStS: {
+         UInt fD     = fregNo(i->ARMin.VLdStS.fD);
+         UInt rN     = iregNo(i->ARMin.VLdStS.amode->reg);
+         Int  simm11 = i->ARMin.VLdStS.amode->simm11;
+         UInt off8   = simm11 >= 0 ? simm11 : ((UInt)(-simm11));
+         UInt bU     = simm11 >= 0 ? 1 : 0;
+         UInt bL     = i->ARMin.VLdStS.isLoad ? 1 : 0;
+         UInt bD     = fD & 1;
+         UInt insn;
+         vassert(0 == (off8 & 3));
+         off8 >>= 2;
+         vassert(0 == (off8 & 0xFFFFFF00));
+         insn = XXXXXX__(0xE,X1101,BITS4(bU,bD,0,bL),rN, (fD >> 1), X1010);
+         insn |= off8;
+         *p++ = insn;
+         goto done;
+      }
+      case ARMin_VAluD: {
+         UInt dN = dregNo(i->ARMin.VAluD.argL);
+         UInt dD = dregNo(i->ARMin.VAluD.dst);
+         UInt dM = dregNo(i->ARMin.VAluD.argR);
+         UInt pqrs = X1111; /* undefined */
+         switch (i->ARMin.VAluD.op) {
+            case ARMvfp_ADD: pqrs = X0110; break;
+            case ARMvfp_SUB: pqrs = X0111; break;
+            case ARMvfp_MUL: pqrs = X0100; break;
+            case ARMvfp_DIV: pqrs = X1000; break;
+            default: goto bad;
+         }
+         vassert(pqrs != X1111);
+         UInt bP  = (pqrs >> 3) & 1;
+         UInt bQ  = (pqrs >> 2) & 1;
+         UInt bR  = (pqrs >> 1) & 1;
+         UInt bS  = (pqrs >> 0) & 1;
+         UInt insn = XXXXXXXX(0xE, X1110, BITS4(bP,0,bQ,bR), dN, dD,
+                              X1011, BITS4(0,bS,0,0), dM);
+         *p++ = insn;
+         goto done;
+      }
+      case ARMin_VAluS: {
+         UInt dN = fregNo(i->ARMin.VAluS.argL);
+         UInt dD = fregNo(i->ARMin.VAluS.dst);
+         UInt dM = fregNo(i->ARMin.VAluS.argR);
+         UInt bN = dN & 1;
+         UInt bD = dD & 1;
+         UInt bM = dM & 1;
+         UInt pqrs = X1111; /* undefined */
+         switch (i->ARMin.VAluS.op) {
+            case ARMvfp_ADD: pqrs = X0110; break;
+            case ARMvfp_SUB: pqrs = X0111; break;
+            case ARMvfp_MUL: pqrs = X0100; break;
+            case ARMvfp_DIV: pqrs = X1000; break;
+            default: goto bad;
+         }
+         vassert(pqrs != X1111);
+         UInt bP  = (pqrs >> 3) & 1;
+         UInt bQ  = (pqrs >> 2) & 1;
+         UInt bR  = (pqrs >> 1) & 1;
+         UInt bS  = (pqrs >> 0) & 1;
+         UInt insn = XXXXXXXX(0xE, X1110, BITS4(bP,bD,bQ,bR),
+                              (dN >> 1), (dD >> 1),
+                              X1010, BITS4(bN,bS,bM,0), (dM >> 1));
+         *p++ = insn;
+         goto done;
+      }
+      case ARMin_VUnaryD: {
+         UInt dD   = dregNo(i->ARMin.VUnaryD.dst);
+         UInt dM   = dregNo(i->ARMin.VUnaryD.src);
+         UInt insn = 0;
+         switch (i->ARMin.VUnaryD.op) {
+            case ARMvfpu_COPY:
+               insn = XXXXXXXX(0xE, X1110,X1011,X0000,dD,X1011,X0100,dM);
+               break;
+            case ARMvfpu_ABS:
+               insn = XXXXXXXX(0xE, X1110,X1011,X0000,dD,X1011,X1100,dM);
+               break;
+            case ARMvfpu_NEG:
+               insn = XXXXXXXX(0xE, X1110,X1011,X0001,dD,X1011,X0100,dM);
+               break;
+            case ARMvfpu_SQRT:
+               insn = XXXXXXXX(0xE, X1110,X1011,X0001,dD,X1011,X1100,dM);
+               break;
+            default:
+               goto bad;
+         }
+         *p++ = insn;
+         goto done;
+      }
+      case ARMin_VUnaryS: {
+         UInt fD   = fregNo(i->ARMin.VUnaryS.dst);
+         UInt fM   = fregNo(i->ARMin.VUnaryS.src);
+         UInt insn = 0;
+         switch (i->ARMin.VUnaryS.op) {
+            case ARMvfpu_COPY:
+               insn = XXXXXXXX(0xE, X1110, BITS4(1,(fD & 1),1,1), X0000,
+                               (fD >> 1), X1010, BITS4(0,1,(fM & 1),0),
+                               (fM >> 1));
+               break;
+            case ARMvfpu_ABS:
+               insn = XXXXXXXX(0xE, X1110, BITS4(1,(fD & 1),1,1), X0000,
+                               (fD >> 1), X1010, BITS4(1,1,(fM & 1),0),
+                               (fM >> 1));
+               break;
+            case ARMvfpu_NEG:
+               insn = XXXXXXXX(0xE, X1110, BITS4(1,(fD & 1),1,1), X0001,
+                               (fD >> 1), X1010, BITS4(0,1,(fM & 1),0),
+                               (fM >> 1));
+               break;
+            case ARMvfpu_SQRT:
+               insn = XXXXXXXX(0xE, X1110, BITS4(1,(fD & 1),1,1), X0001,
+                               (fD >> 1), X1010, BITS4(1,1,(fM & 1),0),
+                               (fM >> 1));
+               break;
+            default:
+               goto bad;
+         }
+         *p++ = insn;
+         goto done;
+      }
+      case ARMin_VCmpD: {
+         UInt dD   = dregNo(i->ARMin.VCmpD.argL);
+         UInt dM   = dregNo(i->ARMin.VCmpD.argR);
+         UInt insn = XXXXXXXX(0xE, X1110, X1011, X0100, dD, X1011, X0100, dM);
+         *p++ = insn;       /* FCMPD dD, dM */
+         *p++ = 0xEEF1FA10; /* FMSTAT */
+         goto done;
+      }
+      case ARMin_VCMovD: {
+         UInt cc = (UInt)i->ARMin.VCMovD.cond;
+         UInt dD = dregNo(i->ARMin.VCMovD.dst);
+         UInt dM = dregNo(i->ARMin.VCMovD.src);
+         vassert(cc < 16 && cc != ARMcc_AL);
+         UInt insn = XXXXXXXX(cc, X1110,X1011,X0000,dD,X1011,X0100,dM);
+         *p++ = insn;
+         goto done;
+      }
+      case ARMin_VCMovS: {
+         UInt cc = (UInt)i->ARMin.VCMovS.cond;
+         UInt fD = fregNo(i->ARMin.VCMovS.dst);
+         UInt fM = fregNo(i->ARMin.VCMovS.src);
+         vassert(cc < 16 && cc != ARMcc_AL);
+         UInt insn = XXXXXXXX(cc, X1110, BITS4(1,(fD & 1),1,1),
+                              X0000,(fD >> 1),X1010,
+                              BITS4(0,1,(fM & 1),0), (fM >> 1));
+         *p++ = insn;
+         goto done;
+      }
+      case ARMin_VCvtSD: {
+         if (i->ARMin.VCvtSD.sToD) {
+            UInt dD = dregNo(i->ARMin.VCvtSD.dst);
+            UInt fM = fregNo(i->ARMin.VCvtSD.src);
+            UInt insn = XXXXXXXX(0xE, X1110, X1011, X0111, dD, X1010,
+                                 BITS4(1,1, (fM & 1), 0),
+                                 (fM >> 1));
+            *p++ = insn;
+            goto done;
+         } else {
+            UInt fD = fregNo(i->ARMin.VCvtSD.dst);
+            UInt dM = dregNo(i->ARMin.VCvtSD.src);
+            UInt insn = XXXXXXXX(0xE, X1110, BITS4(1,(fD & 1),1,1),
+                                 X0111, (fD >> 1),
+                                 X1011, X1100, dM);
+            *p++ = insn;
+            goto done;
+         }
+         goto bad;
+      }
+      case ARMin_VXferD: {
+         UInt dD  = dregNo(i->ARMin.VXferD.dD);
+         UInt rHi = iregNo(i->ARMin.VXferD.rHi);
+         UInt rLo = iregNo(i->ARMin.VXferD.rLo);
+         /* vmov dD, rLo, rHi is
+            E C 4 rHi rLo B (0,0,dD[4],1) dD[3:0]
+            vmov rLo, rHi, dD is
+            E C 5 rHi rLo B (0,0,dD[4],1) dD[3:0]
+         */
+         UInt insn
+            = XXXXXXXX(0xE, 0xC, i->ARMin.VXferD.toD ? 4 : 5,
+                       rHi, rLo, 0xB,
+                       BITS4(0,0, ((dD >> 4) & 1), 1), (dD & 0xF));
+         *p++ = insn;
+         goto done;
+      }
+      case ARMin_VXferS: {
+         UInt fD  = fregNo(i->ARMin.VXferS.fD);
+         UInt rLo = iregNo(i->ARMin.VXferS.rLo);
+         /* vmov fD, rLo is
+            E E 0 fD[4:1] rLo A (fD[0],0,0,1) 0
+            vmov rLo, fD is
+            E E 1 fD[4:1] rLo A (fD[0],0,0,1) 0
+         */
+         UInt insn
+            = XXXXXXXX(0xE, 0xE, i->ARMin.VXferS.toS ? 0 : 1,
+                       (fD >> 1) & 0xF, rLo, 0xA, 
+                       BITS4((fD & 1),0,0,1), 0);
+         *p++ = insn;
+         goto done;
+      }
+      case ARMin_VCvtID: {
+         Bool iToD = i->ARMin.VCvtID.iToD;
+         Bool syned = i->ARMin.VCvtID.syned;
+         if (iToD && syned) {
+            // FSITOD: I32S-in-freg to F64-in-dreg
+            UInt regF = fregNo(i->ARMin.VCvtID.src);
+            UInt regD = dregNo(i->ARMin.VCvtID.dst);
+            UInt insn = XXXXXXXX(0xE, X1110, X1011, X1000, regD,
+                                 X1011, BITS4(1,1,(regF & 1),0),
+                                 (regF >> 1) & 0xF);
+            *p++ = insn;
+            goto done;
+         }
+         if (iToD && (!syned)) {
+            // FUITOD: I32U-in-freg to F64-in-dreg
+            UInt regF = fregNo(i->ARMin.VCvtID.src);
+            UInt regD = dregNo(i->ARMin.VCvtID.dst);
+            UInt insn = XXXXXXXX(0xE, X1110, X1011, X1000, regD,
+                                 X1011, BITS4(0,1,(regF & 1),0),
+                                 (regF >> 1) & 0xF);
+            *p++ = insn;
+            goto done;
+         }
+         if ((!iToD) && syned) {
+            // FTOSID: F64-in-dreg to I32S-in-freg
+            UInt regD = dregNo(i->ARMin.VCvtID.src);
+            UInt regF = fregNo(i->ARMin.VCvtID.dst);
+            UInt insn = XXXXXXXX(0xE, X1110, BITS4(1,(regF & 1),1,1),
+                                 X1101, (regF >> 1) & 0xF,
+                                 X1011, X0100, regD);
+            *p++ = insn;
+            goto done;
+         }
+         if ((!iToD) && (!syned)) {
+            // FTOUID: F64-in-dreg to I32U-in-freg
+            UInt regD = dregNo(i->ARMin.VCvtID.src);
+            UInt regF = fregNo(i->ARMin.VCvtID.dst);
+            UInt insn = XXXXXXXX(0xE, X1110, BITS4(1,(regF & 1),1,1),
+                                 X1100, (regF >> 1) & 0xF,
+                                 X1011, X0100, regD);
+            *p++ = insn;
+            goto done;
+         }
+         /*UNREACHED*/
+         vassert(0);
+      }
+      case ARMin_FPSCR: {
+         Bool toFPSCR = i->ARMin.FPSCR.toFPSCR;
+         HReg iReg    = iregNo(i->ARMin.FPSCR.iReg);
+         if (toFPSCR) {
+            /* fmxr fpscr, iReg is EEE1 iReg A10 */
+            *p++ = 0xEEE10A10 | ((iReg & 0xF) << 12);
+            goto done;
+         }
+         goto bad; // FPSCR -> iReg case currently ATC
+      }
+      default: 
+         goto bad;
     }
 
- bad:
-    ppARMInstr(i);
-    vpanic("emit_ARMInstr");
-    /*NOTREACHED*/
 bad:
+   ppARMInstr(i);
+   vpanic("emit_ARMInstr");
+   /*NOTREACHED*/
     
-// done:
-    vassert(p - &buf[0] <= 32);
-    return p - &buf[0];
+  done:
+   vassert(((UChar*)p) - &buf[0] <= 32);
+   return ((UChar*)p) - &buf[0];
 }
 
+#undef BITS4
+#undef X0000
+#undef X0001
+#undef X0010
+#undef X0011
+#undef X0100
+#undef X0101
+#undef X0110
+#undef X0111
+#undef X1000
+#undef X1001
+#undef X1010
+#undef X1011
+#undef X1100
+#undef X1101
+#undef X1110
+#undef X1111
+#undef XXXXX___
+#undef XXXXXX__
+#undef XXX___XX
+#undef XXXXX__X
+#undef XXXXXXXX
 
 /*---------------------------------------------------------------*/
 /*--- end                                     host_arm_defs.c ---*/
index 1d22685ec15b7ae67e0c4f887e7b4772e02a2c1c..5fd947f0686f4725bc956daccff7371c6834ae10 100644 (file)
    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.
 */
 
 #ifndef __VEX_HOST_ARM_DEFS_H
 
 extern void ppHRegARM ( HReg );
 
-extern HReg hregARM_R0 ( void );
-extern HReg hregARM_R1 ( void );
-extern HReg hregARM_R2 ( void );
-extern HReg hregARM_R3 ( void );
-extern HReg hregARM_R4 ( void );
-extern HReg hregARM_R5 ( void );
-extern HReg hregARM_R6 ( void );
-extern HReg hregARM_R7 ( void );
-extern HReg hregARM_R8 ( void );
-extern HReg hregARM_R9 ( void );
+extern HReg hregARM_R0  ( void );
+extern HReg hregARM_R1  ( void );
+extern HReg hregARM_R2  ( void );
+extern HReg hregARM_R3  ( void );
+extern HReg hregARM_R4  ( void );
+extern HReg hregARM_R5  ( void );
+extern HReg hregARM_R6  ( void );
+extern HReg hregARM_R7  ( void );
+extern HReg hregARM_R8  ( void );
+extern HReg hregARM_R9  ( void );
 extern HReg hregARM_R10 ( void );
 extern HReg hregARM_R11 ( void );
 extern HReg hregARM_R12 ( void );
 extern HReg hregARM_R13 ( void );
 extern HReg hregARM_R14 ( void );
 extern HReg hregARM_R15 ( void );
+extern HReg hregARM_D8  ( void );
+extern HReg hregARM_D9  ( void );
+extern HReg hregARM_D10 ( void );
+extern HReg hregARM_D11 ( void );
+extern HReg hregARM_D12 ( void );
+extern HReg hregARM_S26 ( void );
+extern HReg hregARM_S27 ( void );
+extern HReg hregARM_S28 ( void );
+extern HReg hregARM_S29 ( void );
+extern HReg hregARM_S30 ( void );
 
-
-#define GET_BP_REG() hregARM_R12()  // x86 ebp
-#define GET_SP_REG() hregARM_R13()  // x86 esp
-#define GET_LN_REG() hregARM_R14()
-#define GET_PC_REG() hregARM_R15()
-
-
+/* Number of registers used arg passing in function calls */
+#define ARM_N_ARGREGS 4   /* r0, r1, r2, r3 */
 
 
-/* --------- Condition codes, Intel encoding. --------- */
+/* --------- Condition codes. --------- */
 
 typedef
    enum {
-      ARMccEQ     = 0,  /* equal                               : Z=1 */
-      ARMccNE     = 1,  /* not equal                           : Z=0 */
+      ARMcc_EQ  = 0,  /* equal                          : Z=1 */
+      ARMcc_NE  = 1,  /* not equal                      : Z=0 */
 
-      ARMccHS     = 2,  /* >=u (higher or same)                : C=1 */
-      ARMccLO     = 3,  /* <u  (lower)                         : C=0 */
+      ARMcc_HS  = 2,  /* >=u (higher or same)           : C=1 */
+      ARMcc_LO  = 3,  /* <u  (lower)                    : C=0 */
 
-      ARMccMI     = 4,  /* minus (negative)                    : N=1 */
-      ARMccPL     = 5,  /* plus (zero or +ve)                  : N=0 */
+      ARMcc_MI  = 4,  /* minus (negative)               : N=1 */
+      ARMcc_PL  = 5,  /* plus (zero or +ve)             : N=0 */
 
-      ARMccVS     = 6,  /* overflow                            : V=1 */
-      ARMccVC     = 7,  /* no overflow                         : V=0 */
+      ARMcc_VS  = 6,  /* overflow                       : V=1 */
+      ARMcc_VC  = 7,  /* no overflow                    : V=0 */
 
-      ARMccHI     = 8,  /* >u   (higher)                       : C=1 && Z=0 */
-      ARMccLS     = 9,  /* <=u  (lower or same)                : C=0 || Z=1 */
+      ARMcc_HI  = 8,  /* >u   (higher)                  : C=1 && Z=0 */
+      ARMcc_LS  = 9,  /* <=u  (lower or same)           : C=0 || Z=1 */
 
-      ARMccGE     = 10, /* >=s (signed greater or equal)       : N=V */
-      ARMccLT     = 11, /* <s  (signed less than)              : N!=V */
+      ARMcc_GE  = 10, /* >=s (signed greater or equal)  : N=V */
+      ARMcc_LT  = 11, /* <s  (signed less than)         : N!=V */
 
-      ARMccGT     = 12, /* >s  (signed greater)                : Z=0 && N=V */
-      ARMccLE     = 13, /* <=s (signed less or equal)          : Z=1 || N!=V */
+      ARMcc_GT  = 12, /* >s  (signed greater)           : Z=0 && N=V */
+      ARMcc_LE  = 13, /* <=s (signed less or equal)     : Z=1 || N!=V */
 
-      ARMccAL     = 14, /* always (unconditional) */
-      ARMccNV     = 15  /* never (basically undefined meaning), deprecated */
+      ARMcc_AL  = 14, /* always (unconditional) */
+      ARMcc_NV  = 15  /* never (basically undefined meaning), deprecated */
    }
    ARMCondCode;
 
@@ -116,95 +116,44 @@ extern HChar* showARMCondCode ( ARMCondCode );
 
 
 
-
-/* --------- Immediate types. --------- */
-
-typedef UInt ARMImm4;
-typedef UInt ARMImm5;
-typedef UInt ARMImm8;
-typedef UInt ARMImm12;
-typedef UInt ARMImm24; // Branch imm
-typedef
-  struct {
-      ARMImm8 imm;
-      ARMImm4 rot;
-  }
-  ARMImm12A;   /* extended (rotated) immedate */
-
-extern Bool mk_ARMImm12A ( UInt, ARMImm12A*);
-
-
-
 /* --------- Memory address expressions (amodes). --------- */
 
 /* --- Addressing Mode 1 --- */
 typedef
    enum {
-       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 */
+      ARMam1_RI=1,   /* reg +/- imm12 */
+      ARMam1_RRS     /* reg1 + (reg2 << 0, 1 2 or 3) */
    }
    ARMAMode1Tag;
 
 typedef
    struct {
-       ARMAMode1Tag tag;
-       union {
-          struct {
-              ARMImm12A imm;
-          } I12A;
-          struct {
-              HReg Rm;
-              ARMImm5 imm;
-          } ShlI;
-          struct {
-              HReg Rm;
-              ARMImm5 imm;
-          } ShrI;
-          struct {
-              HReg Rm;
-              ARMImm5 imm;
-          } SarI;
-          struct {
-              HReg Rm;
-              HReg Rs;
-          } ShlR;
-          struct {
-              HReg Rm;
-              HReg Rs;
-          } ShrR;
-          struct {
-              HReg Rm;
-              HReg Rs;
-          } SarR;
-       } ARMam1;
+      ARMAMode1Tag tag;
+      union {
+         struct {
+            HReg reg;
+            Int  simm13; /* -4095 .. +4095 */
+         } RI;
+         struct {
+            HReg base;
+            HReg index;
+            UInt shift; /* 0, 1 2 or 3 */
+         } RRS;
+      } ARMam1;
    }
    ARMAMode1;
 
-extern ARMAMode1* ARMAMode1_I12A ( ARMImm12A );
-extern ARMAMode1* ARMAMode1_ShlI ( HReg, ARMImm5 );
-extern ARMAMode1* ARMAMode1_ShrI ( HReg, ARMImm5 );
-extern ARMAMode1* ARMAMode1_SarI ( HReg, ARMImm5 );
-extern ARMAMode1* ARMAMode1_ShlR ( HReg, HReg );
-extern ARMAMode1* ARMAMode1_ShrR ( HReg, HReg );
-extern ARMAMode1* ARMAMode1_SarR ( HReg, HReg );
-
-extern ARMAMode1* dopyARMAMode1 ( ARMAMode1* );
+extern ARMAMode1* ARMAMode1_RI  ( HReg reg, Int simm13 );
+extern ARMAMode1* ARMAMode1_RRS ( HReg base, HReg index, UInt shift );
 
 extern void ppARMAMode1 ( ARMAMode1* );
 
 
-
 /* --- Addressing Mode 2 --- */
 typedef
    enum {
-     ARMam2_RI,      /* Reg +/- Imm12 */
-     ARMam2_RR,       /* Reg +/- Reg */
-     ARMam2_RRS,       /* Reg +/- (Reg << Imm5) */
+      ARMam2_RI=3,   /* reg +/- imm8 */
+      ARMam2_RR      /* reg1 + reg2 */
    }
    ARMAMode2Tag;
 
@@ -213,245 +162,473 @@ typedef
       ARMAMode2Tag tag;
       union {
          struct {
-            HReg Rn;
-            ARMImm12 imm;
+            HReg reg;
+            Int  simm9; /* -255 .. 255 */
          } RI;
          struct {
-            HReg Rn;
-            HReg Rm;
-        } RR;
-         struct {
-            HReg Rn;
-            HReg Rm;
-            ARMImm5 shift;
-        } RRS;
+            HReg base;
+            HReg index;
+         } RR;
       } ARMam2;
    }
    ARMAMode2;
 
-extern ARMAMode2* ARMAMode2_RI ( HReg, ARMImm12 );
-extern ARMAMode2* ARMAMode2_RR ( HReg, HReg );
-extern ARMAMode2* ARMAMode2_RRS ( HReg, HReg, ARMImm5 );
-
-extern ARMAMode2* dopyARMAMode2 ( ARMAMode2* );
+extern ARMAMode2* ARMAMode2_RI ( HReg reg, Int simm9 );
+extern ARMAMode2* ARMAMode2_RR ( HReg base, HReg index );
 
 extern void ppARMAMode2 ( ARMAMode2* );
 
 
-/* --- Addressing Mode 3 --- */
+/* --- Addressing Mode suitable for VFP --- */
+/* The simm11 is encoded as 8 bits + 1 sign bit,
+   so can only be 0 % 4. */
+typedef
+   struct {
+      HReg reg;
+      Int  simm11; /* -1020, -1016 .. 1016, 1020 */
+   }
+   ARMAModeV;
+
+extern ARMAModeV* mkARMAModeV ( HReg reg, Int simm11 );
+
+extern void ppARMAModeV ( ARMAModeV* );
+
+
+/* --------- Reg or imm-8x4 operands --------- */
+/* a.k.a (a very restricted form of) Shifter Operand,
+   in the ARM parlance. */
+
 typedef
    enum {
-     ARMam3_RI,       /* Reg +/- Imm8 */
-     ARMam3_RR,       /* Reg +/- Reg */
+      ARMri84_I84=5,   /* imm8 `ror` (2 * imm4) */
+      ARMri84_R        /* reg */
    }
-   ARMAMode3Tag;
+   ARMRI84Tag;
 
 typedef
    struct {
-      ARMAMode3Tag tag;
+      ARMRI84Tag tag;
       union {
          struct {
-            HReg Rn;
-            ARMImm8 imm;
-         } RI;
+            UShort imm8;
+            UShort imm4;
+         } I84;
          struct {
-            HReg Rn;
-            HReg Rm;
-        } RR;
-      } ARMam3;
+            HReg reg;
+         } R;
+      } ARMri84;
    }
-   ARMAMode3;
+   ARMRI84;
 
+extern ARMRI84* ARMRI84_I84 ( UShort imm8, UShort imm4 );
+extern ARMRI84* ARMRI84_R   ( HReg );
 
-extern ARMAMode3* ARMAMode3_RI ( HReg, ARMImm8 );
-extern ARMAMode3* ARMAMode3_RR ( HReg, HReg );
+extern void ppARMRI84 ( ARMRI84* );
+
+
+/* --------- Reg or imm5 operands --------- */
+typedef
+   enum {
+      ARMri5_I5=7,   /* imm5, 1 .. 31 only (no zero!) */
+      ARMri5_R       /* reg */
+   }
+   ARMRI5Tag;
 
-extern ARMAMode3* dopyARMAMode3 ( ARMAMode3* );
+typedef
+   struct {
+      ARMRI5Tag tag;
+      union {
+         struct {
+            UInt imm5;
+         } I5;
+         struct {
+            HReg reg;
+         } R;
+      } ARMri5;
+   }
+   ARMRI5;
 
-extern void ppARMAMode3 ( ARMAMode3* );
+extern ARMRI5* ARMRI5_I5 ( UInt imm5 );
+extern ARMRI5* ARMRI5_R  ( HReg );
 
+extern void ppARMRI5 ( ARMRI5* );
 
 
+/* --------- Instructions. --------- */
 
-/* ------ Branch destination ------ */
+/* --------- */
 typedef
    enum {
-       ARMbdImm,
-       ARMbdReg
+      ARMalu_ADD=10,   /* plain 32-bit add */
+      ARMalu_ADDS,     /* 32-bit add, and set the flags */
+      ARMalu_ADC,      /* 32-bit add with carry */
+      ARMalu_SUB,      /* plain 32-bit subtract */
+      ARMalu_SUBS,     /* 32-bit subtract, and set the flags */
+      ARMalu_SBC,      /* 32-bit subtract with carry */
+      ARMalu_AND,
+      ARMalu_BIC,
+      ARMalu_OR,
+      ARMalu_XOR
    }
-   ARMBranchTag;
+   ARMAluOp;
+
+extern HChar* showARMAluOp ( ARMAluOp op );
+
 
 typedef
-  struct {
-      ARMBranchTag tag;
-      union {
-         struct {
-             ARMImm24 imm24;
-         } Imm;
-         struct {
-             HReg reg;
-         } Reg;
-      } ARMbd;
-  }
-  ARMBranchDest;
+   enum {
+      ARMsh_SHL=20,
+      ARMsh_SHR,
+      ARMsh_SAR
+   }
+   ARMShiftOp;
 
-extern ARMBranchDest* ARMBranchDest_Imm ( ARMImm24 );
-extern ARMBranchDest* ARMBranchDest_Reg ( HReg );
+extern HChar* showARMShiftOp ( ARMShiftOp op );
 
-extern void ppARMBranchDest ( ARMBranchDest* );
 
+typedef
+   enum {
+      ARMun_NEG=30,
+      ARMun_NOT,
+      ARMun_CLZ
+   }
+   ARMUnaryOp;
 
-/* --------- Instructions. --------- */
+extern HChar* showARMUnaryOp ( ARMUnaryOp op );
 
 
-/* --- DPI's --- */
 typedef
    enum {
-       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
+      ARMmul_PLAIN=40,
+      ARMmul_ZX,
+      ARMmul_SX
    }
-   ARMAluOp;
+   ARMMulOp;
 
-extern HChar* showARMAluOp ( ARMAluOp );
+extern HChar* showARMMulOp ( ARMMulOp op );
+
+
+typedef
+   enum {
+      ARMvfp_ADD=50,
+      ARMvfp_SUB,
+      ARMvfp_MUL,
+      ARMvfp_DIV
+   }
+   ARMVfpOp;
 
+extern HChar* showARMVfpOp ( ARMVfpOp op );
+
+
+typedef
+   enum {
+      ARMvfpu_COPY=60,
+      ARMvfpu_NEG,
+      ARMvfpu_ABS,
+      ARMvfpu_SQRT
+   }
+   ARMVfpUnaryOp;
+
+extern HChar* showARMVfpUnaryOp ( ARMVfpUnaryOp op );
 
 
-/* --------- */
 typedef
    enum {
-       ARMin_DPCmp,
-       ARMin_DPInstr1,
-       ARMin_DPInstr2,
-
-       ARMin_LoadUB,
-       ARMin_StoreB,
-       ARMin_LoadW,
-       ARMin_StoreW,
-       ARMin_LoadSB,
-       ARMin_LoadUH,
-       ARMin_LoadSH,
-       ARMin_StoreH,
-
-       ARMin_Branch,
-       ARMin_BranchL,
-       ARMin_Literal
+      /* baseline */
+      ARMin_Alu=70,
+      ARMin_Shift,
+      ARMin_Unary,
+      ARMin_CmpOrTst,
+      ARMin_Mov,
+      ARMin_Imm32,
+      ARMin_LdSt32,
+      ARMin_LdSt16,
+      ARMin_LdSt8U,
+      ARMin_Ld8S,
+      ARMin_Goto,
+      ARMin_CMov,
+      ARMin_Call,
+      ARMin_Mul,
+      ARMin_LdrEX,
+      ARMin_StrEX,
+      /* vfp */
+      ARMin_VLdStD,
+      ARMin_VLdStS,
+      ARMin_VAluD,
+      ARMin_VAluS,
+      ARMin_VUnaryD,
+      ARMin_VUnaryS,
+      ARMin_VCmpD,
+      ARMin_VCMovD,
+      ARMin_VCMovS,
+      ARMin_VCvtSD,
+      ARMin_VXferD,
+      ARMin_VXferS,
+      ARMin_VCvtID,
+      ARMin_FPSCR
    }
    ARMInstrTag;
 
+/* Destinations are on the LEFT (first operand) */
 
 typedef
    struct {
       ARMInstrTag tag;
       union {
-         /* Addressing Mode 1 */
-         struct {
-             ARMAluOp op;
-             HReg Rn;
-             ARMAMode1* shifter_op;
-         } DPCmp;        // test instrs - compare Rd with RIS and set flags
-         struct {
-             ARMAluOp op;
-             HReg Rd;
-             ARMAMode1* shifter_op;
-         } DPInstr1;      // 1 reg: Mov
-         struct {
-             ARMAluOp op;
-             HReg Rd;
-             HReg Rn;
-             ARMAMode1* shifter_op;
-         } DPInstr2;      // 2 regs: Logic, Arith, Bic
-
-         /* Addressing Mode 2 */
-         struct {
-             HReg Rd;
-             ARMAMode2* addr_mode;
-         } LoadUB;
-         struct {
-             HReg Rd;
-             ARMAMode2* addr_mode;
-         } StoreB;
-         struct {
-             HReg Rd;
-             ARMAMode2* addr_mode;
-         } LoadW;
-         struct {
-             HReg Rd;
-             ARMAMode2* addr_mode;
-         } StoreW;
-
-         /* Addressing Mode 3 */
-         struct {
-             HReg Rd;
-             ARMAMode3* addr_mode;
-         } LoadSB;
-         struct {
-             HReg Rd;
-             ARMAMode3* addr_mode;
-         } LoadUH;
-         struct {
-             HReg Rd;
-             ARMAMode3* addr_mode;
-         } LoadSH;
-         struct {
-             HReg Rd;
-             ARMAMode3* addr_mode;
-         } StoreH;
-
-
-         /* Branch */
-         struct {
-             ARMCondCode cond;
-             ARMBranchDest* dest;
-         } Branch;
-         struct {
-             ARMCondCode cond;
-             ARMBranchDest* dest;
-         } BranchL;
-
-         /* Literal */
-         struct {
-             HReg reg;
-             UInt imm;
-         } Literal;       // -- reg = imm
-
+         /* ADD/SUB/AND/OR/XOR, vanilla ALU op */
+         struct {
+            ARMAluOp op;
+            HReg     dst;
+            HReg     argL;
+            ARMRI84* argR;
+         } Alu;
+         /* SHL/SHR/SAR, 2nd arg is reg or imm */
+         struct {
+            ARMShiftOp op;
+            HReg       dst;
+            HReg       argL;
+            ARMRI5*    argR;
+         } Shift;
+         /* NOT/NEG/CLZ */
+         struct {
+            ARMUnaryOp op;
+            HReg       dst;
+            HReg       src;
+         } Unary;
+         /* CMP/TST; subtract/and, discard result, set NZCV */
+         struct {
+            Bool     isCmp;
+            HReg     argL;
+            ARMRI84* argR;
+         } CmpOrTst;
+         /* MOV dst, src -- reg-reg (or reg-imm8x4) move */
+         struct {
+            HReg     dst;
+            ARMRI84* src;
+         } Mov;
+         /* Pseudo-insn; make a 32-bit immediate */
+         struct {
+            HReg dst;
+            UInt imm32;
+         } Imm32;
+         /* 32-bit load or store */
+         struct {
+            Bool       isLoad;
+            HReg       rD;
+            ARMAMode1* amode;
+         } LdSt32;
+         /* 16-bit load or store */
+         struct {
+            Bool       isLoad;
+            Bool       signedLoad;
+            HReg       rD;
+            ARMAMode2* amode;
+         } LdSt16;
+         /* 8-bit (unsigned) load or store */
+         struct {
+            Bool       isLoad;
+            HReg       rD;
+            ARMAMode1* amode;
+         } LdSt8U;
+         /* 8-bit signed load */
+         struct {
+            HReg       rD;
+            ARMAMode2* amode;
+         } Ld8S;
+         /* Pseudo-insn.  Go to guest address gnext, on given
+            condition, which could be ARMcc_AL. */
+         struct {
+            IRJumpKind  jk;
+            ARMCondCode cond;
+            HReg        gnext;
+         } Goto;
+         /* Mov src to dst on the given condition, which may not
+            be ARMcc_AL. */
+         struct {
+            ARMCondCode cond;
+            HReg        dst;
+            ARMRI84*    src;
+         } CMov;
+         /* Pseudo-insn.  Call target (an absolute address), on given
+            condition (which could be ARMcc_AL). */
+         struct {
+            ARMCondCode cond;
+            HWord       target;
+            Int         nArgRegs; /* # regs carrying args: 0 .. 4 */
+         } Call;
+         /* (PLAIN) 32 *  32 -> 32:  r0    = r2 * r3
+            (ZX)    32 *u 32 -> 64:  r1:r0 = r2 *u r3
+            (SX)    32 *s 32 -> 64:  r1:r0 = r2 *s r3
+            Why hardwired registers?  Because the ARM ARM specifies
+            (eg for straight MUL) the result (Rd) and the left arg (Rm)
+            may not be the same register.  That's not a constraint we
+            can enforce in the register allocator (without mucho extra
+            complexity).  Hence hardwire it.  At least using caller-saves
+            registers, which are less likely to be in use. */
+         struct {
+            ARMMulOp op;
+         } Mul;
+         /* LDREX{,H,B} r0, [r1]
+            Again, hardwired registers since this is not performance
+            critical, and there are possibly constraints on the
+            registers that we can't express in the register allocator.*/
+         struct {
+            Int  szB; /* currently only 4 is allowed */
+         } LdrEX;
+         /* STREX{,H,B} r0, r1, [r2]
+            r0 = SC( [r2] = r1 )
+            Ditto comment re fixed registers. */
+         struct {
+            Int  szB; /* currently only 4 is allowed */
+         } StrEX;
+         /* VFP INSTRUCTIONS */
+         /* 64-bit Fp load/store */
+         struct {
+            Bool       isLoad;
+            HReg       dD;
+            ARMAModeV* amode;
+         } VLdStD;
+         /* 32-bit Fp load/store */
+         struct {
+            Bool       isLoad;
+            HReg       fD;
+            ARMAModeV* amode;
+         } VLdStS;
+         /* 64-bit FP binary arithmetic */
+         struct {
+            ARMVfpOp op;
+            HReg     dst;
+            HReg     argL;
+            HReg     argR;
+         } VAluD;
+         /* 32-bit FP binary arithmetic */
+         struct {
+            ARMVfpOp op;
+            HReg     dst;
+            HReg     argL;
+            HReg     argR;
+         } VAluS;
+         /* 64-bit FP unary, also reg-reg move */
+         struct {
+            ARMVfpUnaryOp op;
+            HReg          dst;
+            HReg          src;
+         } VUnaryD;
+         /* 32-bit FP unary, also reg-reg move */
+         struct {
+            ARMVfpUnaryOp op;
+            HReg          dst;
+            HReg          src;
+         } VUnaryS;
+         /* 64-bit FP compare and move results to CPSR (FCMPD;FMSTAT) */
+         struct {
+            HReg argL;
+            HReg argR;
+         } VCmpD;
+         /* 64-bit FP mov src to dst on the given condition, which may
+            not be ARMcc_AL. */
+         struct {
+            ARMCondCode cond;
+            HReg        dst;
+            HReg        src;
+         } VCMovD;
+         /* 32-bit FP mov src to dst on the given condition, which may
+            not be ARMcc_AL. */
+         struct {
+            ARMCondCode cond;
+            HReg        dst;
+            HReg        src;
+         } VCMovS;
+         /* Convert between 32-bit and 64-bit FP values (both ways).
+            (FCVTSD, FCVTDS) */
+         struct {
+            Bool sToD; /* True: F32->F64.  False: F64->F32 */
+            HReg dst;
+            HReg src;
+         } VCvtSD;
+         /* Transfer a VFP D reg to/from two integer registers (VMOV) */
+         struct {
+            Bool toD;
+            HReg dD;
+            HReg rHi;
+            HReg rLo;
+         } VXferD;
+         /* Transfer a VFP S reg to/from an integer register (VMOV) */
+         struct {
+            Bool toS;
+            HReg fD;
+            HReg rLo;
+         } VXferS;
+         /* Convert between 32-bit ints and 64-bit FP values (both ways
+            and both signednesses). (FSITOD, FUITOD, FTOSID, FTOUID) */
+         struct {
+            Bool iToD; /* True: I32->F64.  False: F64->I32 */
+            Bool syned; /* True: I32 is signed.  False: I32 is unsigned */
+            HReg dst;
+            HReg src;
+         } VCvtID;
+         /* Move a 32-bit value to/from the FPSCR (FMXR, FMRX) */
+         struct {
+            Bool toFPSCR;
+            HReg iReg;
+         } FPSCR;
       } ARMin;
    }
    ARMInstr;
 
-extern ARMInstr* ARMInstr_DPCmp     ( ARMAluOp, HReg, ARMAMode1* );
-extern ARMInstr* ARMInstr_DPInstr1  ( ARMAluOp, HReg, ARMAMode1* );
-extern ARMInstr* ARMInstr_DPInstr2  ( ARMAluOp, HReg, HReg, ARMAMode1* );
-
-extern ARMInstr* ARMInstr_LoadUB    ( HReg, ARMAMode2* );
-extern ARMInstr* ARMInstr_StoreB    ( HReg, ARMAMode2* );
-extern ARMInstr* ARMInstr_LoadW     ( HReg, ARMAMode2* );
-extern ARMInstr* ARMInstr_StoreW    ( HReg, ARMAMode2* );
-extern ARMInstr* ARMInstr_LoadSB    ( HReg, ARMAMode3* );
-extern ARMInstr* ARMInstr_LoadUH    ( HReg, ARMAMode3* );
-extern ARMInstr* ARMInstr_LoadSH    ( HReg, ARMAMode3* );
-extern ARMInstr* ARMInstr_StoreH    ( HReg, ARMAMode3* );
-
-extern ARMInstr* ARMInstr_Branch    ( ARMCondCode, ARMBranchDest* );
-extern ARMInstr* ARMInstr_BranchL   ( ARMCondCode, ARMBranchDest* );
 
-extern ARMInstr* ARMInstr_Literal   ( HReg, UInt );
+extern ARMInstr* ARMInstr_Alu      ( ARMAluOp, HReg, HReg, ARMRI84* );
+extern ARMInstr* ARMInstr_Shift    ( ARMShiftOp, HReg, HReg, ARMRI5* );
+extern ARMInstr* ARMInstr_Unary    ( ARMUnaryOp, HReg, HReg );
+extern ARMInstr* ARMInstr_CmpOrTst ( Bool isCmp, HReg, ARMRI84* );
+extern ARMInstr* ARMInstr_Mov      ( HReg, ARMRI84* );
+extern ARMInstr* ARMInstr_Imm32    ( HReg, UInt );
+extern ARMInstr* ARMInstr_LdSt32   ( Bool isLoad, HReg, ARMAMode1* );
+extern ARMInstr* ARMInstr_LdSt16   ( Bool isLoad, Bool signedLoad,
+                                     HReg, ARMAMode2* );
+extern ARMInstr* ARMInstr_LdSt8U   ( Bool isLoad, HReg, ARMAMode1* );
+extern ARMInstr* ARMInstr_Ld8S     ( HReg, ARMAMode2* );
+extern ARMInstr* ARMInstr_Goto     ( IRJumpKind, ARMCondCode, HReg gnext );
+extern ARMInstr* ARMInstr_CMov     ( ARMCondCode, HReg dst, ARMRI84* src );
+extern ARMInstr* ARMInstr_Call     ( ARMCondCode, HWord, Int nArgRegs );
+extern ARMInstr* ARMInstr_Mul      ( ARMMulOp op );
+extern ARMInstr* ARMInstr_LdrEX    ( Int szB );
+extern ARMInstr* ARMInstr_StrEX    ( Int szB );
+extern ARMInstr* ARMInstr_VLdStD   ( Bool isLoad, HReg, ARMAModeV* );
+extern ARMInstr* ARMInstr_VLdStS   ( Bool isLoad, HReg, ARMAModeV* );
+extern ARMInstr* ARMInstr_VAluD    ( ARMVfpOp op, HReg, HReg, HReg );
+extern ARMInstr* ARMInstr_VAluS    ( ARMVfpOp op, HReg, HReg, HReg );
+extern ARMInstr* ARMInstr_VUnaryD  ( ARMVfpUnaryOp, HReg dst, HReg src );
+extern ARMInstr* ARMInstr_VUnaryS  ( ARMVfpUnaryOp, HReg dst, HReg src );
+extern ARMInstr* ARMInstr_VCmpD    ( HReg argL, HReg argR );
+extern ARMInstr* ARMInstr_VCMovD   ( ARMCondCode, HReg dst, HReg src );
+extern ARMInstr* ARMInstr_VCMovS   ( ARMCondCode, HReg dst, HReg src );
+extern ARMInstr* ARMInstr_VCvtSD   ( Bool sToD, HReg dst, HReg src );
+extern ARMInstr* ARMInstr_VXferD   ( Bool toD, HReg dD, HReg rHi, HReg rLo );
+extern ARMInstr* ARMInstr_VXferS   ( Bool toS, HReg fD, HReg rLo );
+extern ARMInstr* ARMInstr_VCvtID   ( Bool iToD, Bool syned,
+                                     HReg dst, HReg src );
+extern ARMInstr* ARMInstr_FPSCR    ( Bool toFPSCR, HReg iReg );
 
 extern void ppARMInstr ( ARMInstr* );
 
 
 /* Some functions that insulate the register allocator from details
    of the underlying instruction set. */
-extern void         getAllocableRegs_ARM ( Int*, HReg** );
-extern void         getRegUsage_ARMInstr ( HRegUsage*, ARMInstr* );
-extern void         mapRegs_ARMInstr     ( HRegRemap*, ARMInstr* );
-extern Bool         isMove_ARMInstr      ( ARMInstr*, HReg*, HReg* );
-extern Int          emit_ARMInstr        ( UChar* buf, Int nbuf, ARMInstr* );
-extern ARMInstr*    genSpill_ARM         ( HReg rreg, Int offset );
-extern ARMInstr*    genReload_ARM        ( HReg rreg, Int offset );
-extern void         getAllocableRegs_ARM ( Int*, HReg** );
-extern HInstrArray* iselSB_ARM           ( IRSB* );
+extern void getRegUsage_ARMInstr ( HRegUsage*, ARMInstr*, Bool );
+extern void mapRegs_ARMInstr     ( HRegRemap*, ARMInstr*, Bool );
+extern Bool isMove_ARMInstr      ( ARMInstr*, HReg*, HReg* );
+extern Int  emit_ARMInstr        ( UChar* buf, Int nbuf, ARMInstr*, 
+                                   Bool, void* dispatch );
+
+extern void genSpill_ARM  ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2,
+                            HReg rreg, Int offset, Bool );
+extern void genReload_ARM ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2,
+                            HReg rreg, Int offset, Bool );
+
+extern void getAllocableRegs_ARM ( Int*, HReg** );
+extern HInstrArray* iselSB_ARM   ( IRSB*, VexArch,
+                                   VexArchInfo*, VexAbiInfo* );
 
 #endif /* ndef __VEX_HOST_ARM_DEFS_H */
 
index 114e29ffc90deb7c8233caa6f4116899275c40f7..0492d39508da73d30c74ee50c7e4b1ef4166e89e 100644 (file)
    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 "host_arm_defs.h"
 
 
+/*---------------------------------------------------------*/
+/*--- ARMvfp control word stuff                         ---*/
+/*---------------------------------------------------------*/
+
+/* Vex-generated code expects to run with the FPU set as follows: all
+   exceptions masked, round-to-nearest, non-vector mode, with the NZCV
+   flags cleared, and FZ (flush to zero) disabled.  Curiously enough,
+   this corresponds to a FPSCR value of zero.
+
+   fpscr should therefore be zero on entry to Vex-generated code, and
+   should be unchanged at exit.  (Or at least the bottom 28 bits
+   should be zero).
+*/
+
+#define DEFAULT_FPSCR 0
+
+
 /*---------------------------------------------------------*/
 /*--- ISelEnv                                           ---*/
 /*---------------------------------------------------------*/
      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 name of the vreg in which we stash a copy of the link reg, so
+     helper functions don't kill it.
 
    - The code array, that is, the insns selected so far.
 
    - A counter, for generating new virtual registers.
 
+   - The host hardware capabilities word.  This is set at the start
+     and does not change.
+
    Note, this is all host-independent.  */
 
 typedef
@@ -83,11 +105,16 @@ typedef
       IRTypeEnv*   type_env;
 
       HReg*        vregmap;
+      HReg*        vregmapHI;
       Int          n_vregmap;
 
+      HReg         savedLR;
+
       HInstrArray* code;
 
       Int          vreg_ctr;
+
+      UInt         hwcaps;
    }
    ISelEnv;
 
@@ -98,6 +125,15 @@ static HReg lookupIRTemp ( ISelEnv* env, IRTemp tmp )
    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 addInstr ( ISelEnv* env, ARMInstr* instr )
 {
    addHInstr(env->code, instr);
@@ -114,6 +150,19 @@ static HReg newVRegI ( ISelEnv* env )
    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, HRcFlt32, True/*virtual reg*/);
+   env->vreg_ctr++;
+   return reg;
+}
 
 
 /*---------------------------------------------------------*/
@@ -126,615 +175,1956 @@ static HReg newVRegI ( ISelEnv* env )
    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 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 ARMAMode2*     iselIntExpr_AMode2_wrk ( ISelEnv* env, IRExpr* e ); */
-static ARMAMode2*     iselIntExpr_AMode2     ( ISelEnv* env, IRExpr* e );
+static ARMAModeV*  iselIntExpr_AModeV_wrk ( ISelEnv* env, IRExpr* e );
+static ARMAModeV*  iselIntExpr_AModeV     ( ISelEnv* env, IRExpr* e );
 
-static ARMAMode3*     iselIntExpr_AMode3_wrk ( ISelEnv* env, IRExpr* e );
-static ARMAMode3*     iselIntExpr_AMode3     ( ISelEnv* env, IRExpr* e );
+static ARMRI84*    iselIntExpr_RI84_wrk
+        ( /*OUT*/Bool* didInv, Bool mayInv, ISelEnv* env, IRExpr* e );
+static ARMRI84*    iselIntExpr_RI84
+        ( /*OUT*/Bool* didInv, Bool mayInv, ISelEnv* env, IRExpr* e );
 
-static ARMBranchDest* iselIntExpr_BD_wrk ( ISelEnv* env, IRExpr* e );
-static ARMBranchDest* iselIntExpr_BD     ( ISelEnv* env, IRExpr* e );
+static ARMRI5*     iselIntExpr_RI5_wrk    ( ISelEnv* env, IRExpr* e );
+static ARMRI5*     iselIntExpr_RI5        ( ISelEnv* env, IRExpr* e );
 
-static ARMCondCode    iselCondCode_wrk ( ISelEnv* env, IRExpr* e );
-static ARMCondCode    iselCondCode     ( 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 );
+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
+static void        iselInt64Expr_wrk      ( HReg* rHi, HReg* rLo, 
+                                            ISelEnv* env, IRExpr* e );
+static void        iselInt64Expr          ( HReg* rHi, HReg* rLo, 
+                                            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 );
 
 
 /*---------------------------------------------------------*/
 /*--- ISEL: Misc helpers                                ---*/
 /*---------------------------------------------------------*/
-#if 0
-/* Is this a 32-bit zero expression? */
-static Bool isZero32 ( IRExpr* e )
+
+static UInt ROR32 ( UInt x, UInt sh ) {
+   vassert(sh >= 0 && sh < 32);
+   if (sh == 0)
+      return x;
+   else
+      return (x << (32-sh)) | (x >> sh);
+}
+
+/* Figure out if 'u' fits in the special shifter-operand 8x4 immediate
+   form, and if so return the components. */
+static Bool fitsIn8x4 ( /*OUT*/UInt* u8, /*OUT*/UInt* u4, UInt u )
 {
-   return e->tag == Iex_Const
-          && e->Iex.Const.con->tag == Ico_U32
-          && e->Iex.Const.con->Ico.U32 == 0;
+   UInt i;
+   for (i = 0; i < 16; i++) {
+      if (0 == (u & 0xFFFFFF00)) {
+         *u8 = u;
+         *u4 = i;
+         return True;
+      }
+      u = ROR32(u, 30);
+   }
+   vassert(i == 16);
+   return False;
 }
-#endif
 
 /* Make a int reg-reg move. */
-static ARMInstr* mk_iMOVsd_RR ( HReg src, HReg dst )
+static ARMInstr* mk_iMOVds_RR ( HReg dst, HReg src )
 {
    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
+   return ARMInstr_Mov(dst, ARMRI84_R(src));
+}
+
+/* Set the VFP unit's rounding mode to default (round to nearest). */
+static void set_VFP_rounding_default ( ISelEnv* env )
+{
+   /* mov rTmp, #DEFAULT_FPSCR
+      fmxr fpscr, rTmp
+   */
+   HReg rTmp = newVRegI(env);
+   addInstr(env, ARMInstr_Imm32(rTmp, DEFAULT_FPSCR));
+   addInstr(env, ARMInstr_FPSCR(True/*toFPSCR*/, rTmp));
+}
+
+/* Mess with the VFP unit's rounding mode: 'mode' is an I32-typed
+   expression denoting a value in the range 0 .. 3, indicating a round
+   mode encoded as per type IRRoundingMode.  Set FPSCR to have the
+   same rounding.
+*/
+static
+void set_VFP_rounding_mode ( ISelEnv* env, IRExpr* mode )
+{
+   /* This isn't simple, because 'mode' carries an IR rounding
+      encoding, and we need to translate that to an ARMvfp one:
+      The IR encoding:
+         00  to nearest (the default)
+         10  to +infinity
+         01  to -infinity
+         11  to zero
+      The ARMvfp encoding:
+         00  to nearest
+         01  to +infinity
+         10  to -infinity
+         11  to zero
+      Easy enough to do; just swap the two bits.
+   */
+   HReg irrm = iselIntExpr_R(env, mode);
+   HReg tL   = newVRegI(env);
+   HReg tR   = newVRegI(env);
+   HReg t3   = newVRegI(env);
+   /* tL = irrm << 1;
+      tR = irrm >> 1;  if we're lucky, these will issue together
+      tL &= 2;
+      tR &= 1;         ditto
+      t3 = tL | tR;
+      t3 <<= 22;
+      fmxr fpscr, t3
+   */
+   addInstr(env, ARMInstr_Shift(ARMsh_SHL, tL, irrm, ARMRI5_I5(1)));
+   addInstr(env, ARMInstr_Shift(ARMsh_SHR, tR, irrm, ARMRI5_I5(1)));
+   addInstr(env, ARMInstr_Alu(ARMalu_AND, tL, tL, ARMRI84_I84(2,0)));
+   addInstr(env, ARMInstr_Alu(ARMalu_AND, tR, tR, ARMRI84_I84(1,0)));
+   addInstr(env, ARMInstr_Alu(ARMalu_OR, t3, tL, ARMRI84_R(tR)));
+   addInstr(env, ARMInstr_Shift(ARMsh_SHL, t3, t3, ARMRI5_I5(22)));
+   addInstr(env, ARMInstr_FPSCR(True/*toFPSCR*/, t3));
+}
+
+
+/*---------------------------------------------------------*/
+/*--- ISEL: Function call helpers                       ---*/
+/*---------------------------------------------------------*/
+
 /* 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).  
+   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_Tmp: case Iex_Const: case Iex_Get: 
-         return False;
-      default:
-         return True;
+   case Iex_RdTmp: 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. */
+   call is unconditional.  Returns True iff it managed to handle this
+   combination of arg/return types, else returns False. */
 
 static
-void doHelperCall ( ISelEnv* env, 
-                    Bool passBBP, 
+Bool 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.
+   HReg        argregs[ARM_N_ARGREGS];
+   HReg        tmpregs[ARM_N_ARGREGS];
+   Bool        go_fast;
+   Int         n_args, i, nextArgReg;
+   ULong       target;
+
+   vassert(ARM_N_ARGREGS == 4);
+
+   /* Marshal args for a call and do the call.
+
+      If passBBP is True, r8 (the baseblock pointer) is to be passed
+      as the first arg.
+
+      This function only deals with a tiny set of possibilities, which
+      cover all helpers in practice.  The restrictions are that only
+      arguments in registers are supported, hence only ARM_N_REGPARMS
+      x 32 integer bits in total can be passed.  In fact the only
+      supported arg types are I32 and I64.
+
+      Generating code which is both efficient and correct when
+      parameters are to be passed in registers is difficult, for the
+      reasons elaborated in detail in comments attached to
+      doHelperCall() in priv/host-x86/isel.c.  Here, we use a variant
+      of the method described in those comments.
+
+      The problem is split into two cases: the fast scheme and the
+      slow scheme.  In the fast scheme, arguments are computed
+      directly into the target (real) registers.  This is only safe
+      when we can be sure that computation of each argument will not
+      trash any real registers set by computation of any other
+      argument.
+
+      In the slow scheme, all args are first computed into vregs, and
+      once they are all done, they are moved 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.
+
+      To decide which scheme to use, all argument expressions are
+      first examined.  If they are all so simple that it is clear they
+      will be evaluated without use of any fixed registers, use the
+      fast scheme, else use the slow scheme.  Note also that only
+      unconditional calls may use the fast scheme, since having to
+      compute a condition expression could itself trash real
+      registers.
 
       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.
+      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++;
+   /* Note that the cee->regparms field is meaningless on ARM hosts
+      (since there is only one calling convention) and so we always
+      ignore it. */
 
-   stack_limit = cee->regparms;
-   if (cee->regparms > 0 && passBBP) stack_limit--;
+   n_args = 0;
+   for (i = 0; args[i]; i++)
+      n_args++;
 
-   /* ------ BEGIN marshall all arguments ------ */
+   argregs[0] = hregARM_R0();
+   argregs[1] = hregARM_R1();
+   argregs[2] = hregARM_R2();
+   argregs[3] = hregARM_R3();
 
-   /* 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. */
+   tmpregs[0] = tmpregs[1] = tmpregs[2] =
+   tmpregs[3] = INVALID_HREG;
 
-   if (cee->regparms > 0) {
+   /* First decide which scheme (slow or fast) is to be used.  First
+      assume the fast scheme, and select slow if any contraindications
+      (wow) appear. */
 
-      /* ------ BEGIN deal with regparms ------ */
+   go_fast = True;
 
-      /* 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;
+   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;
+      }
+   }
 
-      /* 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 (go_fast) {
+      for (i = 0; i < n_args; i++) {
          if (mightRequireFixedRegs(args[i])) {
-            danger = True;
+            go_fast = False;
             break;
          }
       }
+   }
+   /* At this point the scheme to use has been established.  Generate
+      code to get the arg values into the argument rregs.  If we run
+      out of arg regs, give up. */
 
-      if (danger) {
-
-         /* Move via temporaries */
-         argregX = argreg;
-         for (i = stack_limit-1; i >= 0; i--) {
+   if (go_fast) {
 
-            if (0) {
-               vex_printf("x86 host: register param is complex: ");
-               ppIRExpr(args[i]);
-               vex_printf("\n");
-            }
+      /* FAST SCHEME */
+      nextArgReg = 0;
+      if (passBBP) {
+         addInstr(env, mk_iMOVds_RR( argregs[nextArgReg],
+                                     hregARM_R8() ));
+         nextArgReg++;
+      }
 
-            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] ) );
+      for (i = 0; i < n_args; i++) {
+         IRType aTy = typeOfIRExpr(env->type_env, args[i]);
+         if (nextArgReg >= ARM_N_ARGREGS)
+            return False; /* out of argregs */
+         if (aTy == Ity_I32) {
+            addInstr(env, mk_iMOVds_RR( argregs[nextArgReg],
+                                        iselIntExpr_R(env, args[i]) ));
+            nextArgReg++;
          }
-
-      } 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--;
+         else if (aTy == Ity_I64) {
+            /* 64-bit args must be passed in an a reg-pair of the form
+               n:n+1, where n is even.  Hence either r0:r1 or r2:r3.
+               On a little-endian host, the less significant word is
+               passed in the lower-numbered register. */
+            if (nextArgReg & 1) {
+               if (nextArgReg >= ARM_N_ARGREGS)
+                  return False; /* out of argregs */
+               addInstr(env, ARMInstr_Imm32( argregs[nextArgReg], 0xAA ));
+               nextArgReg++;
+            }
+            if (nextArgReg >= ARM_N_ARGREGS)
+               return False; /* out of argregs */
+            HReg raHi, raLo;
+            iselInt64Expr(&raHi, &raLo, env, args[i]);
+            addInstr(env, mk_iMOVds_RR( argregs[nextArgReg], raLo ));
+            nextArgReg++;
+            addInstr(env, mk_iMOVds_RR( argregs[nextArgReg], raHi ));
+            nextArgReg++;
          }
-
-      }
-
-      /* Not forgetting %ebp if needed. */
-      if (passBBP) {
-         vassert(argreg == 1);
-         addInstr(env, mk_iMOVsd_RR( hregX86_EBP(), argregs[0]));
-         not_done_yet--;
+         else
+            return False; /* unhandled arg type */
       }
 
-      /* ------ END deal with regparms ------ */
+      /* Fast scheme only applies for unconditional calls.  Hence: */
+      cc = ARMcc_AL;
 
    } else {
 
-      /* No regparms.  Heave %ebp on the stack if needed. */
+      /* SLOW SCHEME; move via temporaries */
+      nextArgReg = 0;
+
       if (passBBP) {
-         addInstr(env, X86Instr_Push(X86RMI_Reg(hregX86_EBP())));
-         n_arg_ws++;
-         not_done_yet--;
+         /* This is pretty stupid; better to move directly to r0
+            after the rest of the args are done. */
+         tmpregs[nextArgReg] = newVRegI(env);
+         addInstr(env, mk_iMOVds_RR( tmpregs[nextArgReg],
+                                     hregARM_R8() ));
+         nextArgReg++;
       }
 
-   }
-
-   vassert(not_done_yet == 0);
+      for (i = 0; i < n_args; i++) {
+         IRType aTy = typeOfIRExpr(env->type_env, args[i]);
+         if (nextArgReg >= ARM_N_ARGREGS)
+            return False; /* out of argregs */
+         if (aTy == Ity_I32) {
+            tmpregs[nextArgReg] = iselIntExpr_R(env, args[i]);
+            nextArgReg++;
+         }
+         else if (aTy == Ity_I64) {
+            /* Same comment applies as in the Fast-scheme case. */
+            if (nextArgReg & 1)
+               nextArgReg++;
+            if (nextArgReg + 1 >= ARM_N_ARGREGS)
+               return False; /* out of argregs */
+            HReg raHi, raLo;
+            iselInt64Expr(&raHi, &raLo, env, args[i]);
+            tmpregs[nextArgReg] = raLo;
+            nextArgReg++;
+            tmpregs[nextArgReg] = raHi;
+            nextArgReg++;
+         }
+      }
 
-   /* ------ 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 = ARMcc_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 );
+         }
+      }
 
-   /* 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 );
+      /* Move the args to their final destinations. */
+      for (i = 0; i < nextArgReg; i++) {
+         if (tmpregs[i] == INVALID_HREG) { // Skip invalid regs
+            addInstr(env, ARMInstr_Imm32( argregs[i], 0xAA ));
+            continue;
+         }
+         /* None of these insns, including any spill code that might
+            be generated, may alter the condition codes. */
+         addInstr( env, mk_iMOVds_RR( argregs[i], tmpregs[i] ) );
       }
+
    }
 
-   /* call the helper, and get the args off the stack afterwards. */
-   callHelperAndClearArgs( env, cc, cee, n_arg_ws );
-#endif
+   /* Should be assured by checks above */
+   vassert(nextArgReg <= ARM_N_ARGREGS);
+
+   target = (HWord)Ptr_to_ULong(cee->addr);
+
+   /* nextArgReg doles out argument registers.  Since these are
+      assigned in the order r0, r1, r2, r3, its numeric value at this
+      point, which must be between 0 and 4 inclusive, is going to be
+      equal to the number of arg regs in use for the call.  Hence bake
+      that number into the call (we'll need to know it when doing
+      register allocation, to know what regs the call reads.)
+
+      There is a bit of a twist -- harmless but worth recording.
+      Suppose the arg types are (Ity_I32, Ity_I64).  Then we will have
+      the first arg in r0 and the second in r3:r2, but r1 isn't used.
+      We nevertheless have nextArgReg==4 and bake that into the call
+      instruction.  This will mean the register allocator wil believe
+      this insn reads r1 when in fact it doesn't.  But that's
+      harmless; it just artificially extends the live range of r1
+      unnecessarily.  The best fix would be to put into the
+      instruction, a bitmask indicating which of r0/1/2/3 carry live
+      values.  But that's too much hassle. */
+
+   /* Finally, the call itself. */
+   addInstr(env, ARMInstr_Call( cc, target, nextArgReg ));
+
+   return True; /* success */
 }
 
 
+/*---------------------------------------------------------*/
+/*--- ISEL: Integer expressions (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 32, 16 and 8-bit type.  All
+   results are returned in a 32-bit register.  For 16- and 8-bit
+   expressions, the upper 16/24 bits are arbitrary, so you should mask
+   or sign extend partial values if necessary.
+*/
 
-// CAB: Do we need to deal with elemSz != 8 ?
+/* --------------------- AMode1 --------------------- */
 
-/* Given a guest-state array descriptor, an index expression and a
-   bias, generate an ARMAMode holding the relevant guest state
-   offset. */
+/* Return an AMode1 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 32-bit one.
+*/
 
-static
-ARMAMode2* genGuestArrayOffset ( ISelEnv* env, IRRegArray* descr, 
-                                IRExpr* off, Int bias )
+static Bool sane_AMode1 ( ARMAMode1* am )
 {
-   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. */
+   switch (am->tag) {
+      case ARMam1_RI:
+         return
+            toBool( hregClass(am->ARMam1.RI.reg) == HRcInt32
+                    && (hregIsVirtual(am->ARMam1.RI.reg)
+                        || am->ARMam1.RI.reg == hregARM_R8())
+                    && am->ARMam1.RI.simm13 >= -4095
+                    && am->ARMam1.RI.simm13 <= 4095 );
+      case ARMam1_RRS:
+         return
+            toBool( hregClass(am->ARMam1.RRS.base) == HRcInt32
+                    && hregIsVirtual(am->ARMam1.RRS.base)
+                    && hregClass(am->ARMam1.RRS.index) == HRcInt32
+                    && hregIsVirtual(am->ARMam1.RRS.index)
+                    && am->ARMam1.RRS.shift >= 0
+                    && am->ARMam1.RRS.shift <= 3 );
+      default:
+         vpanic("sane_AMode: unknown ARM AMode1 tag");
+   }
+}
 
-   if (nElems != 8 || (elemSz != 1 && elemSz != 8))
-      vpanic("genGuestArrayOffset(arm host)");
+static ARMAMode1* iselIntExpr_AMode1 ( ISelEnv* env, IRExpr* e )
+{
+   ARMAMode1* am = iselIntExpr_AMode1_wrk(env, e);
+   vassert(sane_AMode1(am));
+   return am;
+}
 
-   /* Compute off into a reg, %off.  Then return:
+static ARMAMode1* iselIntExpr_AMode1_wrk ( ISelEnv* env, IRExpr* e )
+{
+   IRType ty = typeOfIRExpr(env->type_env,e);
+   vassert(ty == Ity_I32);
+
+   /* FIXME: add RRS matching */
+
+   /* {Add32,Sub32}(expr,simm13) */
+   if (e->tag == Iex_Binop
+       && (e->Iex.Binop.op == Iop_Add32 || e->Iex.Binop.op == Iop_Sub32)
+       && e->Iex.Binop.arg2->tag == Iex_Const
+       && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
+      Int simm = (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
+      if (simm >= -4095 && simm <= 4095) {
+         HReg reg;
+         if (e->Iex.Binop.op == Iop_Sub32)
+            simm = -simm;
+         reg = iselIntExpr_R(env, e->Iex.Binop.arg1);
+         return ARMAMode1_RI(reg, simm);
+      }
+   }
 
-         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 )));
-       }
+   /* Doesn't match anything in particular.  Generate it into
+      a register and use that. */
+   {
+      HReg reg = iselIntExpr_R(env, e);
+      return ARMAMode1_RI(reg, 0);
    }
 
-   mk_ARMImm12A( (UInt)7, &imm12a );
-   addInstr(env, ARMInstr_DPInstr2(ARMalu_AND, tmp, tmp,
-                                  ARMAMode1_I12A( imm12a )));
-   vassert(elemSz == 1 || elemSz == 8);
+}
 
 
+/* --------------------- AMode2 --------------------- */
 
-// CAB: This anywhere near correct?
+/* Return an AMode2 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 32-bit one.
+*/
 
-// X86AMode_IRRS: Immediate + Reg1 + (Reg2 << Shift)
-// return X86AMode_IRRS( descr->base, hregX86_EBP(), tmp, elemSz==8 ? 3 : 0);
+static Bool sane_AMode2 ( ARMAMode2* am )
+{
+   switch (am->tag) {
+      case ARMam2_RI:
+         return
+            toBool( hregClass(am->ARMam2.RI.reg) == HRcInt32
+                    && hregIsVirtual(am->ARMam2.RI.reg)
+                    && am->ARMam2.RI.simm9 >= -255
+                    && am->ARMam2.RI.simm9 <= 255 );
+      case ARMam2_RR:
+         return
+            toBool( hregClass(am->ARMam2.RR.base) == HRcInt32
+                    && hregIsVirtual(am->ARMam2.RR.base)
+                    && hregClass(am->ARMam2.RR.index) == HRcInt32
+                    && hregIsVirtual(am->ARMam2.RR.index) );
+      default:
+         vpanic("sane_AMode: unknown ARM AMode2 tag");
+   }
+}
 
-   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 );
+static ARMAMode2* iselIntExpr_AMode2 ( ISelEnv* env, IRExpr* e )
+{
+   ARMAMode2* am = iselIntExpr_AMode2_wrk(env, e);
+   vassert(sane_AMode2(am));
+   return am;
 }
 
+static ARMAMode2* iselIntExpr_AMode2_wrk ( ISelEnv* env, IRExpr* e )
+{
+   IRType ty = typeOfIRExpr(env->type_env,e);
+   vassert(ty == Ity_I32);
+
+   /* FIXME: add RR matching */
+
+   /* {Add32,Sub32}(expr,simm8) */
+   if (e->tag == Iex_Binop
+       && (e->Iex.Binop.op == Iop_Add32 || e->Iex.Binop.op == Iop_Sub32)
+       && e->Iex.Binop.arg2->tag == Iex_Const
+       && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
+      Int simm = (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
+      if (simm >= -255 && simm <= 255) {
+         HReg reg;
+         if (e->Iex.Binop.op == Iop_Sub32)
+            simm = -simm;
+         reg = iselIntExpr_R(env, e->Iex.Binop.arg1);
+         return ARMAMode2_RI(reg, simm);
+      }
+   }
+
+   /* Doesn't match anything in particular.  Generate it into
+      a register and use that. */
+   {
+      HReg reg = iselIntExpr_R(env, e);
+      return ARMAMode2_RI(reg, 0);
+   }
+
+}
 
-/*---------------------------------------------------------*/
-/*--- ISEL ...                                           ---*/
-/*---------------------------------------------------------*/
 
-/* --------------------- AMODEs --------------------- */
+/* --------------------- AModeV --------------------- */
 
-/* Return an AMode which computes the value of the specified
+/* Return an AModeV which computes the value of the specified
    expression, possibly also adding insns to the code list as a
-   result.
+   result.  The expression may only be a 32-bit one.
 */
 
-/* ---------------- Addressing Mode 1 ---------------- */
-
-static Bool sane_AMode1 ( ARMAMode1* am )
+static Bool sane_AModeV ( ARMAModeV* am )
 {
-    switch (am->tag) {
-    default:
-       vpanic("sane_AMode1: unknown arm amode tag");
-    }
+  return toBool( hregClass(am->reg) == HRcInt32
+                 && hregIsVirtual(am->reg)
+                 && am->simm11 >= -1020 && am->simm11 <= 1020
+                 && 0 == (am->simm11 & 3) );
 }
 
-static ARMAMode1* iselIntExpr_AMode1 ( ISelEnv* env, IRExpr* e )
+static ARMAModeV* iselIntExpr_AModeV ( ISelEnv* env, IRExpr* e )
 {
-    ARMAMode1* am = iselIntExpr_AMode1_wrk(env, e);
-    vassert(sane_AMode1(am));
-    return am;
+   ARMAModeV* am = iselIntExpr_AModeV_wrk(env, e);
+   vassert(sane_AModeV(am));
+   return am;
 }
 
-/* DO NOT CALL THIS DIRECTLY ! */
-static ARMAMode1* iselIntExpr_AMode1_wrk ( ISelEnv* env, IRExpr* e )
+static ARMAModeV* iselIntExpr_AModeV_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
-    */
+   IRType ty = typeOfIRExpr(env->type_env,e);
+   vassert(ty == Ity_I32);
+
+   /* {Add32,Sub32}(expr, simm8 << 2) */
+   if (e->tag == Iex_Binop
+       && (e->Iex.Binop.op == Iop_Add32 || e->Iex.Binop.op == Iop_Sub32)
+       && e->Iex.Binop.arg2->tag == Iex_Const
+       && e->Iex.Binop.arg2->Iex.Const.con->tag == Ico_U32) {
+      Int simm = (Int)e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
+      if (simm >= -1020 && simm <= 1020 && 0 == (simm & 3)) {
+         HReg reg;
+         if (e->Iex.Binop.op == Iop_Sub32)
+            simm = -simm;
+         reg = iselIntExpr_R(env, e->Iex.Binop.arg1);
+         return mkARMAModeV(reg, simm);
+      }
+   }
 
+   /* Doesn't match anything in particular.  Generate it into
+      a register and use that. */
+   {
+      HReg reg = iselIntExpr_R(env, e);
+      return mkARMAModeV(reg, 0);
+   }
 
-    return NULL; 
 }
 
 
+/* --------------------- RI84 --------------------- */
 
-/* ---------------- Addressing Mode 2 ---------------- */
+/* Select instructions to generate 'e' into a RI84.  If mayInv is
+   true, then the caller will also accept an I84 form that denotes
+   'not e'.  In this case didInv may not be NULL, and *didInv is set
+   to True.  This complication is so as to allow generation of an RI84
+   which is suitable for use in either an AND or BIC instruction,
+   without knowing (before this call) which one.
+*/
+static ARMRI84* iselIntExpr_RI84 ( /*OUT*/Bool* didInv, Bool mayInv,
+                                   ISelEnv* env, IRExpr* e )
+{
+   ARMRI84* ri;
+   if (mayInv)
+      vassert(didInv != NULL);
+   ri = iselIntExpr_RI84_wrk(didInv, mayInv, env, e);
+   /* sanity checks ... */
+   switch (ri->tag) {
+      case ARMri84_I84:
+         return ri;
+      case ARMri84_R:
+         vassert(hregClass(ri->ARMri84.R.reg) == HRcInt32);
+         vassert(hregIsVirtual(ri->ARMri84.R.reg));
+         return ri;
+      default:
+         vpanic("iselIntExpr_RI84: unknown arm RI84 tag");
+   }
+}
 
-__attribute__((unused))
-static Bool sane_AMode2 ( ARMAMode2* am )
+/* DO NOT CALL THIS DIRECTLY ! */
+static ARMRI84* iselIntExpr_RI84_wrk ( /*OUT*/Bool* didInv, Bool mayInv,
+                                       ISelEnv* env, IRExpr* e )
 {
-   switch (am->tag) {
-   default:
-       vpanic("sane_AMode2: unknown arm amode tag");
+   IRType ty = typeOfIRExpr(env->type_env,e);
+   vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
+
+   if (didInv) *didInv = False;
+
+   /* special case: immediate */
+   if (e->tag == Iex_Const) {
+      UInt u, u8 = 0x100, u4 = 0x10; /* both invalid */
+      switch (e->Iex.Const.con->tag) {
+         case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
+         case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
+         case Ico_U8:  u = 0xFF   & (e->Iex.Const.con->Ico.U8); break;
+         default: vpanic("iselIntExpr_RI84.Iex_Const(armh)");
+      }
+      if (fitsIn8x4(&u8, &u4, u)) {
+         return ARMRI84_I84( (UShort)u8, (UShort)u4 );
+      }
+      if (mayInv && fitsIn8x4(&u8, &u4, ~u)) {
+         vassert(didInv);
+         *didInv = True;
+         return ARMRI84_I84( (UShort)u8, (UShort)u4 );
+      }
+      /* else fail, fall through to default case */
+   }
+
+   /* default case: calculate into a register and return that */
+   {
+      HReg r = iselIntExpr_R ( env, e );
+      return ARMRI84_R(r);
    }
 }
 
-/* Apparently unused
-static ARMAMode2* iselIntExpr_AMode2_wrk ( ISelEnv* env, IRExpr* e )
+
+/* --------------------- RI5 --------------------- */
+
+/* Select instructions to generate 'e' into a RI5. */
+
+static ARMRI5* iselIntExpr_RI5 ( ISelEnv* env, IRExpr* e )
 {
-    ARMAMode2* am = iselIntExpr_AMode2_wrk(env, e);
-    vassert(sane_AMode2(am));
-    return am;
+   ARMRI5* ri = iselIntExpr_RI5_wrk(env, e);
+   /* sanity checks ... */
+   switch (ri->tag) {
+      case ARMri5_I5:
+         return ri;
+      case ARMri5_R:
+         vassert(hregClass(ri->ARMri5.R.reg) == HRcInt32);
+         vassert(hregIsVirtual(ri->ARMri5.R.reg));
+         return ri;
+      default:
+         vpanic("iselIntExpr_RI5: unknown arm RI5 tag");
+   }
 }
-*/
 
 /* 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) */
+static ARMRI5* iselIntExpr_RI5_wrk ( ISelEnv* env, IRExpr* e )
+{
+   IRType ty = typeOfIRExpr(env->type_env,e);
+   vassert(ty == Ity_I32 || ty == Ity_I8);
+
+   /* special case: immediate */
+   if (e->tag == Iex_Const) {
+      UInt u; /* both invalid */
+      switch (e->Iex.Const.con->tag) {
+         case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
+         case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
+         case Ico_U8:  u = 0xFF   & (e->Iex.Const.con->Ico.U8); break;
+         default: vpanic("iselIntExpr_RI5.Iex_Const(armh)");
+      }
+      if (u >= 1 && u <= 31) {
+         return ARMRI5_I5(u);
+      }
+      /* else fail, fall through to default case */
+   }
 
-    return NULL; 
+   /* default case: calculate into a register and return that */
+   {
+      HReg r = iselIntExpr_R ( env, e );
+      return ARMRI5_R(r);
+   }
 }
 
 
+/* ------------------- CondCode ------------------- */
 
-/* ---------------- Addressing Mode 3 ---------------- */
+/* Generate code to evaluated a bit-typed expression, returning the
+   condition code which would correspond when the expression would
+   notionally have returned 1. */
 
-static Bool sane_AMode3 ( ARMAMode3* am )
+static ARMCondCode iselCondCode ( ISelEnv* env, IRExpr* e )
 {
-   switch (am->tag) {
-   default:
-       vpanic("sane_AMode3: unknown arm amode tag");
+   ARMCondCode cc = iselCondCode_wrk(env,e);
+   vassert(cc != ARMcc_AL && cc != ARMcc_NV);
+   return cc;
+}
+
+static ARMCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
+{
+   vassert(e);
+   vassert(typeOfIRExpr(env->type_env,e) == Ity_I1);
+
+   /* var */
+   if (e->tag == Iex_RdTmp) {
+      HReg rTmp = lookupIRTemp(env, e->Iex.RdTmp.tmp);
+      /* CmpOrTst doesn't modify rTmp; so this is OK. */
+      ARMRI84* one  = ARMRI84_I84(1,0);
+      addInstr(env, ARMInstr_CmpOrTst(False/*test*/, rTmp, one));
+      return ARMcc_NE;
+   }
+
+   /* Not1(e) */
+   if (e->tag == Iex_Unop && e->Iex.Unop.op == Iop_Not1) {
+      /* Generate code for the arg, and negate the test condition */
+      return 1 ^ iselCondCode(env, e->Iex.Unop.arg);
+   }
+
+   /* --- patterns rooted at: 32to1 --- */
+
+   if (e->tag == Iex_Unop
+       && e->Iex.Unop.op == Iop_32to1) {
+      HReg     rTmp = iselIntExpr_R(env, e->Iex.Unop.arg);
+      ARMRI84* one  = ARMRI84_I84(1,0);
+      addInstr(env, ARMInstr_CmpOrTst(False/*test*/, rTmp, one));
+      return ARMcc_NE;
+   }
+
+   /* --- patterns rooted at: CmpNEZ8 --- */
+
+   if (e->tag == Iex_Unop
+       && e->Iex.Unop.op == Iop_CmpNEZ8) {
+      HReg     r1   = iselIntExpr_R(env, e->Iex.Unop.arg);
+      ARMRI84* xFF  = ARMRI84_I84(0xFF,0);
+      addInstr(env, ARMInstr_CmpOrTst(False/*!isCmp*/, r1, xFF));
+      return ARMcc_NE;
+   }
+
+   /* --- patterns rooted at: CmpNEZ32 --- */
+
+   if (e->tag == Iex_Unop
+       && e->Iex.Unop.op == Iop_CmpNEZ32) {
+      HReg     r1   = iselIntExpr_R(env, e->Iex.Unop.arg);
+      ARMRI84* zero = ARMRI84_I84(0,0);
+      addInstr(env, ARMInstr_CmpOrTst(True/*isCmp*/, r1, zero));
+      return ARMcc_NE;
+   }
+
+   /* --- patterns rooted at: CmpNEZ64 --- */
+
+   if (e->tag == Iex_Unop
+       && e->Iex.Unop.op == Iop_CmpNEZ64) {
+      HReg     tHi, tLo;
+      HReg     tmp  = newVRegI(env);
+      ARMRI84* zero = ARMRI84_I84(0,0);
+      iselInt64Expr(&tHi, &tLo, env, e->Iex.Unop.arg);
+      addInstr(env, ARMInstr_Alu(ARMalu_OR, tmp, tHi, ARMRI84_R(tLo)));
+      addInstr(env, ARMInstr_CmpOrTst(True/*isCmp*/, tmp, zero));
+      return ARMcc_NE;
    }
+
+   /* --- Cmp*32*(x,y) --- */
+   if (e->tag == Iex_Binop
+       && (e->Iex.Binop.op == Iop_CmpEQ32
+           || e->Iex.Binop.op == Iop_CmpNE32
+           || e->Iex.Binop.op == Iop_CmpLT32S
+           || e->Iex.Binop.op == Iop_CmpLT32U
+           || e->Iex.Binop.op == Iop_CmpLE32S
+           || e->Iex.Binop.op == Iop_CmpLE32U)) {
+      HReg     argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
+      ARMRI84* argR = iselIntExpr_RI84(NULL,False, 
+                                       env, e->Iex.Binop.arg2);
+      addInstr(env, ARMInstr_CmpOrTst(True/*isCmp*/, argL, argR));
+      switch (e->Iex.Binop.op) {
+         case Iop_CmpEQ32:  return ARMcc_EQ;
+         case Iop_CmpNE32:  return ARMcc_NE;
+         case Iop_CmpLT32S: return ARMcc_LT;
+         case Iop_CmpLT32U: return ARMcc_LO;
+         case Iop_CmpLE32S: return ARMcc_LE;
+         case Iop_CmpLE32U: return ARMcc_LS;
+         default: vpanic("iselCondCode(arm): CmpXX32");
+      }
+   }
+
+   ppIRExpr(e);
+   vpanic("iselCondCode");
 }
 
-static ARMAMode3* iselIntExpr_AMode3 ( ISelEnv* env, IRExpr* e )
+
+/* --------------------- Reg --------------------- */
+
+static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
 {
-    ARMAMode3* am = iselIntExpr_AMode3_wrk(env, e);
-    vassert(sane_AMode3(am));
-    return am;
+   HReg r = iselIntExpr_R_wrk(env, e);
+   /* sanity checks ... */
+#  if 0
+   vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
+#  endif
+   vassert(hregClass(r) == HRcInt32);
+   vassert(hregIsVirtual(r));
+   return r;
 }
 
 /* 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);
+static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
+{
+   IRType ty = typeOfIRExpr(env->type_env,e);
+   vassert(ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8);
+
+   switch (e->tag) {
+
+   /* --------- TEMP --------- */
+   case Iex_RdTmp: {
+      return lookupIRTemp(env, e->Iex.RdTmp.tmp);
+   }
+
+   /* --------- LOAD --------- */
+   case Iex_Load: {
+      HReg dst  = newVRegI(env);
 
-    // ARMam3_RI,       /* Reg +/- Imm8 */
-    // ARMam3_RR,       /* Reg +/- Reg */
+      if (e->Iex.Load.end != Iend_LE)
+         goto irreducible;
+
+      if (ty == Ity_I32) {
+         ARMAMode1* amode = iselIntExpr_AMode1 ( env, e->Iex.Load.addr );
+         addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, dst, amode));
+         return dst;
+      }
+      if (ty == Ity_I16) {
+         ARMAMode2* amode = iselIntExpr_AMode2 ( env, e->Iex.Load.addr );
+         addInstr(env, ARMInstr_LdSt16(True/*isLoad*/, False/*!signedLoad*/,
+                                       dst, amode));
+         return dst;
+      }
+      if (ty == Ity_I8) {
+         ARMAMode1* amode = iselIntExpr_AMode1 ( env, e->Iex.Load.addr );
+         addInstr(env, ARMInstr_LdSt8U(True/*isLoad*/, dst, amode));
+         return dst;
+      }
+
+//zz      if (ty == Ity_I16) {
+//zz         addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
+//zz         return dst;
+//zz      }
+//zz      if (ty == Ity_I8) {
+//zz         addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
+//zz         return dst;
+//zz      }
+      break;
+   }
+
+//zz   /* --------- TERNARY OP --------- */
+//zz   case Iex_Triop: {
+//zz      /* C3210 flags following FPU partial remainder (fprem), both
+//zz         IEEE compliant (PREM1) and non-IEEE compliant (PREM). */
+//zz      if (e->Iex.Triop.op == Iop_PRemC3210F64
+//zz          || e->Iex.Triop.op == Iop_PRem1C3210F64) {
+//zz         HReg junk = newVRegF(env);
+//zz         HReg dst  = newVRegI(env);
+//zz         HReg srcL = iselDblExpr(env, e->Iex.Triop.arg2);
+//zz         HReg srcR = iselDblExpr(env, e->Iex.Triop.arg3);
+//zz         /* XXXROUNDINGFIXME */
+//zz         /* set roundingmode here */
+//zz         addInstr(env, X86Instr_FpBinary(
+//zz                           e->Iex.Binop.op==Iop_PRemC3210F64 
+//zz                              ? Xfp_PREM : Xfp_PREM1,
+//zz                           srcL,srcR,junk
+//zz                 ));
+//zz         /* The previous pseudo-insn will have left the FPU's C3210
+//zz            flags set correctly.  So bag them. */
+//zz         addInstr(env, X86Instr_FpStSW_AX());
+//zz         addInstr(env, mk_iMOVsd_RR(hregX86_EAX(), dst));
+//zz         addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0x4700), dst));
+//zz         return dst;
+//zz      }
+//zz
+//zz      break;
+//zz   }
+
+   /* --------- BINARY OP --------- */
+   case Iex_Binop: {
+
+      ARMAluOp   aop = 0; /* invalid */
+      ARMShiftOp sop = 0; /* invalid */
+
+      /* ADD/SUB/AND/OR/XOR */
+      switch (e->Iex.Binop.op) {
+         case Iop_And32: {
+            Bool     didInv = False;
+            HReg     dst    = newVRegI(env);
+            HReg     argL   = iselIntExpr_R(env, e->Iex.Binop.arg1);
+            ARMRI84* argR   = iselIntExpr_RI84(&didInv, True/*mayInv*/,
+                                               env, e->Iex.Binop.arg2);
+            addInstr(env, ARMInstr_Alu(didInv ? ARMalu_BIC : ARMalu_AND,
+                                       dst, argL, argR));
+            return dst;
+         }
+         case Iop_Or32:  aop = ARMalu_OR;  goto std_binop;
+         case Iop_Xor32: aop = ARMalu_XOR; goto std_binop;
+         case Iop_Sub32: aop = ARMalu_SUB; goto std_binop;
+         case Iop_Add32: aop = ARMalu_ADD; goto std_binop;
+         std_binop: {
+            HReg     dst  = newVRegI(env);
+            HReg     argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
+            ARMRI84* argR = iselIntExpr_RI84(NULL, False/*mayInv*/,
+                                             env, e->Iex.Binop.arg2);
+            addInstr(env, ARMInstr_Alu(aop, dst, argL, argR));
+            return dst;
+         }
+         default: break;
+      }
+
+      /* SHL/SHR/SAR */
+      switch (e->Iex.Binop.op) {
+         case Iop_Shl32: sop = ARMsh_SHL; goto sh_binop;
+         case Iop_Shr32: sop = ARMsh_SHR; goto sh_binop;
+         case Iop_Sar32: sop = ARMsh_SAR; goto sh_binop;
+         sh_binop: {
+            HReg    dst  = newVRegI(env);
+            HReg    argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
+            ARMRI5* argR = iselIntExpr_RI5(env, e->Iex.Binop.arg2);
+            addInstr(env, ARMInstr_Shift(sop, dst, argL, argR));
+            vassert(ty == Ity_I32); /* else the IR is ill-typed */
+            return dst;
+         }
+         default: break;
+      }
 
-    return NULL; 
+      /* MUL */
+      if (e->Iex.Binop.op == Iop_Mul32) {
+         HReg argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
+         HReg argR = iselIntExpr_R(env, e->Iex.Binop.arg2);
+         HReg dst  = newVRegI(env);
+         addInstr(env, mk_iMOVds_RR(hregARM_R2(), argL));
+         addInstr(env, mk_iMOVds_RR(hregARM_R3(), argR));
+         addInstr(env, ARMInstr_Mul(ARMmul_PLAIN));
+         addInstr(env, mk_iMOVds_RR(dst, hregARM_R0()));
+         return dst;
+      }
+
+      /* Handle misc other ops. */
+
+      if (e->Iex.Binop.op == Iop_Max32U) {
+         HReg argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
+         HReg argR = iselIntExpr_R(env, e->Iex.Binop.arg2);
+         HReg dst  = newVRegI(env);
+         addInstr(env, ARMInstr_CmpOrTst(True/*isCmp*/, argL, ARMRI84_R(argR)));
+         addInstr(env, mk_iMOVds_RR(dst, argL));
+         addInstr(env, ARMInstr_CMov(ARMcc_LO, dst, ARMRI84_R(argR)));
+         return dst;
+      }
+
+      if (e->Iex.Binop.op == Iop_CmpF64) {
+         HReg dL = iselDblExpr(env, e->Iex.Binop.arg1);
+         HReg dR = iselDblExpr(env, e->Iex.Binop.arg2);
+         HReg dst = newVRegI(env);
+         /* Do the compare (FCMPD) and set NZCV in FPSCR.  Then also do
+            FMSTAT, so we can examine the results directly. */
+         addInstr(env, ARMInstr_VCmpD(dL, dR));
+         /* Create in dst, the IRCmpF64Result encoded result. */
+         addInstr(env, ARMInstr_Imm32(dst, 0));
+         addInstr(env, ARMInstr_CMov(ARMcc_EQ, dst, ARMRI84_I84(0x40,0))); //EQ
+         addInstr(env, ARMInstr_CMov(ARMcc_MI, dst, ARMRI84_I84(0x01,0))); //LT
+         addInstr(env, ARMInstr_CMov(ARMcc_GT, dst, ARMRI84_I84(0x00,0))); //GT
+         addInstr(env, ARMInstr_CMov(ARMcc_VS, dst, ARMRI84_I84(0x45,0))); //UN
+         return dst;
+      }
+
+      if (e->Iex.Binop.op == Iop_F64toI32S
+          || e->Iex.Binop.op == Iop_F64toI32U) {
+         /* Wretched uglyness all round, due to having to deal
+            with rounding modes.  Oh well. */
+         /* FIXME: if arg1 is a constant indicating round-to-zero,
+            then we could skip all this arsing around with FPSCR and
+            simply emit FTO{S,U}IZD. */
+         Bool syned = e->Iex.Binop.op == Iop_F64toI32S;
+         HReg valD  = iselDblExpr(env, e->Iex.Binop.arg2);
+         set_VFP_rounding_mode(env, e->Iex.Binop.arg1);
+         /* FTO{S,U}ID valF, valD */
+         HReg valF = newVRegF(env);
+         addInstr(env, ARMInstr_VCvtID(False/*!iToD*/, syned,
+                                       valF, valD));
+         set_VFP_rounding_default(env);
+         /* VMOV dst, valF */
+         HReg dst = newVRegI(env);
+         addInstr(env, ARMInstr_VXferS(False/*!toS*/, valF, dst));
+         return dst;
+      }
+
+      break;
+   }
+
+   /* --------- UNARY OP --------- */
+   case Iex_Unop: {
+
+//zz      /* 1Uto8(32to1(expr32)) */
+//zz      if (e->Iex.Unop.op == Iop_1Uto8) { 
+//zz         DECLARE_PATTERN(p_32to1_then_1Uto8);
+//zz         DEFINE_PATTERN(p_32to1_then_1Uto8,
+//zz                        unop(Iop_1Uto8,unop(Iop_32to1,bind(0))));
+//zz         if (matchIRExpr(&mi,p_32to1_then_1Uto8,e)) {
+//zz            IRExpr* expr32 = mi.bindee[0];
+//zz            HReg dst = newVRegI(env);
+//zz            HReg src = iselIntExpr_R(env, expr32);
+//zz            addInstr(env, mk_iMOVsd_RR(src,dst) );
+//zz            addInstr(env, X86Instr_Alu32R(Xalu_AND,
+//zz                                          X86RMI_Imm(1), dst));
+//zz            return dst;
+//zz         }
+//zz      }
+//zz
+//zz      /* 8Uto32(LDle(expr32)) */
+//zz      if (e->Iex.Unop.op == Iop_8Uto32) {
+//zz         DECLARE_PATTERN(p_LDle8_then_8Uto32);
+//zz         DEFINE_PATTERN(p_LDle8_then_8Uto32,
+//zz                        unop(Iop_8Uto32,
+//zz                             IRExpr_Load(Iend_LE,Ity_I8,bind(0))) );
+//zz         if (matchIRExpr(&mi,p_LDle8_then_8Uto32,e)) {
+//zz            HReg dst = newVRegI(env);
+//zz            X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
+//zz            addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
+//zz            return dst;
+//zz         }
+//zz      }
+//zz
+//zz      /* 8Sto32(LDle(expr32)) */
+//zz      if (e->Iex.Unop.op == Iop_8Sto32) {
+//zz         DECLARE_PATTERN(p_LDle8_then_8Sto32);
+//zz         DEFINE_PATTERN(p_LDle8_then_8Sto32,
+//zz                        unop(Iop_8Sto32,
+//zz                             IRExpr_Load(Iend_LE,Ity_I8,bind(0))) );
+//zz         if (matchIRExpr(&mi,p_LDle8_then_8Sto32,e)) {
+//zz            HReg dst = newVRegI(env);
+//zz            X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
+//zz            addInstr(env, X86Instr_LoadEX(1,True,amode,dst));
+//zz            return dst;
+//zz         }
+//zz      }
+//zz
+//zz      /* 16Uto32(LDle(expr32)) */
+//zz      if (e->Iex.Unop.op == Iop_16Uto32) {
+//zz         DECLARE_PATTERN(p_LDle16_then_16Uto32);
+//zz         DEFINE_PATTERN(p_LDle16_then_16Uto32,
+//zz                        unop(Iop_16Uto32,
+//zz                             IRExpr_Load(Iend_LE,Ity_I16,bind(0))) );
+//zz         if (matchIRExpr(&mi,p_LDle16_then_16Uto32,e)) {
+//zz            HReg dst = newVRegI(env);
+//zz            X86AMode* amode = iselIntExpr_AMode ( env, mi.bindee[0] );
+//zz            addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
+//zz            return dst;
+//zz         }
+//zz      }
+//zz
+//zz      /* 8Uto32(GET:I8) */
+//zz      if (e->Iex.Unop.op == Iop_8Uto32) {
+//zz         if (e->Iex.Unop.arg->tag == Iex_Get) {
+//zz            HReg      dst;
+//zz            X86AMode* amode;
+//zz            vassert(e->Iex.Unop.arg->Iex.Get.ty == Ity_I8);
+//zz            dst = newVRegI(env);
+//zz            amode = X86AMode_IR(e->Iex.Unop.arg->Iex.Get.offset,
+//zz                                hregX86_EBP());
+//zz            addInstr(env, X86Instr_LoadEX(1,False,amode,dst));
+//zz            return dst;
+//zz         }
+//zz      }
+//zz
+//zz      /* 16to32(GET:I16) */
+//zz      if (e->Iex.Unop.op == Iop_16Uto32) {
+//zz         if (e->Iex.Unop.arg->tag == Iex_Get) {
+//zz            HReg      dst;
+//zz            X86AMode* amode;
+//zz            vassert(e->Iex.Unop.arg->Iex.Get.ty == Ity_I16);
+//zz            dst = newVRegI(env);
+//zz            amode = X86AMode_IR(e->Iex.Unop.arg->Iex.Get.offset,
+//zz                                hregX86_EBP());
+//zz            addInstr(env, X86Instr_LoadEX(2,False,amode,dst));
+//zz            return dst;
+//zz         }
+//zz      }
+
+      switch (e->Iex.Unop.op) {
+         case Iop_8Uto32: {
+            HReg dst = newVRegI(env);
+            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+            addInstr(env, ARMInstr_Alu(ARMalu_AND,
+                                       dst, src, ARMRI84_I84(0xFF,0)));
+            return dst;
+         }
+//zz         case Iop_8Uto16:
+//zz         case Iop_8Uto32:
+//zz         case Iop_16Uto32: {
+//zz            HReg dst = newVRegI(env);
+//zz            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+//zz            UInt mask = e->Iex.Unop.op==Iop_16Uto32 ? 0xFFFF : 0xFF;
+//zz            addInstr(env, mk_iMOVsd_RR(src,dst) );
+//zz            addInstr(env, X86Instr_Alu32R(Xalu_AND,
+//zz                                          X86RMI_Imm(mask), dst));
+//zz            return dst;
+//zz         }
+//zz         case Iop_8Sto16:
+//zz         case Iop_8Sto32:
+         case Iop_16Uto32: {
+            HReg dst = newVRegI(env);
+            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+            ARMRI5* amt = ARMRI5_I5(16);
+            addInstr(env, ARMInstr_Shift(ARMsh_SHL, dst, src, amt));
+            addInstr(env, ARMInstr_Shift(ARMsh_SHR, dst, dst, amt));
+            return dst;
+         }
+         case Iop_8Sto32:
+         case Iop_16Sto32: {
+            HReg dst = newVRegI(env);
+            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+            ARMRI5* amt = ARMRI5_I5(e->Iex.Unop.op==Iop_16Sto32 ? 16 : 24);
+            addInstr(env, ARMInstr_Shift(ARMsh_SHL, dst, src, amt));
+            addInstr(env, ARMInstr_Shift(ARMsh_SAR, dst, dst, amt));
+            return dst;
+         }
+//zz         case Iop_Not8:
+//zz         case Iop_Not16:
+         case Iop_Not32: {
+            HReg dst = newVRegI(env);
+            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+            addInstr(env, ARMInstr_Unary(ARMun_NOT, dst, src));
+            return dst;
+         }
+         case Iop_64HIto32: {
+            HReg rHi, rLo;
+            iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
+            return rHi; /* and abandon rLo .. poor wee thing :-) */
+         }
+         case Iop_64to32: {
+            HReg rHi, rLo;
+            iselInt64Expr(&rHi,&rLo, env, e->Iex.Unop.arg);
+            return rLo; /* similar stupid comment to the above ... */
+         }
+//zz         case Iop_16HIto8:
+//zz         case Iop_32HIto16: {
+//zz            HReg dst  = newVRegI(env);
+//zz            HReg src  = iselIntExpr_R(env, e->Iex.Unop.arg);
+//zz            Int shift = e->Iex.Unop.op == Iop_16HIto8 ? 8 : 16;
+//zz            addInstr(env, mk_iMOVsd_RR(src,dst) );
+//zz            addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, dst));
+//zz            return dst;
+//zz         }
+         case Iop_1Uto32:
+         case Iop_1Uto8: {
+            HReg        dst  = newVRegI(env);
+            ARMCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
+            addInstr(env, ARMInstr_Mov(dst, ARMRI84_I84(0,0)));
+            addInstr(env, ARMInstr_CMov(cond, dst, ARMRI84_I84(1,0)));
+            return dst;
+         }
+
+         case Iop_1Sto32: {
+            HReg        dst  = newVRegI(env);
+            ARMCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
+            ARMRI5*     amt  = ARMRI5_I5(31);
+            /* This is really rough.  We could do much better here;
+               perhaps mvn{cond} dst, #0 as the second insn?
+               (same applies to 1Sto64) */
+            addInstr(env, ARMInstr_Mov(dst, ARMRI84_I84(0,0)));
+            addInstr(env, ARMInstr_CMov(cond, dst, ARMRI84_I84(1,0)));
+            addInstr(env, ARMInstr_Shift(ARMsh_SHL, dst, dst, amt));
+            addInstr(env, ARMInstr_Shift(ARMsh_SAR, dst, dst, amt));
+            return dst;
+         }
+
+
+//zz         case Iop_1Sto8:
+//zz         case Iop_1Sto16:
+//zz         case Iop_1Sto32: {
+//zz            /* could do better than this, but for now ... */
+//zz            HReg dst         = newVRegI(env);
+//zz            X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
+//zz            addInstr(env, X86Instr_Set32(cond,dst));
+//zz            addInstr(env, X86Instr_Sh32(Xsh_SHL, 31, dst));
+//zz            addInstr(env, X86Instr_Sh32(Xsh_SAR, 31, dst));
+//zz            return dst;
+//zz         }
+//zz         case Iop_Ctz32: {
+//zz            /* Count trailing zeroes, implemented by x86 'bsfl' */
+//zz            HReg dst = newVRegI(env);
+//zz            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+//zz            addInstr(env, X86Instr_Bsfr32(True,src,dst));
+//zz            return dst;
+//zz         }
+         case Iop_Clz32: {
+            /* Count leading zeroes; easy on ARM. */
+            HReg dst = newVRegI(env);
+            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+            addInstr(env, ARMInstr_Unary(ARMun_CLZ, dst, src));
+            return dst;
+         }
+
+         case Iop_CmpwNEZ32: {
+            HReg dst = newVRegI(env);
+            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+            addInstr(env, ARMInstr_Unary(ARMun_NEG, dst, src));
+            addInstr(env, ARMInstr_Alu(ARMalu_OR, dst, dst, ARMRI84_R(src)));
+            addInstr(env, ARMInstr_Shift(ARMsh_SAR, dst, dst, ARMRI5_I5(31)));
+            return dst;
+         }
+
+         case Iop_Left32: {
+            HReg dst = newVRegI(env);
+            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+            addInstr(env, ARMInstr_Unary(ARMun_NEG, dst, src));
+            addInstr(env, ARMInstr_Alu(ARMalu_OR, dst, dst, ARMRI84_R(src)));
+            return dst;
+         }
+
+//zz         case Iop_V128to32: {
+//zz            HReg      dst  = newVRegI(env);
+//zz            HReg      vec  = iselVecExpr(env, e->Iex.Unop.arg);
+//zz            X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
+//zz            sub_from_esp(env, 16);
+//zz            addInstr(env, X86Instr_SseLdSt(False/*store*/, vec, esp0));
+//zz            addInstr(env, X86Instr_Alu32R( Xalu_MOV, X86RMI_Mem(esp0), dst ));
+//zz            add_to_esp(env, 16);
+//zz            return dst;
+//zz         }
+//zz
+         case Iop_ReinterpF32asI32: {
+            HReg dst = newVRegI(env);
+            HReg src = iselFltExpr(env, e->Iex.Unop.arg);
+            addInstr(env, ARMInstr_VXferS(False/*!toS*/, src, dst));
+            return dst;
+         }
+
+//zz
+//zz         case Iop_16to8:
+         case Iop_32to8:
+         case Iop_32to16:
+            /* These are no-ops. */
+            return iselIntExpr_R(env, e->Iex.Unop.arg);
+
+         default: 
+            break;
+      }
+      break;
+   }
+
+   /* --------- GET --------- */
+   case Iex_Get: {
+      if (ty == Ity_I32 
+          && 0 == (e->Iex.Get.offset & 3)
+          && e->Iex.Get.offset < 4096-4) {
+         HReg dst = newVRegI(env);
+         addInstr(env, ARMInstr_LdSt32(
+                          True/*isLoad*/,
+                          dst,
+                          ARMAMode1_RI(hregARM_R8(), e->Iex.Get.offset)));
+         return dst;
+      }
+//zz      if (ty == Ity_I8 || ty == Ity_I16) {
+//zz         HReg dst = newVRegI(env);
+//zz         addInstr(env, X86Instr_LoadEX(
+//zz                          toUChar(ty==Ity_I8 ? 1 : 2),
+//zz                          False,
+//zz                          X86AMode_IR(e->Iex.Get.offset,hregX86_EBP()),
+//zz                          dst));
+//zz         return dst;
+//zz      }
+      break;
+   }
+
+//zz   case Iex_GetI: {
+//zz      X86AMode* am 
+//zz         = genGuestArrayOffset(
+//zz              env, e->Iex.GetI.descr, 
+//zz                   e->Iex.GetI.ix, e->Iex.GetI.bias );
+//zz      HReg dst = newVRegI(env);
+//zz      if (ty == Ity_I8) {
+//zz         addInstr(env, X86Instr_LoadEX( 1, False, am, dst ));
+//zz         return dst;
+//zz      }
+//zz      if (ty == Ity_I32) {
+//zz         addInstr(env, X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(am), dst));
+//zz         return dst;
+//zz      }
+//zz      break;
+//zz   }
+
+   /* --------- CCALL --------- */
+   case Iex_CCall: {
+      HReg    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)
+         goto irreducible;
+
+      /* Marshal args, do the call, clear stack. */
+      Bool ok = doHelperCall( env, False,
+                              NULL, e->Iex.CCall.cee, e->Iex.CCall.args );
+      if (ok) {
+         addInstr(env, mk_iMOVds_RR(dst, hregARM_R0()));
+         return dst;
+      }
+      /* else fall through; will hit the irreducible: label */
+   }
+
+   /* --------- LITERAL --------- */
+   /* 32 literals */
+   case Iex_Const: {
+      UInt u   = 0;
+      HReg dst = newVRegI(env);
+      switch (e->Iex.Const.con->tag) {
+         case Ico_U32: u = e->Iex.Const.con->Ico.U32; break;
+         case Ico_U16: u = 0xFFFF & (e->Iex.Const.con->Ico.U16); break;
+         case Ico_U8:  u = 0xFF   & (e->Iex.Const.con->Ico.U8); break;
+         default: vpanic("iselIntExpr_R.Iex_Const(arm)");
+      }
+      addInstr(env, ARMInstr_Imm32(dst, u));
+      return dst;
+   }
+
+   /* --------- MULTIPLEX --------- */
+   case Iex_Mux0X: {
+      IRExpr* cond = e->Iex.Mux0X.cond;
+
+      /* Mux0X( 32to8(1Uto32(ccexpr)), expr0, exprX ) */
+      if (ty == Ity_I32
+          && cond->tag == Iex_Unop
+          && cond->Iex.Unop.op == Iop_32to8
+          && cond->Iex.Unop.arg->tag == Iex_Unop
+          && cond->Iex.Unop.arg->Iex.Unop.op == Iop_1Uto32) {
+         ARMCondCode cc;
+         HReg     rX  = iselIntExpr_R(env, e->Iex.Mux0X.exprX);
+         ARMRI84* r0  = iselIntExpr_RI84(NULL, False, env, e->Iex.Mux0X.expr0);
+         HReg     dst = newVRegI(env);
+         addInstr(env, mk_iMOVds_RR(dst, rX));
+         cc = iselCondCode(env, cond->Iex.Unop.arg->Iex.Unop.arg);
+         addInstr(env, ARMInstr_CMov(cc ^ 1, dst, r0));
+         return dst;
+      }
+
+      /* Mux0X(cond, expr0, exprX) (general case) */
+      if (ty == Ity_I32) {
+         HReg     r8;
+         HReg     rX  = iselIntExpr_R(env, e->Iex.Mux0X.exprX);
+         ARMRI84* r0  = iselIntExpr_RI84(NULL, False, env, e->Iex.Mux0X.expr0);
+         HReg     dst = newVRegI(env);
+         addInstr(env, mk_iMOVds_RR(dst, rX));
+         r8 = iselIntExpr_R(env, cond);
+         addInstr(env, ARMInstr_CmpOrTst(False/*!isCmp*/, r8,
+                                         ARMRI84_I84(0xFF,0)));
+         addInstr(env, ARMInstr_CMov(ARMcc_EQ, dst, r0));
+         return dst;
+      }
+      break;
+   }
+
+   default: 
+   break;
+   } /* switch (e->tag) */
+
+   /* We get here if no pattern matched. */
+  irreducible:
+   ppIRExpr(e);
+   vpanic("iselIntExpr_R: cannot reduce tree");
 }
 
 
+/* -------------------- 64-bit -------------------- */
 
-/* ---------------- Branch Destination ---------------- */
+/* Compute a 64-bit value into a register pair, which is returned as
+   the first two parameters.  As with iselIntExpr_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 ARMBranchDest* iselIntExpr_BD ( ISelEnv* env, IRExpr* e )
+static void iselInt64Expr ( HReg* rHi, HReg* rLo, 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");
-   }
+   iselInt64Expr_wrk(rHi, rLo, env, e);
+#  if 0
+   vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
+#  endif
+   vassert(hregClass(*rHi) == HRcInt32);
+   vassert(hregIsVirtual(*rHi));
+   vassert(hregClass(*rLo) == HRcInt32);
+   vassert(hregIsVirtual(*rLo));
 }
 
 /* DO NOT CALL THIS DIRECTLY ! */
-static ARMBranchDest* iselIntExpr_BD_wrk ( ISelEnv* env, IRExpr* e )
+static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
 {
-    /*
-      ARMbdImm,
-      ARMbdReg
-    */
+   vassert(e);
+   vassert(typeOfIRExpr(env->type_env,e) == Ity_I64);
+
+   /* 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    tHi = newVRegI(env);
+      HReg    tLo = newVRegI(env);
+      vassert(e->Iex.Const.con->tag == Ico_U64);
+      addInstr(env, ARMInstr_Imm32(tHi, wHi));
+      addInstr(env, ARMInstr_Imm32(tLo, wLo));
+      *rHi = tHi;
+      *rLo = tLo;
+      return;
+   }
 
-    return NULL;
-}
+   /* 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 && e->Iex.Load.end == Iend_LE) {
+      HReg      tLo, tHi, rA;
+      vassert(e->Iex.Load.ty == Ity_I64);
+      rA  = iselIntExpr_R(env, e->Iex.Load.addr);
+      tHi = newVRegI(env);
+      tLo = newVRegI(env);
+      addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tHi, ARMAMode1_RI(rA, 4)));
+      addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tLo, ARMAMode1_RI(rA, 0)));
+      *rHi = tHi;
+      *rLo = tLo;
+      return;
+   }
 
+   /* 64-bit GET */
+   if (e->tag == Iex_Get) {
+      ARMAMode1* am0 = ARMAMode1_RI(hregARM_R8(), e->Iex.Get.offset + 0);
+      ARMAMode1* am4 = ARMAMode1_RI(hregARM_R8(), e->Iex.Get.offset + 4);
+      HReg tHi = newVRegI(env);
+      HReg tLo = newVRegI(env);
+      addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tHi, am4));
+      addInstr(env, ARMInstr_LdSt32(True/*isLoad*/, tLo, am0));
+      *rHi = tHi;
+      *rLo = tLo;
+      return;
+   }
 
+   /* --------- BINARY ops --------- */
+   if (e->tag == Iex_Binop) {
+      switch (e->Iex.Binop.op) {
+
+         /* 32 x 32 -> 64 multiply */
+         case Iop_MullS32:
+         case Iop_MullU32: {
+            HReg     argL = iselIntExpr_R(env, e->Iex.Binop.arg1);
+            HReg     argR = iselIntExpr_R(env, e->Iex.Binop.arg2);
+            HReg     tHi  = newVRegI(env);
+            HReg     tLo  = newVRegI(env);
+            ARMMulOp mop  = e->Iex.Binop.op == Iop_MullS32
+                               ? ARMmul_SX : ARMmul_ZX;
+            addInstr(env, mk_iMOVds_RR(hregARM_R2(), argL));
+            addInstr(env, mk_iMOVds_RR(hregARM_R3(), argR));
+            addInstr(env, ARMInstr_Mul(mop));
+            addInstr(env, mk_iMOVds_RR(tHi, hregARM_R1()));
+            addInstr(env, mk_iMOVds_RR(tLo, hregARM_R0()));
+            *rHi = tHi;
+            *rLo = tLo;
+            return;
+         }
 
+         case Iop_Or64: {
+            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, ARMInstr_Alu(ARMalu_OR, tHi, xHi, ARMRI84_R(yHi)));
+            addInstr(env, ARMInstr_Alu(ARMalu_OR, tLo, xLo, ARMRI84_R(yLo)));
+            *rHi = tHi;
+            *rLo = tLo;
+            return;
+         }
 
-/* --------------------- CONDCODE --------------------- */
+         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, ARMInstr_Alu(ARMalu_ADDS, tLo, xLo, ARMRI84_R(yLo)));
+            addInstr(env, ARMInstr_Alu(ARMalu_ADC,  tHi, xHi, ARMRI84_R(yHi)));
+            *rHi = tHi;
+            *rLo = tLo;
+            return;
+         }
 
-/* Generate code to evaluated a bit-typed expression, returning the
-   condition code which would correspond when the expression would
-   notionally have returned 1. */
+         /* 32HLto64(e1,e2) */
+         case Iop_32HLto64: {
+            *rHi = iselIntExpr_R(env, e->Iex.Binop.arg1);
+            *rLo = iselIntExpr_R(env, e->Iex.Binop.arg2);
+            return;
+         }
 
-static ARMCondCode iselCondCode ( ISelEnv* env, IRExpr* e )
+         default:
+            break;
+      }
+   }
+
+   /* --------- UNARY ops --------- */
+   if (e->tag == Iex_Unop) {
+      switch (e->Iex.Unop.op) {
+
+         /* ReinterpF64asI64 */
+         case Iop_ReinterpF64asI64: {
+            HReg dstHi = newVRegI(env);
+            HReg dstLo = newVRegI(env);
+            HReg src   = iselDblExpr(env, e->Iex.Unop.arg);
+            addInstr(env, ARMInstr_VXferD(False/*!toD*/, src, dstHi, dstLo));
+            *rHi = dstHi;
+            *rLo = dstLo;
+            return;
+         }
+
+         /* Left64(e) */
+         case Iop_Left64: {
+            HReg yLo, yHi;
+            HReg tHi  = newVRegI(env);
+            HReg tLo  = newVRegI(env);
+            HReg zero = newVRegI(env);
+            /* yHi:yLo = arg */
+            iselInt64Expr(&yHi, &yLo, env, e->Iex.Unop.arg);
+            /* zero = 0 */
+            addInstr(env, ARMInstr_Imm32(zero, 0));
+            /* tLo = 0 - yLo, and set carry */
+            addInstr(env, ARMInstr_Alu(ARMalu_SUBS, tLo, zero, ARMRI84_R(yLo)));
+            /* tHi = 0 - yHi - carry */
+            addInstr(env, ARMInstr_Alu(ARMalu_SBC,  tHi, zero, ARMRI84_R(yHi)));
+            /* So now we have tHi:tLo = -arg.  To finish off, or 'arg'
+               back in, so as to give the final result 
+               tHi:tLo = arg | -arg. */
+            addInstr(env, ARMInstr_Alu(ARMalu_OR, tHi, tHi, ARMRI84_R(yHi)));
+            addInstr(env, ARMInstr_Alu(ARMalu_OR, tLo, tLo, ARMRI84_R(yLo)));
+            *rHi = tHi;
+            *rLo = tLo;
+            return;
+         }
+
+         /* CmpwNEZ64(e) */
+         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, ARMInstr_Alu(ARMalu_OR,
+                                       tmp1, srcHi, ARMRI84_R(srcLo)));
+            /* tmp2 = (tmp1 | -tmp1) >>s 31 */
+            addInstr(env, ARMInstr_Unary(ARMun_NEG, tmp2, tmp1));
+            addInstr(env, ARMInstr_Alu(ARMalu_OR,
+                                       tmp2, tmp2, ARMRI84_R(tmp1)));
+            addInstr(env, ARMInstr_Shift(ARMsh_SAR,
+                                         tmp2, tmp2, ARMRI5_I5(31)));
+            *rHi = tmp2;
+            *rLo = tmp2;
+            return;
+         }
+
+         case Iop_1Sto64: {
+            HReg        dst  = newVRegI(env);
+            ARMCondCode cond = iselCondCode(env, e->Iex.Unop.arg);
+            ARMRI5*     amt  = ARMRI5_I5(31);
+            /* This is really rough.  We could do much better here;
+               perhaps mvn{cond} dst, #0 as the second insn?
+               (same applies to 1Sto32) */
+            addInstr(env, ARMInstr_Mov(dst, ARMRI84_I84(0,0)));
+            addInstr(env, ARMInstr_CMov(cond, dst, ARMRI84_I84(1,0)));
+            addInstr(env, ARMInstr_Shift(ARMsh_SHL, dst, dst, amt));
+            addInstr(env, ARMInstr_Shift(ARMsh_SAR, dst, dst, amt));
+            *rHi = dst;
+            *rLo = dst;
+            return;
+         }
+
+         default: 
+            break;
+      }
+   } /* if (e->tag == Iex_Unop) */
+
+   /* --------- MULTIPLEX --------- */
+   if (e->tag == Iex_Mux0X) {
+      IRType ty8;
+      HReg   r8, rXhi, rXlo, r0hi, r0lo, dstHi, dstLo;
+      ty8 = typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond);
+      vassert(ty8 == Ity_I8);
+      iselInt64Expr(&rXhi, &rXlo, env, e->Iex.Mux0X.exprX);
+      iselInt64Expr(&r0hi, &r0lo, env, e->Iex.Mux0X.expr0);
+      dstHi = newVRegI(env);
+      dstLo = newVRegI(env);
+      addInstr(env, mk_iMOVds_RR(dstHi, rXhi));
+      addInstr(env, mk_iMOVds_RR(dstLo, rXlo));
+      r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
+      addInstr(env, ARMInstr_CmpOrTst(False/*!isCmp*/, r8,
+                                      ARMRI84_I84(0xFF,0)));
+      addInstr(env, ARMInstr_CMov(ARMcc_EQ, dstHi, ARMRI84_R(r0hi)));
+      addInstr(env, ARMInstr_CMov(ARMcc_EQ, dstLo, ARMRI84_R(r0lo)));
+      *rHi = dstHi;
+      *rLo = dstLo;
+      return;
+   }
+
+   ppIRExpr(e);
+   vpanic("iselInt64Expr");
+}
+
+
+/*---------------------------------------------------------*/
+/*--- ISEL: Floating point expressions (64 bit)         ---*/
+/*---------------------------------------------------------*/
+
+/* Compute a 64-bit floating point value into a register, the identity
+   of which is returned.  As with iselIntExpr_R, the reg may be either
+   real or virtual; in any case it must not be changed by subsequent
+   code emitted by the caller.  */
+
+static HReg iselDblExpr ( ISelEnv* env, IRExpr* e )
 {
-    /* Uh, there's nothing we can sanity check here, unfortunately. */
-    return iselCondCode_wrk(env, e);
+   HReg r = iselDblExpr_wrk( env, e );
+#  if 0
+   vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
+#  endif
+   vassert(hregClass(r) == HRcFlt64);
+   vassert(hregIsVirtual(r));
+   return r;
 }
 
-/* DO NOT CALL THIS DIRECTLY */
-static ARMCondCode iselCondCode_wrk ( ISelEnv* env, IRExpr* e )
+/* DO NOT CALL THIS DIRECTLY */
+static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
 {
-#if 0
-    MatchInfo mi;
-    DECLARE_PATTERN(p_32to1);
-    DECLARE_PATTERN(p_1Uto32_then_32to1);
-#endif
+   IRType ty = typeOfIRExpr(env->type_env,e);
+   vassert(e);
+   vassert(ty == Ity_F64);
 
-    return 0;
+   if (e->tag == Iex_RdTmp) {
+      return lookupIRTemp(env, e->Iex.RdTmp.tmp);
+   }
+
+   if (e->tag == Iex_Const) {
+      /* Just handle the zero case. */
+      IRConst* con = e->Iex.Const.con;
+      if (con->tag == Ico_F64i && con->Ico.F64i == 0ULL) {
+         HReg z32 = newVRegI(env);
+         HReg dst = newVRegD(env);
+         addInstr(env, ARMInstr_Imm32(z32, 0));
+         addInstr(env, ARMInstr_VXferD(True/*toD*/, dst, z32, z32));
+         return dst;
+      }
+   }
+
+   if (e->tag == Iex_Load && e->Iex.Load.end == Iend_LE) {
+      ARMAModeV* am;
+      HReg res = newVRegD(env);
+      vassert(e->Iex.Load.ty == Ity_F64);
+      am = iselIntExpr_AModeV(env, e->Iex.Load.addr);
+      addInstr(env, ARMInstr_VLdStD(True/*isLoad*/, res, am));
+      return res;
+   }
+
+   if (e->tag == Iex_Get) {
+      // XXX This won't work if offset > 1020 or is not 0 % 4.
+      // In which case we'll have to generate more longwinded code.
+      ARMAModeV* am  = mkARMAModeV(hregARM_R8(), e->Iex.Get.offset);
+      HReg       res = newVRegD(env);
+      addInstr(env, ARMInstr_VLdStD(True/*isLoad*/, res, am));
+      return res;
+   }
+
+   if (e->tag == Iex_Unop) {
+      switch (e->Iex.Unop.op) {
+         case Iop_ReinterpI64asF64: {
+            HReg srcHi, srcLo;
+            HReg dst = newVRegD(env);
+            iselInt64Expr(&srcHi, &srcLo, env, e->Iex.Unop.arg);
+            addInstr(env, ARMInstr_VXferD(True/*toD*/, dst, srcHi, srcLo));
+            return dst;
+         }
+         case Iop_NegF64: {
+            HReg src = iselDblExpr(env, e->Iex.Unop.arg);
+            HReg dst = newVRegD(env);
+            addInstr(env, ARMInstr_VUnaryD(ARMvfpu_NEG, dst, src));
+            return dst;
+         }
+         case Iop_AbsF64: {
+            HReg src = iselDblExpr(env, e->Iex.Unop.arg);
+            HReg dst = newVRegD(env);
+            addInstr(env, ARMInstr_VUnaryD(ARMvfpu_ABS, dst, src));
+            return dst;
+         }
+         case Iop_F32toF64: {
+            HReg src = iselFltExpr(env, e->Iex.Unop.arg);
+            HReg dst = newVRegD(env);
+            addInstr(env, ARMInstr_VCvtSD(True/*sToD*/, dst, src));
+            return dst;
+         }
+         case Iop_I32UtoF64:
+         case Iop_I32StoF64: {
+            HReg src   = iselIntExpr_R(env, e->Iex.Unop.arg);
+            HReg f32   = newVRegF(env);
+            HReg dst   = newVRegD(env);
+            Bool syned = e->Iex.Unop.op == Iop_I32StoF64;
+            /* VMOV f32, src */
+            addInstr(env, ARMInstr_VXferS(True/*toS*/, f32, src));
+            /* FSITOD dst, f32 */
+            addInstr(env, ARMInstr_VCvtID(True/*iToD*/, syned,
+                                          dst, f32));
+            return dst;
+         }
+         default:
+            break;
+      }
+   }
+
+   if (e->tag == Iex_Binop) {
+      switch (e->Iex.Binop.op) {
+         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, ARMInstr_VUnaryD(ARMvfpu_SQRT, dst, src));
+            return dst;
+         }
+         default:
+            break;
+      }
+   }
+
+   if (e->tag == Iex_Triop) {
+      switch (e->Iex.Triop.op) {
+         case Iop_DivF64:
+         case Iop_MulF64:
+         case Iop_AddF64:
+         case Iop_SubF64: {
+            ARMVfpOp op = 0; /*INVALID*/
+            HReg argL = iselDblExpr(env, e->Iex.Triop.arg2);
+            HReg argR = iselDblExpr(env, e->Iex.Triop.arg3);
+            HReg dst  = newVRegD(env);
+            switch (e->Iex.Triop.op) {
+               case Iop_DivF64: op = ARMvfp_DIV; break;
+               case Iop_MulF64: op = ARMvfp_MUL; break;
+               case Iop_AddF64: op = ARMvfp_ADD; break;
+               case Iop_SubF64: op = ARMvfp_SUB; break;
+               default: vassert(0);
+            }
+            addInstr(env, ARMInstr_VAluD(op, dst, argL, argR));
+            return dst;
+         }
+         default:
+            break;
+      }
+   }
+
+   if (e->tag == Iex_Mux0X) {
+      if (ty == Ity_F64
+          && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
+         HReg r8;
+         HReg rX  = iselDblExpr(env, e->Iex.Mux0X.exprX);
+         HReg r0  = iselDblExpr(env, e->Iex.Mux0X.expr0);
+         HReg dst = newVRegD(env);
+         addInstr(env, ARMInstr_VUnaryD(ARMvfpu_COPY, dst, rX));
+         r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
+         addInstr(env, ARMInstr_CmpOrTst(False/*!isCmp*/, r8,
+                                         ARMRI84_I84(0xFF,0)));
+         addInstr(env, ARMInstr_VCMovD(ARMcc_EQ, dst, r0));
+         return dst;
+      }
+   }
+
+   ppIRExpr(e);
+   vpanic("iselDblExpr_wrk");
 }
 
 
+/*---------------------------------------------------------*/
+/*--- ISEL: Floating point expressions (32 bit)         ---*/
+/*---------------------------------------------------------*/
 
-static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
+/* Compute a 64-bit floating point value into a register, the identity
+   of which is returned.  As with iselIntExpr_R, the reg may be either
+   real or virtual; in any case it must not be changed by subsequent
+   code emitted by the caller.  */
+
+static HReg iselFltExpr ( ISelEnv* env, IRExpr* e )
 {
-    return iselIntExpr_R_wrk(env, e);
+   HReg r = iselFltExpr_wrk( env, e );
+#  if 0
+   vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
+#  endif
+   vassert(hregClass(r) == HRcFlt32);
+   vassert(hregIsVirtual(r));
+   return r;
 }
 
-/* DO NOT CALL THIS DIRECTLY */
-static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
+/* DO NOT CALL THIS DIRECTLY */
+static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e )
 {
-    return 0;
-}
+   IRType ty = typeOfIRExpr(env->type_env,e);
+   vassert(e);
+   vassert(ty == Ity_F32);
 
+   if (e->tag == Iex_RdTmp) {
+      return lookupIRTemp(env, e->Iex.RdTmp.tmp);
+   }
+
+   if (e->tag == Iex_Load && e->Iex.Load.end == Iend_LE) {
+      ARMAModeV* am;
+      HReg res = newVRegF(env);
+      vassert(e->Iex.Load.ty == Ity_F32);
+      am = iselIntExpr_AModeV(env, e->Iex.Load.addr);
+      addInstr(env, ARMInstr_VLdStS(True/*isLoad*/, res, am));
+      return res;
+   }
+
+   if (e->tag == Iex_Get) {
+      // XXX This won't work if offset > 1020 or is not 0 % 4.
+      // In which case we'll have to generate more longwinded code.
+      ARMAModeV* am  = mkARMAModeV(hregARM_R8(), e->Iex.Get.offset);
+      HReg       res = newVRegF(env);
+      addInstr(env, ARMInstr_VLdStS(True/*isLoad*/, res, am));
+      return res;
+   }
+
+   if (e->tag == Iex_Unop) {
+      switch (e->Iex.Unop.op) {
+         case Iop_ReinterpI32asF32: {
+            HReg dst = newVRegF(env);
+            HReg src = iselIntExpr_R(env, e->Iex.Unop.arg);
+            addInstr(env, ARMInstr_VXferS(True/*toS*/, dst, src));
+            return dst;
+         }
+         case Iop_NegF32: {
+            HReg src = iselFltExpr(env, e->Iex.Unop.arg);
+            HReg dst = newVRegF(env);
+            addInstr(env, ARMInstr_VUnaryS(ARMvfpu_NEG, dst, src));
+            return dst;
+         }
+         case Iop_AbsF32: {
+            HReg src = iselFltExpr(env, e->Iex.Unop.arg);
+            HReg dst = newVRegF(env);
+            addInstr(env, ARMInstr_VUnaryS(ARMvfpu_ABS, dst, src));
+            return dst;
+         }
+         default:
+            break;
+      }
+   }
+
+   if (e->tag == Iex_Binop) {
+      switch (e->Iex.Binop.op) {
+         case Iop_SqrtF32: {
+            /* first arg is rounding mode; we ignore it. */
+            HReg src = iselFltExpr(env, e->Iex.Binop.arg2);
+            HReg dst = newVRegF(env);
+            addInstr(env, ARMInstr_VUnaryS(ARMvfpu_SQRT, dst, src));
+            return dst;
+         }
+         case Iop_F64toF32: {
+            HReg valD = iselDblExpr(env, e->Iex.Binop.arg2);
+            set_VFP_rounding_mode(env, e->Iex.Binop.arg1);
+            HReg valS = newVRegF(env);
+            /* FCVTSD valS, valD */
+            addInstr(env, ARMInstr_VCvtSD(False/*!sToD*/, valS, valD));
+            set_VFP_rounding_default(env);
+            return valS;
+         }
+         default:
+            break;
+      }
+   }
+
+   if (e->tag == Iex_Triop) {
+      switch (e->Iex.Triop.op) {
+         case Iop_DivF32:
+         case Iop_MulF32:
+         case Iop_AddF32:
+         case Iop_SubF32: {
+            ARMVfpOp op = 0; /*INVALID*/
+            HReg argL = iselFltExpr(env, e->Iex.Triop.arg2);
+            HReg argR = iselFltExpr(env, e->Iex.Triop.arg3);
+            HReg dst  = newVRegF(env);
+            switch (e->Iex.Triop.op) {
+               case Iop_DivF32: op = ARMvfp_DIV; break;
+               case Iop_MulF32: op = ARMvfp_MUL; break;
+               case Iop_AddF32: op = ARMvfp_ADD; break;
+               case Iop_SubF32: op = ARMvfp_SUB; break;
+               default: vassert(0);
+            }
+            addInstr(env, ARMInstr_VAluS(op, dst, argL, argR));
+            return dst;
+         }
+         default:
+            break;
+      }
+   }
+
+   if (e->tag == Iex_Mux0X) {
+      if (ty == Ity_F32
+          && typeOfIRExpr(env->type_env,e->Iex.Mux0X.cond) == Ity_I8) {
+         HReg r8;
+         HReg rX  = iselFltExpr(env, e->Iex.Mux0X.exprX);
+         HReg r0  = iselFltExpr(env, e->Iex.Mux0X.expr0);
+         HReg dst = newVRegF(env);
+         addInstr(env, ARMInstr_VUnaryS(ARMvfpu_COPY, dst, rX));
+         r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond);
+         addInstr(env, ARMInstr_CmpOrTst(False/*!isCmp*/, r8,
+                                         ARMRI84_I84(0xFF,0)));
+         addInstr(env, ARMInstr_VCMovS(ARMcc_EQ, dst, r0));
+         return dst;
+      }
+   }
+
+   ppIRExpr(e);
+   vpanic("iselFltExpr_wrk");
+}
 
 
 /*---------------------------------------------------------*/
@@ -753,78 +2143,116 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
    /* --------- 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;
+      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;
 
-       if (tya != Ity_I32 || end != Iend_LE)
-          goto stmt_fail;
+      if (tya != Ity_I32 || end != Iend_LE) 
+         goto stmt_fail;
 
-       reg = iselIntExpr_R(env, stmt->Ist.Store.data);
+      if (tyd == Ity_I32) {
+         HReg       rD = iselIntExpr_R(env, stmt->Ist.Store.data);
+         ARMAMode1* am = iselIntExpr_AMode1(env, stmt->Ist.Store.addr);
+         addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rD, am));
+         return;
+      }
+      if (tyd == Ity_I16) {
+         HReg       rD = iselIntExpr_R(env, stmt->Ist.Store.data);
+         ARMAMode2* am = iselIntExpr_AMode2(env, stmt->Ist.Store.addr);
+         addInstr(env, ARMInstr_LdSt16(False/*!isLoad*/,
+                                       False/*!isSignedLoad*/, rD, am));
+         return;
+      }
+      if (tyd == Ity_I8) {
+         HReg       rD = iselIntExpr_R(env, stmt->Ist.Store.data);
+         ARMAMode1* am = iselIntExpr_AMode1(env, stmt->Ist.Store.addr);
+         addInstr(env, ARMInstr_LdSt8U(False/*!isLoad*/, rD, am));
+         return;
+      }
+      if (tyd == Ity_I64) {
+         HReg rDhi, rDlo, rA;
+         iselInt64Expr(&rDhi, &rDlo, env, stmt->Ist.Store.data);
+         rA = iselIntExpr_R(env, stmt->Ist.Store.addr);
+         addInstr(env, ARMInstr_LdSt32(False/*!load*/, rDhi,
+                                       ARMAMode1_RI(rA,4)));
+         addInstr(env, ARMInstr_LdSt32(False/*!load*/, rDlo,
+                                       ARMAMode1_RI(rA,0)));
+         return;
+      }
+      if (tyd == Ity_F64) {
+         HReg       dD = iselDblExpr(env, stmt->Ist.Store.data);
+         ARMAModeV* am = iselIntExpr_AModeV(env, stmt->Ist.Store.addr);
+         addInstr(env, ARMInstr_VLdStD(False/*!isLoad*/, dD, am));
+         return;
+      }
+      if (tyd == Ity_F32) {
+         HReg       fD = iselFltExpr(env, stmt->Ist.Store.data);
+         ARMAModeV* am = iselIntExpr_AModeV(env, stmt->Ist.Store.addr);
+         addInstr(env, ARMInstr_VLdStS(False/*!isLoad*/, fD, am));
+         return;
+      }
 
-       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;
-       }       
+      break;
    }
 
    /* --------- 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;
+           HReg       rD = iselIntExpr_R(env, stmt->Ist.Put.data);
+           ARMAMode1* am = ARMAMode1_RI(hregARM_R8(), stmt->Ist.Put.offset);
+           addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rD, am));
+           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_I64) {
+          HReg rDhi, rDlo;
+          ARMAMode1* am0 = ARMAMode1_RI(hregARM_R8(), stmt->Ist.Put.offset + 0);
+          ARMAMode1* am4 = ARMAMode1_RI(hregARM_R8(), stmt->Ist.Put.offset + 4);
+          iselInt64Expr(&rDhi, &rDlo, env, stmt->Ist.Put.data);
+          addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rDhi, am4));
+          addInstr(env, ARMInstr_LdSt32(False/*!isLoad*/, rDlo, am0));
+          return;
        }
-       if (tyd == Ity_I8) {
-          ARMAMode2* am2 = ARMAMode2_RI(GET_BP_REG(), stmt->Ist.Put.offset);
-          addInstr(env, ARMInstr_StoreB(reg, am2));
-          return;
+       if (tyd == Ity_F64) {
+          // XXX This won't work if offset > 1020 or is not 0 % 4.
+          // In which case we'll have to generate more longwinded code.
+          ARMAModeV* am = mkARMAModeV(hregARM_R8(), stmt->Ist.Put.offset);
+          HReg       rD = iselDblExpr(env, stmt->Ist.Put.data);
+          addInstr(env, ARMInstr_VLdStD(False/*!isLoad*/, rD, am));
+          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;
+       if (tyd == Ity_F32) {
+          // XXX This won't work if offset > 1020 or is not 0 % 4.
+          // In which case we'll have to generate more longwinded code.
+          ARMAModeV* am = mkARMAModeV(hregARM_R8(), stmt->Ist.Put.offset);
+          HReg       rD = iselFltExpr(env, stmt->Ist.Put.data);
+          addInstr(env, ARMInstr_VLdStS(False/*!isLoad*/, rD, am));
+          return;
        }
-// CAB: Ity_I32, Ity_I16 ?
        break;
    }
 
+//zz   /* --------- Indexed PUT --------- */
+//zz   /* write guest state, run-time offset */
+//zz   case Ist_PutI: {
+//zz      ARMAMode2* am2
+//zz           = genGuestArrayOffset(
+//zz               env, stmt->Ist.PutI.descr, 
+//zz               stmt->Ist.PutI.ix, stmt->Ist.PutI.bias );
+//zz       
+//zz       IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.PutI.data);
+//zz       
+//zz       if (tyd == Ity_I8) {
+//zz           HReg reg = iselIntExpr_R(env, stmt->Ist.PutI.data);
+//zz           addInstr(env, ARMInstr_StoreB(reg, am2));
+//zz           return;
+//zz       }
+//zz// CAB: Ity_I32, Ity_I16 ?
+//zz       break;
+//zz   }
+
    /* --------- TMP --------- */
    /* assign value to temporary */
    case Ist_WrTmp: {
@@ -832,23 +2260,48 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
       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);
+         ARMRI84* ri84 = iselIntExpr_RI84(NULL, False,
+                                          env, stmt->Ist.WrTmp.data);
+         HReg     dst  = lookupIRTemp(env, tmp);
+         addInstr(env, ARMInstr_Mov(dst,ri84));
+         return;
+      }
+      if (ty == Ity_I1) {
+         HReg        dst  = lookupIRTemp(env, tmp);
+         ARMCondCode cond = iselCondCode(env, stmt->Ist.WrTmp.data);
+         addInstr(env, ARMInstr_Mov(dst, ARMRI84_I84(0,0)));
+         addInstr(env, ARMInstr_CMov(cond, dst, ARMRI84_I84(1,0)));
+         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_F64) {
+         HReg src = iselDblExpr(env, stmt->Ist.WrTmp.data);
          HReg dst = lookupIRTemp(env, tmp);
-         addInstr(env, ARMInstr_DPInstr1(ARMalu_MOV,dst,am));
+         addInstr(env, ARMInstr_VUnaryD(ARMvfpu_COPY, dst, src));
+         return;
+      }
+      if (ty == Ity_F32) {
+         HReg src = iselFltExpr(env, stmt->Ist.WrTmp.data);
+         HReg dst = lookupIRTemp(env, tmp);
+         addInstr(env, ARMInstr_VUnaryS(ARMvfpu_COPY, dst, src));
          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;
+      IRType   retty;
+      IRDirty* d = stmt->Ist.Dirty.details;
+      Bool     passBBP = False;
 
       if (d->nFxState == 0)
          vassert(!d->needsBBP);
@@ -856,43 +2309,110 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
       passBBP = toBool(d->nFxState > 0 && d->needsBBP);
 
       /* Marshal args, do the call, clear stack. */
-      doHelperCall( env, passBBP, d->guard, d->cee, d->args );
+      Bool ok = doHelperCall( env, passBBP, d->guard, d->cee, d->args );
+      if (!ok)
+         break; /* will go to stmt_fail: */
 
       /* 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);
+         /* No return value.  Nothing to do. */
+         return;
 
-// CAB: ?     if (retty == Ity_I64) {
+      retty = typeOfIRTemp(env->type_env, d->tmp);
 
-#if 0
+      if (retty == Ity_I64) {
+         HReg dstHi, dstLo;
+         /* The returned value is in r1:r0.  Park it in the
+            register-pair associated with tmp. */
+         lookupIRTemp64( &dstHi, &dstLo, env, d->tmp);
+         addInstr(env, mk_iMOVds_RR(dstHi, hregARM_R1()) );
+         addInstr(env, mk_iMOVds_RR(dstLo, hregARM_R0()) );
+         return;
+      }
       if (retty == Ity_I32 || retty == Ity_I16 || retty == Ity_I8) {
-         /* The returned value is in %eax.  Park it in the register
+         /* The returned value is in r0.  Park it in the register
             associated with tmp. */
          HReg dst = lookupIRTemp(env, d->tmp);
-         addInstr(env, mk_iMOVsd_RR(hregX86_EAX(),dst) );
+         addInstr(env, mk_iMOVds_RR(dst, hregARM_R0()) );
          return;
       }
-#endif
+
+      break;
+   }
+
+   /* --------- Load Linked and Store Conditional --------- */
+   case Ist_LLSC: {
+      if (stmt->Ist.LLSC.storedata == NULL) {
+         /* LL */
+         IRTemp res = stmt->Ist.LLSC.result;
+         IRType ty  = typeOfIRTemp(env->type_env, res);
+         if (ty == Ity_I32 || ty == Ity_I8) {
+            Int  szB   = 0;
+            HReg r_dst = lookupIRTemp(env, res);
+            HReg raddr = iselIntExpr_R(env, stmt->Ist.LLSC.addr);
+            switch (ty) {
+               case Ity_I8:  szB = 1; break;
+               case Ity_I32: szB = 4; break;
+               default:      vassert(0);
+            }
+            addInstr(env, mk_iMOVds_RR(hregARM_R1(), raddr));
+            addInstr(env, ARMInstr_LdrEX(szB));
+            addInstr(env, mk_iMOVds_RR(r_dst, hregARM_R0()));
+            return;
+         }
+         /* else fall thru; is unhandled */
+      } else {
+         /* SC */
+         IRTemp res = stmt->Ist.LLSC.result;
+         IRType ty  = typeOfIRTemp(env->type_env, res);
+         IRType tyd = typeOfIRExpr(env->type_env, stmt->Ist.LLSC.storedata);
+         vassert(ty == Ity_I1);
+         if (tyd == Ity_I32 || tyd == Ity_I8) {
+            Int  szB     = 0;
+            HReg r_res   = lookupIRTemp(env, res);
+            HReg rD      = iselIntExpr_R(env, stmt->Ist.LLSC.storedata);
+            HReg rA      = iselIntExpr_R(env, stmt->Ist.LLSC.addr);
+            ARMRI84* one = ARMRI84_I84(1,0);
+            switch (tyd) {
+               case Ity_I8:  szB = 1; break;
+               case Ity_I32: szB = 4; break;
+               default:      vassert(0);
+            }
+            addInstr(env, mk_iMOVds_RR(hregARM_R1(), rD));
+            addInstr(env, mk_iMOVds_RR(hregARM_R2(), rA));
+            addInstr(env, ARMInstr_StrEX(szB));
+            /* now r0 is 1 if failed, 0 if success.  Change to IR
+               conventions (0 is fail, 1 is success).  Also transfer
+               result to r_res. */
+            addInstr(env, ARMInstr_Alu(ARMalu_XOR, r_res, hregARM_R0(), one));
+            /* And be conservative -- mask off all but the lowest bit */
+            addInstr(env, ARMInstr_Alu(ARMalu_AND, r_res, r_res, one));
+            return;
+         }
+         /* else fall thru; is unhandled */
+      }
       break;
    }
 
+   /* --------- INSTR MARK --------- */
+   /* Doesn't generate any executable code ... */
+   case Ist_IMark:
+       return;
+
+   /* --------- NO-OP --------- */
+   case Ist_NoOp:
+       return;
+
    /* --------- EXIT --------- */
-   /* conditional exit from BB */
    case Ist_Exit: {
-      ARMBranchDest* dst;
+      HReg        gnext;
       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));
+      gnext = iselIntExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
+      cc    = iselCondCode(env, stmt->Ist.Exit.guard);
+      addInstr(env, mk_iMOVds_RR(hregARM_R14(), env->savedLR));
+      addInstr(env, ARMInstr_Goto(stmt->Ist.Exit.jk, cc, gnext));
       return;
    }
 
@@ -910,19 +2430,17 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
 
 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) );
+   HReg rDst;
+   if (vex_traceflags & VEX_TRACE_VCODE) {
+      vex_printf("\n-- goto {");
+      ppIRJumpKind(jk);
+      vex_printf("} ");
+      ppIRExpr(next);
+      vex_printf("\n");
+   }
+   rDst = iselIntExpr_R(env, next);
+   addInstr(env, mk_iMOVds_RR(hregARM_R14(), env->savedLR));
+   addInstr(env, ARMInstr_Goto(jk, ARMcc_AL, rDst));
 }
 
 
@@ -932,46 +2450,74 @@ static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
 
 /* Translate an entire SB to arm code. */
 
-HInstrArray* iselSB_ARM ( IRSB* bb )
+HInstrArray* iselSB_ARM ( IRSB* bb, VexArch      arch_host,
+                                    VexArchInfo* archinfo_host,
+                                    VexAbiInfo*  vbi/*UNUSED*/ )
 {
-    Int     i, j;
+   Int      i, j;
+   HReg     hreg, hregHI;
+   ISelEnv* env;
+   UInt     hwcaps_host = archinfo_host->hwcaps;
 
-    /* Make up an initial environment to use. */
-    ISelEnv* env = LibVEX_Alloc(sizeof(ISelEnv));
-    env->vreg_ctr = 0;
+   /* sanity ... */
+   vassert(arch_host == VexArchARM);
+   vassert(0 == hwcaps_host);
 
-    /* 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]);
+   /* Make up an initial environment to use. */
+   env = LibVEX_Alloc(sizeof(ISelEnv));
+   env->vreg_ctr = 0;
+
+   /* Set up output code array. */
+   env->code = newHInstrArray();
     
-    iselNext(env,bb->next,bb->jumpkind);
+   /* 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));
+
+   /* 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:  hregHI = mkHReg(j++, HRcInt32, True);
+                        hreg   = mkHReg(j++, HRcInt32, True); break;
+         case Ity_F32:  hreg   = mkHReg(j++, HRcFlt32, True); break;
+         case Ity_F64:  hreg   = mkHReg(j++, HRcFlt64, True); break;
+         //case Ity_V128: hreg   = mkHReg(j++, HRcVec128, True); break;
+         default: ppIRType(bb->tyenv->types[i]);
+                  vpanic("iselBB: IRTemp type");
+      }
+      env->vregmap[i]   = hreg;
+      env->vregmapHI[i] = hregHI;
+   }
+   env->vreg_ctr = j;
 
-    /* record the number of vregs we used. */
-    env->code->n_vregs = env->vreg_ctr;
-    return env->code;
-}
+   /* Keep a copy of the link reg, since any call to a helper function
+      will trash it, and we can't get back to the dispatcher once that
+      happens. */
+   env->savedLR = newVRegI(env);
+   addInstr(env, mk_iMOVds_RR(env->savedLR, hregARM_R14()));
 
+   /* 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);
 
+   /* record the number of vregs we used. */
+   env->code->n_vregs = env->vreg_ctr;
+   return env->code;
+}
 
 
 /*---------------------------------------------------------------*/
index fc420aa1d53e31d898eaa80f2af30e423420eba9..ca08816aa4a4ec69a048f45b85eda7308fcaf69a 100644 (file)
@@ -334,13 +334,15 @@ HInstrArray* doRegisterAllocation (
    /* Apply a reg-reg mapping to an insn. */
    void (*mapRegs) ( HRegRemap*, HInstr*, Bool ),
 
-   /* Return an insn to spill/restore a real reg to a spill slot byte
-      offset.  Also (optionally) a 'directReload' function, which
+   /* Return one, or, if we're unlucky, two insn(s) to spill/restore a
+      real reg to a spill slot byte offset.  The two leading HInstr**
+      args are out parameters, through which the generated insns are
+      returned.  Also (optionally) a 'directReload' function, which
       attempts to replace a given instruction by one which reads
       directly from a specified spill slot.  May be NULL, in which
       case the optimisation is not attempted. */
-   HInstr* (*genSpill) ( HReg, Int, Bool ),
-   HInstr* (*genReload) ( HReg, Int, Bool ),
+   void    (*genSpill)  ( HInstr**, HInstr**, HReg, Int, Bool ),
+   void    (*genReload) ( HInstr**, HInstr**, HReg, Int, Bool ),
    HInstr* (*directReload) ( HInstr*, HReg, Short ),
    Int     guest_sizeB,
 
@@ -830,7 +832,7 @@ HInstrArray* doRegisterAllocation (
       }
 
       /* The spill slots are 64 bits in size.  As per the comment on
-         definition of HRegClass in h_generic_regs.h, that means, to
+         definition of HRegClass in host_generic_regs.h, that means, to
          spill a vreg of class Flt64 or Vec128, we'll need to find two
          adjacent spill slots to use.  Note, this logic needs to kept
          in sync with the size info on the definition of HRegClass. */
@@ -1157,9 +1159,15 @@ HInstrArray* doRegisterAllocation (
             if (vreg_lrs[m].dead_before > ii) {
                vassert(vreg_lrs[m].reg_class != HRcINVALID);
                if ((!eq_spill_opt) || !rreg_state[k].eq_spill_slot) {
-                  EMIT_INSTR( (*genSpill)( rreg_state[k].rreg,
-                                           vreg_lrs[m].spill_offset,
-                                           mode64 ) );
+                  HInstr* spill1 = NULL;
+                  HInstr* spill2 = NULL;
+                  (*genSpill)( &spill1, &spill2, rreg_state[k].rreg,
+                               vreg_lrs[m].spill_offset, mode64 );
+                  vassert(spill1 || spill2); /* can't both be NULL */
+                  if (spill1)
+                     EMIT_INSTR(spill1);
+                  if (spill2)
+                     EMIT_INSTR(spill2);
                }
                rreg_state[k].eq_spill_slot = True;
             }
@@ -1199,7 +1207,7 @@ HInstrArray* doRegisterAllocation (
          in a spill slot, and this is last use of that vreg, see if we
          can convert the instruction into one reads directly from the
          spill slot.  This is clearly only possible for x86 and amd64
-         targets, since ppc is a load-store architecture.  If
+         targets, since ppc and arm load-store architectures.  If
          successful, replace instrs_in->arr[ii] with this new
          instruction, and recompute its reg usage, so that the change
          is invisible to the standard-case handling that follows. */
@@ -1332,9 +1340,15 @@ HInstrArray* doRegisterAllocation (
                indeed needed. */
             if (reg_usage.mode[j] != HRmWrite) {
                vassert(vreg_lrs[m].reg_class != HRcINVALID);
-               EMIT_INSTR( (*genReload)( rreg_state[k].rreg,
-                                         vreg_lrs[m].spill_offset,
-                                         mode64 ) );
+               HInstr* reload1 = NULL;
+               HInstr* reload2 = NULL;
+               (*genReload)( &reload1, &reload2, rreg_state[k].rreg,
+                             vreg_lrs[m].spill_offset, mode64 );
+               vassert(reload1 || reload2); /* can't both be NULL */
+               if (reload1)
+                  EMIT_INSTR(reload1);
+               if (reload2)
+                  EMIT_INSTR(reload2);
                /* This rreg is read or modified by the instruction.
                   If it's merely read we can claim it now equals the
                   spill slot, but not so if it is modified. */
@@ -1409,9 +1423,15 @@ HInstrArray* doRegisterAllocation (
          vassert(vreg_lrs[m].dead_before > ii);
          vassert(vreg_lrs[m].reg_class != HRcINVALID);
          if ((!eq_spill_opt) || !rreg_state[spillee].eq_spill_slot) {
-            EMIT_INSTR( (*genSpill)( rreg_state[spillee].rreg,
-                                     vreg_lrs[m].spill_offset,
-                                     mode64 ) );
+            HInstr* spill1 = NULL;
+            HInstr* spill2 = NULL;
+            (*genSpill)( &spill1, &spill2, rreg_state[spillee].rreg,
+                         vreg_lrs[m].spill_offset, mode64 );
+            vassert(spill1 || spill2); /* can't both be NULL */
+            if (spill1)
+               EMIT_INSTR(spill1);
+            if (spill2)
+               EMIT_INSTR(spill2);
          }
 
          /* Update the rreg_state to reflect the new assignment for this
@@ -1429,9 +1449,15 @@ HInstrArray* doRegisterAllocation (
             written), we have to generate a reload for it. */
          if (reg_usage.mode[j] != HRmWrite) {
             vassert(vreg_lrs[m].reg_class != HRcINVALID);
-            EMIT_INSTR( (*genReload)( rreg_state[spillee].rreg,
-                                      vreg_lrs[m].spill_offset,
-                                      mode64 ) );
+            HInstr* reload1 = NULL;
+            HInstr* reload2 = NULL;
+            (*genReload)( &reload1, &reload2, rreg_state[spillee].rreg,
+                          vreg_lrs[m].spill_offset, mode64 );
+            vassert(reload1 || reload2); /* can't both be NULL */
+            if (reload1)
+               EMIT_INSTR(reload1);
+            if (reload2)
+               EMIT_INSTR(reload2);
             /* This rreg is read or modified by the instruction.
                If it's merely read we can claim it now equals the
                spill slot, but not so if it is modified. */
index f38746b874f5fe0107e80c9c6c48cc3286c3797f..20fade144c26b927aaa32aecef744eece39102ba 100644 (file)
@@ -56,6 +56,7 @@ void ppHRegClass ( HRegClass hrc )
    switch (hrc) {
       case HRcInt32:   vex_printf("HRcInt32"); break;
       case HRcInt64:   vex_printf("HRcInt64"); break;
+      case HRcFlt32:   vex_printf("HRcFlt32"); break;
       case HRcFlt64:   vex_printf("HRcFlt64"); break;
       case HRcVec64:   vex_printf("HRcVec64"); break;
       case HRcVec128:  vex_printf("HRcVec128"); break;
@@ -71,7 +72,8 @@ void ppHReg ( HReg r )
    switch (hregClass(r)) {
       case HRcInt32:   vex_printf("%%%sr%d", maybe_v, regNo); return;
       case HRcInt64:   vex_printf("%%%sR%d", maybe_v, regNo); return;
-      case HRcFlt64:   vex_printf("%%%sF%d", maybe_v, regNo); return;
+      case HRcFlt32:   vex_printf("%%%sF%d", maybe_v, regNo); return;
+      case HRcFlt64:   vex_printf("%%%sD%d", maybe_v, regNo); return;
       case HRcVec64:   vex_printf("%%%sv%d", maybe_v, regNo); return;
       case HRcVec128:  vex_printf("%%%sV%d", maybe_v, regNo); return;
       default: vpanic("ppHReg");
index 845f7f0a4a7b2de340b95e422215ce29d3b3baff..24b93517f6012a9e5c7fcc7728733fcc40603b40 100644 (file)
@@ -74,9 +74,9 @@
    Note further that since the class field is never 1111b, no valid
    register can have the value INVALID_HREG.
 
-   There are currently 5 register classes:
+   There are currently 6 register classes:
 
-     int32 int64 float64 simd64 simd128
+     int32 int64 float32 float64 simd64 simd128
 */
 
 typedef UInt HReg;
@@ -87,23 +87,27 @@ typedef UInt HReg;
    available on any specific host.  For example on x86, the available
    classes are: Int32, Flt64, Vec128 only.
 
-   IMPORTANT NOTE: reg_alloc2.c needs how much space is needed to spill
-   each class of register.  It has the following knowledge hardwired in:
+   IMPORTANT NOTE: host_generic_reg_alloc2.c needs how much space is
+   needed to spill each class of register.  It allocates the following
+   amount of space:
 
-      HRcInt32     32 bits
+      HRcInt32     64 bits
       HRcInt64     64 bits
-      HRcFlt64     80 bits (on x86 these are spilled by fstpt/fldt)
+      HRcFlt32     64 bits
+      HRcFlt64     128 bits (on x86 these are spilled by fstpt/fldt and
+                             so won't fit in a 64-bit slot)
       HRcVec64     64 bits
       HRcVec128    128 bits
 
    If you add another regclass, you must remember to update
-   reg_alloc2.c accordingly.
+   host_generic_reg_alloc2.c accordingly.
 */
 typedef
    enum { 
       HRcINVALID=1,   /* NOT A VALID REGISTER CLASS */
-      HRcInt32=4,     /* 32-bit int */
-      HRcInt64=5,     /* 64-bit int */
+      HRcInt32=3,     /* 32-bit int */
+      HRcInt64=4,     /* 64-bit int */
+      HRcFlt32=5,     /* 32-bit float */
       HRcFlt64=6,     /* 64-bit float */
       HRcVec64=7,     /* 64-bit SIMD */
       HRcVec128=8     /* 128-bit SIMD */
@@ -265,10 +269,10 @@ HInstrArray* doRegisterAllocation (
    /* Apply a reg-reg mapping to an insn. */
    void (*mapRegs) (HRegRemap*, HInstr*, Bool),
 
-   /* Return an insn to spill/restore a real reg to a spill slot
+   /* Return insn(s) to spill/restore a real reg to a spill slot
       offset.  And optionally a function to do direct reloads. */
-   HInstr* (*genSpill) ( HReg, Int, Bool ),
-   HInstr* (*genReload) ( HReg, Int, Bool ),
+   void    (*genSpill) (  HInstr**, HInstr**, HReg, Int, Bool ),
+   void    (*genReload) ( HInstr**, HInstr**, HReg, Int, Bool ),
    HInstr* (*directReload) ( HInstr*, HReg, Short ),
    Int     guest_sizeB,
 
index 76ddfce07326a633a81f79d97da3e2f37b340b66..dc14defb36ef380d785a786852e58a7aec52e5d8 100644 (file)
@@ -1457,7 +1457,7 @@ static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e )
          return r_ccIR;
       }
 
-      if (e->Iex.Binop.op == Iop_F64toI32) {
+      if (e->Iex.Binop.op == Iop_F64toI32S) {
          /* This works in both mode64 and mode32. */
          HReg      r1      = StackFramePtr(env->mode64);
          PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
@@ -1485,7 +1485,7 @@ static HReg iselWordExpr_R_wrk ( ISelEnv* env, IRExpr* e )
          return idst;
       }
 
-      if (e->Iex.Binop.op == Iop_F64toI64) {
+      if (e->Iex.Binop.op == Iop_F64toI64S) {
          if (mode64) {
             HReg      r1      = StackFramePtr(env->mode64);
             PPCAMode* zero_r1 = PPCAMode_IR( 0, r1 );
@@ -2732,8 +2732,8 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo,
             *rLo = iselWordExpr_R(env, e->Iex.Binop.arg2);
             return;
 
-         /* F64toI64 */
-         case Iop_F64toI64: {
+         /* F64toI64S */
+         case Iop_F64toI64S: {
             HReg      tLo     = newVRegI(env);
             HReg      tHi     = newVRegI(env);
             HReg      r1      = StackFramePtr(env->mode64);
@@ -3186,7 +3186,7 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
          return r_dst;
       }
 
-      if (e->Iex.Binop.op == Iop_I64toF64) {
+      if (e->Iex.Binop.op == Iop_I64StoF64) {
          if (mode64) {
             HReg fdst = newVRegF(env);
             HReg isrc = iselWordExpr_R(env, e->Iex.Binop.arg2);
index e50d9750918315e339784d04cf0fc6f8c1675c97..fa45db55ca8100b2996b16151767b4894ba3abe3 100644 (file)
@@ -998,8 +998,9 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
          return dst;
       }
 
-      if (e->Iex.Binop.op == Iop_F64toI32 || e->Iex.Binop.op == Iop_F64toI16) {
-         Int  sz  = e->Iex.Binop.op == Iop_F64toI16 ? 2 : 4;
+      if (e->Iex.Binop.op == Iop_F64toI32S
+          || e->Iex.Binop.op == Iop_F64toI16S) {
+         Int  sz  = e->Iex.Binop.op == Iop_F64toI16S ? 2 : 4;
          HReg rf  = iselDblExpr(env, e->Iex.Binop.arg2);
          HReg dst = newVRegI(env);
 
@@ -2260,7 +2261,7 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
          /* Sigh, this is an almost exact copy of the F64 -> I32/I16
             case.  Unfortunately I see no easy way to avoid the
             duplication. */
-         case Iop_F64toI64: {
+         case Iop_F64toI64S: {
             HReg rf  = iselDblExpr(env, e->Iex.Binop.arg2);
             HReg tLo = newVRegI(env);
             HReg tHi = newVRegI(env);
@@ -2940,7 +2941,7 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
       return dst;
    }
 
-   if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64toF64) {
+   if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_I64StoF64) {
       HReg dst = newVRegF(env);
       HReg rHi,rLo;
       iselInt64Expr( &rHi, &rLo, env, e->Iex.Binop.arg2);
@@ -3003,7 +3004,7 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
 
    if (e->tag == Iex_Unop) {
       switch (e->Iex.Unop.op) {
-         case Iop_I32toF64: {
+         case Iop_I32StoF64: {
             HReg dst = newVRegF(env);
             HReg ri  = iselIntExpr_R(env, e->Iex.Unop.arg);
             addInstr(env, X86Instr_Push(X86RMI_Reg(ri)));
index 97c4f42e8232f842f497e3fdd713b0cc9815db1d..6e5171e7d39898e80d41fbd8e17548479ceabd36 100644 (file)
@@ -257,6 +257,10 @@ void ppIROp ( IROp op )
       case Iop_SubF64r32: vex_printf("SubF64r32"); return;
       case Iop_MulF64r32: vex_printf("MulF64r32"); return;
       case Iop_DivF64r32: vex_printf("DivF64r32"); return;
+      case Iop_AddF32:    vex_printf("AddF32"); return;
+      case Iop_SubF32:    vex_printf("SubF32"); return;
+      case Iop_MulF32:    vex_printf("MulF32"); return;
+      case Iop_DivF32:    vex_printf("DivF32"); return;
 
       case Iop_ScaleF64:      vex_printf("ScaleF64"); return;
       case Iop_AtanF64:       vex_printf("AtanF64"); return;
@@ -267,9 +271,11 @@ void ppIROp ( IROp op )
       case Iop_PRem1F64:      vex_printf("PRem1F64"); return;
       case Iop_PRem1C3210F64: vex_printf("PRem1C3210F64"); return;
       case Iop_NegF64:        vex_printf("NegF64"); return;
+      case Iop_AbsF64:        vex_printf("AbsF64"); return;
+      case Iop_NegF32:        vex_printf("NegF32"); return;
+      case Iop_AbsF32:        vex_printf("AbsF32"); return;
       case Iop_SqrtF64:       vex_printf("SqrtF64"); return;
-
-      case Iop_AbsF64:    vex_printf("AbsF64"); return;
+      case Iop_SqrtF32:       vex_printf("SqrtF32"); return;
       case Iop_SinF64:    vex_printf("SinF64"); return;
       case Iop_CosF64:    vex_printf("CosF64"); return;
       case Iop_TanF64:    vex_printf("TanF64"); return;
@@ -291,13 +297,17 @@ void ppIROp ( IROp op )
 
       case Iop_CmpF64:    vex_printf("CmpF64"); return;
 
-      case Iop_F64toI16: vex_printf("F64toI16"); return;
-      case Iop_F64toI32: vex_printf("F64toI32"); return;
-      case Iop_F64toI64: vex_printf("F64toI64"); return;
+      case Iop_F64toI16S: vex_printf("F64toI16S"); return;
+      case Iop_F64toI32S: vex_printf("F64toI32S"); return;
+      case Iop_F64toI64S: vex_printf("F64toI64S"); return;
+
+      case Iop_F64toI32U: vex_printf("F64toI32U"); return;
 
-      case Iop_I16toF64: vex_printf("I16toF64"); return;
-      case Iop_I32toF64: vex_printf("I32toF64"); return;
-      case Iop_I64toF64: vex_printf("I64toF64"); return;
+      case Iop_I16StoF64: vex_printf("I16StoF64"); return;
+      case Iop_I32StoF64: vex_printf("I32StoF64"); return;
+      case Iop_I64StoF64: vex_printf("I64StoF64"); return;
+
+      case Iop_I32UtoF64: vex_printf("I32UtoF64"); return;
 
       case Iop_F32toF64: vex_printf("F32toF64"); return;
       case Iop_F64toF32: vex_printf("F64toF32"); return;
@@ -1780,23 +1790,37 @@ void typeOfPrimop ( IROp op,
       case Iop_MulF64r32: case Iop_DivF64r32:
          TERNARY(ity_RMode,Ity_F64,Ity_F64, Ity_F64);
 
+      case Iop_AddF32: case Iop_SubF32:
+      case Iop_MulF32: case Iop_DivF32:
+         TERNARY(ity_RMode,Ity_F32,Ity_F32, Ity_F32);
+
       case Iop_NegF64: case Iop_AbsF64: 
          UNARY(Ity_F64, Ity_F64);
 
+      case Iop_NegF32: case Iop_AbsF32:
+         UNARY(Ity_F32, Ity_F32);
+
       case Iop_SqrtF64:
       case Iop_SqrtF64r32:
          BINARY(ity_RMode,Ity_F64, Ity_F64);
 
+      case Iop_SqrtF32:
+         BINARY(ity_RMode,Ity_F32, Ity_F32);
+
       case Iop_CmpF64:
          BINARY(Ity_F64,Ity_F64, Ity_I32);
 
-      case Iop_F64toI16: BINARY(ity_RMode,Ity_F64, Ity_I16);
-      case Iop_F64toI32: BINARY(ity_RMode,Ity_F64, Ity_I32);
-      case Iop_F64toI64: BINARY(ity_RMode,Ity_F64, Ity_I64);
+      case Iop_F64toI16S: BINARY(ity_RMode,Ity_F64, Ity_I16);
+      case Iop_F64toI32S: BINARY(ity_RMode,Ity_F64, Ity_I32);
+      case Iop_F64toI64S: BINARY(ity_RMode,Ity_F64, Ity_I64);
+
+      case Iop_F64toI32U: BINARY(ity_RMode,Ity_F64, Ity_I32);
+
+      case Iop_I16StoF64: UNARY(Ity_I16, Ity_F64);
+      case Iop_I32StoF64: UNARY(Ity_I32, Ity_F64);
+      case Iop_I64StoF64: BINARY(ity_RMode,Ity_I64, Ity_F64);
 
-      case Iop_I16toF64: UNARY(Ity_I16, Ity_F64);
-      case Iop_I32toF64: UNARY(Ity_I32, Ity_F64);
-      case Iop_I64toF64: BINARY(ity_RMode,Ity_I64, Ity_F64);
+      case Iop_I32UtoF64: UNARY(Ity_I32, Ity_F64);
 
       case Iop_F32toF64: UNARY(Ity_F32, Ity_F64);
       case Iop_F64toF32: BINARY(ity_RMode,Ity_F64, Ity_F32);
@@ -2697,15 +2721,16 @@ void tcStmt ( IRSB* bb, IRStmt* stmt, IRType gWordTy )
          tyRes = typeOfIRTemp(tyenv, stmt->Ist.LLSC.result);
          if (stmt->Ist.LLSC.storedata == NULL) {
             /* it's a LL */
-            if (tyRes != Ity_I64 && tyRes != Ity_I32)
+            if (tyRes != Ity_I64 && tyRes != Ity_I32 && tyRes != Ity_I8)
                sanityCheckFail(bb,stmt,"Ist.LLSC(LL).result :: bogus");
          } else {
             /* it's a SC */
             if (tyRes != Ity_I1)
                sanityCheckFail(bb,stmt,"Ist.LLSC(SC).result: not :: Ity_I1");
             tyData = typeOfIRExpr(tyenv, stmt->Ist.LLSC.storedata);
-            if (tyData != Ity_I64 && tyData != Ity_I32)
-               sanityCheckFail(bb,stmt,"Ist.LLSC(SC).result :: storedata bogus");
+            if (tyData != Ity_I64 && tyData != Ity_I32 && tyData != Ity_I8)
+               sanityCheckFail(bb,stmt,
+                               "Ist.LLSC(SC).result :: storedata bogus");
          }
          break;
       }
index 40f2466bbad9f34767281e2d63c904a70d741340..bc8ae935b51e525cbbdf47d0fbd1cd3fb9d374e0 100644 (file)
@@ -904,6 +904,30 @@ static Bool sameIRTemps ( IRExpr* e1, IRExpr* e2 )
                   && e1->Iex.RdTmp.tmp == e2->Iex.RdTmp.tmp );
 }
 
+static Bool sameIcoU32s ( IRExpr* e1, IRExpr* e2 )
+{
+   return toBool( e1->tag == Iex_Const
+                  && e2->tag == Iex_Const
+                  && e1->Iex.Const.con->tag == Ico_U32
+                  && e2->Iex.Const.con->tag == Ico_U32
+                  && e1->Iex.Const.con->Ico.U32
+                     == e2->Iex.Const.con->Ico.U32 );
+}
+
+/* Are both expressions either the same IRTemp or IRConst-U32s ?  If
+   in doubt, say No. */
+static Bool sameIRTempsOrIcoU32s ( IRExpr* e1, IRExpr* e2 )
+{
+   switch (e1->tag) {
+      case Iex_RdTmp:
+         return sameIRTemps(e1, e2);
+      case Iex_Const:
+         return sameIcoU32s(e1, e2);
+      default:
+         return False;
+   }
+}
+
 static Bool notBool ( Bool b )
 {
    if (b == True) return False;
@@ -1578,14 +1602,22 @@ static IRExpr* fold_Expr ( IRExpr* e )
    }
 
    /* Mux0X */
-   if (e->tag == Iex_Mux0X
-       && e->Iex.Mux0X.cond->tag == Iex_Const) {
-      Bool zero;
-      /* assured us by the IR type rules */
-      vassert(e->Iex.Mux0X.cond->Iex.Const.con->tag == Ico_U8);
-      zero = toBool(0 == (0xFF & e->Iex.Mux0X.cond
-                                  ->Iex.Const.con->Ico.U8));
-      e2 = zero ? e->Iex.Mux0X.expr0 : e->Iex.Mux0X.exprX;
+   if (e->tag == Iex_Mux0X) {
+      /* is the discriminant is a constant? */
+      if (e->Iex.Mux0X.cond->tag == Iex_Const) {
+         Bool zero;
+         /* assured us by the IR type rules */
+         vassert(e->Iex.Mux0X.cond->Iex.Const.con->tag == Ico_U8);
+         zero = toBool(0 == (0xFF & e->Iex.Mux0X.cond
+                                     ->Iex.Const.con->Ico.U8));
+         e2 = zero ? e->Iex.Mux0X.expr0 : e->Iex.Mux0X.exprX;
+      }
+      else
+      /* are the arms identical? (pretty weedy test) */
+      if (sameIRTempsOrIcoU32s(e->Iex.Mux0X.expr0,
+                               e->Iex.Mux0X.exprX)) {
+         e2 = e->Iex.Mux0X.expr0;
+      }
    }
 
    if (DEBUG_IROPT && e2 != e) {
@@ -3938,6 +3970,20 @@ static IRExpr* fold_IRExpr_Unop ( IROp op, IRExpr* aa )
       if (is_Unop(aa, Iop_CmpwNEZ64))
          return IRExpr_Unop( Iop_CmpNEZ64, aa->Iex.Unop.arg );
       break;
+
+   case Iop_1Sto32:
+      /* 1Sto32( CmpNEZ8( 32to8( 1Uto32( CmpNEZ32( x ))))) -> CmpwNEZ32(x) */
+      if (is_Unop(aa, Iop_CmpNEZ8)
+          && is_Unop(aa->Iex.Unop.arg, Iop_32to8)
+          && is_Unop(aa->Iex.Unop.arg->Iex.Unop.arg, Iop_1Uto32)
+          && is_Unop(aa->Iex.Unop.arg->Iex.Unop.arg->Iex.Unop.arg,
+                     Iop_CmpNEZ32)) {
+         return IRExpr_Unop( Iop_CmpwNEZ32,
+                             aa->Iex.Unop.arg->Iex.Unop.arg
+                               ->Iex.Unop.arg->Iex.Unop.arg);
+      }
+      break;
+
    default:
       break;
    }
index e14f4cc8765739af5b1d5b4baf1accb89adb382a..5eddba483536366c9ea309cdafc409d45337a1dc 100644 (file)
@@ -60,6 +60,7 @@
 #include "host_x86_defs.h"
 #include "host_amd64_defs.h"
 #include "host_ppc_defs.h"
+#include "host_arm_defs.h"
 
 #include "guest_generic_bb_to_IR.h"
 #include "guest_x86_defs.h"
@@ -179,8 +180,8 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta )
    Bool         (*isMove)       ( HInstr*, HReg*, HReg* );
    void         (*getRegUsage)  ( HRegUsage*, HInstr*, Bool );
    void         (*mapRegs)      ( HRegRemap*, HInstr*, Bool );
-   HInstr*      (*genSpill)     ( HReg, Int, Bool );
-   HInstr*      (*genReload)    ( HReg, Int, Bool );
+   void         (*genSpill)     ( HInstr**, HInstr**, HReg, Int, Bool );
+   void         (*genReload)    ( HInstr**, HInstr**, HReg, Int, Bool );
    HInstr*      (*directReload) ( HInstr*, HReg, Short );
    void         (*ppInstr)      ( HInstr*, Bool );
    void         (*ppReg)        ( HReg );
@@ -314,8 +315,27 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta )
          vassert(vta->dispatch == NULL); /* return-to-dispatcher scheme */
          break;
 
+      case VexArchARM:
+         mode64       = False;
+         getAllocableRegs_ARM ( &n_available_real_regs,
+                                &available_real_regs );
+         isMove       = (Bool(*)(HInstr*,HReg*,HReg*)) isMove_ARMInstr;
+         getRegUsage  = (void(*)(HRegUsage*,HInstr*, Bool)) getRegUsage_ARMInstr;
+         mapRegs      = (void(*)(HRegRemap*,HInstr*, Bool)) mapRegs_ARMInstr;
+         genSpill     = (HInstr*(*)(HReg,Int, Bool)) genSpill_ARM;
+         genReload    = (HInstr*(*)(HReg,Int, Bool)) genReload_ARM;
+         ppInstr      = (void(*)(HInstr*, Bool)) ppARMInstr;
+         ppReg        = (void(*)(HReg)) ppHRegARM;
+         iselSB       = iselSB_ARM;
+         emit         = (Int(*)(UChar*,Int,HInstr*,Bool,void*)) emit_ARMInstr;
+         host_is_bigendian = False;
+         host_word_type    = Ity_I32;
+         vassert(are_valid_hwcaps(VexArchARM, vta->archinfo_host.hwcaps));
+         vassert(vta->dispatch == NULL); /* return-to-dispatcher scheme */
+         break;
+
       default:
-         vpanic("LibVEX_Translate: unsupported target insn set");
+         vpanic("LibVEX_Translate: unsupported host insn set");
    }
 
 
@@ -331,7 +351,7 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta )
          offB_TISTART     = offsetof(VexGuestX86State,guest_TISTART);
          offB_TILEN       = offsetof(VexGuestX86State,guest_TILEN);
          vassert(are_valid_hwcaps(VexArchX86, vta->archinfo_guest.hwcaps));
-         vassert(0 == sizeof(VexGuestX86State) % 8);
+         vassert(0 == sizeof(VexGuestX86State) % 16);
          vassert(sizeof( ((VexGuestX86State*)0)->guest_TISTART) == 4);
          vassert(sizeof( ((VexGuestX86State*)0)->guest_TILEN  ) == 4);
          vassert(sizeof( ((VexGuestX86State*)0)->guest_NRADDR ) == 4);
@@ -347,24 +367,12 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta )
          offB_TISTART     = offsetof(VexGuestAMD64State,guest_TISTART);
          offB_TILEN       = offsetof(VexGuestAMD64State,guest_TILEN);
          vassert(are_valid_hwcaps(VexArchAMD64, vta->archinfo_guest.hwcaps));
-         vassert(0 == sizeof(VexGuestAMD64State) % 8);
+         vassert(0 == sizeof(VexGuestAMD64State) % 16);
          vassert(sizeof( ((VexGuestAMD64State*)0)->guest_TISTART ) == 8);
          vassert(sizeof( ((VexGuestAMD64State*)0)->guest_TILEN   ) == 8);
          vassert(sizeof( ((VexGuestAMD64State*)0)->guest_NRADDR  ) == 8);
          break;
 
-      case VexArchARM:
-         preciseMemExnsFn = guest_arm_state_requires_precise_mem_exns;
-         disInstrFn       = NULL; /* HACK */
-         specHelper       = guest_arm_spechelper;
-         guest_sizeB      = sizeof(VexGuestARMState);
-         guest_word_type  = Ity_I32;
-         guest_layout     = &armGuest_layout;
-         offB_TISTART     = 0; /* hack ... arm has bitrot */
-         offB_TILEN       = 0; /* hack ... arm has bitrot */
-         vassert(are_valid_hwcaps(VexArchARM, vta->archinfo_guest.hwcaps));
-         break;
-
       case VexArchPPC32:
          preciseMemExnsFn = guest_ppc32_state_requires_precise_mem_exns;
          disInstrFn       = disInstr_PPC;
@@ -375,7 +383,7 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta )
          offB_TISTART     = offsetof(VexGuestPPC32State,guest_TISTART);
          offB_TILEN       = offsetof(VexGuestPPC32State,guest_TILEN);
          vassert(are_valid_hwcaps(VexArchPPC32, vta->archinfo_guest.hwcaps));
-         vassert(0 == sizeof(VexGuestPPC32State) % 8);
+         vassert(0 == sizeof(VexGuestPPC32State) % 16);
          vassert(sizeof( ((VexGuestPPC32State*)0)->guest_TISTART ) == 4);
          vassert(sizeof( ((VexGuestPPC32State*)0)->guest_TILEN   ) == 4);
          vassert(sizeof( ((VexGuestPPC32State*)0)->guest_NRADDR  ) == 4);
@@ -398,6 +406,22 @@ VexTranslateResult LibVEX_Translate ( VexTranslateArgs* vta )
          vassert(sizeof( ((VexGuestPPC64State*)0)->guest_NRADDR_GPR2) == 8);
          break;
 
+      case VexArchARM:
+         preciseMemExnsFn = guest_arm_state_requires_precise_mem_exns;
+         disInstrFn       = disInstr_ARM;
+         specHelper       = guest_arm_spechelper;
+         guest_sizeB      = sizeof(VexGuestARMState);
+         guest_word_type  = Ity_I32;
+         guest_layout     = &armGuest_layout;
+         offB_TISTART     = offsetof(VexGuestARMState,guest_TISTART);
+         offB_TILEN       = offsetof(VexGuestARMState,guest_TILEN);
+         vassert(are_valid_hwcaps(VexArchARM, vta->archinfo_guest.hwcaps));
+         vassert(0 == sizeof(VexGuestARMState) % 16);
+         vassert(sizeof( ((VexGuestARMState*)0)->guest_TISTART) == 4);
+         vassert(sizeof( ((VexGuestARMState*)0)->guest_TILEN  ) == 4);
+         vassert(sizeof( ((VexGuestARMState*)0)->guest_NRADDR ) == 4);
+         break;
+
       default:
          vpanic("LibVEX_Translate: unsupported guest insn set");
    }
index 1848700b2506d112dc6d415315647c897a8c850e..dcc45916f1b49826bcb28cbff3be6734863b2add 100644 (file)
@@ -144,6 +144,8 @@ typedef  unsigned long HWord;
 #   define VEX_HOST_WORDSIZE 8
 #elif defined(__powerpc__) && !defined(__powerpc64__)
 #   define VEX_HOST_WORDSIZE 4
+#elif defined(__arm__)
+#   define VEX_HOST_WORDSIZE 4
 
 #elif defined(_AIX) && !defined(__64BIT__)
 #   define VEX_HOST_WORDSIZE 4
index 885f8be919a95de9dba028be3201e0b3e794fa44..1f8532c5f1f9b556c2b37b82dce7c98fa7655831 100644 (file)
    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.
 */
 
 #ifndef __LIBVEX_PUB_GUEST_ARM_H
 /*--- Vex's representation of the ARM CPU state.              ---*/
 /*---------------------------------------------------------------*/
 
-/* R13 traditionally used as the stack pointer ? */
-
 typedef
    struct {
-      UInt  guest_R0;
-      UInt  guest_R1;
-      UInt  guest_R2;
-      UInt  guest_R3;
-      UInt  guest_R4;
-      UInt  guest_R5;
-      UInt  guest_R6;
-      UInt  guest_R7;
-      UInt  guest_R8;
-      UInt  guest_R9;
-      UInt  guest_R10;
-      UInt  guest_R11;
-      UInt  guest_R12;
-
-      /* aka the stack pointer */
-      UInt  guest_R13;
-
-      /* aka the link register */
-      UInt  guest_R14; 
-
-      /* Program counter. */
-      UInt  guest_R15;
-
-      /* System call number copied in here from swi insn literal
-         field. */
-      UInt  guest_SYSCALLNO;
-
-      /* 3-word thunk used to calculate N(sign) Z(zero) C(carry,
+      /* 0 */
+      UInt guest_R0;
+      UInt guest_R1;
+      UInt guest_R2;
+      UInt guest_R3;
+      UInt guest_R4;
+      UInt guest_R5;
+      UInt guest_R6;
+      UInt guest_R7;
+      UInt guest_R8;
+      UInt guest_R9;
+      UInt guest_R10;
+      UInt guest_R11;
+      UInt guest_R12;
+      UInt guest_R13;     /* stack pointer */
+      UInt guest_R14;     /* link register */
+      UInt guest_R15;     /* program counter */
+
+      /* 4-word thunk used to calculate N(sign) Z(zero) C(carry,
          unsigned overflow) and V(signed overflow) flags. */
-      UInt  guest_CC_OP;
-      UInt  guest_CC_DEP1;
-      UInt  guest_CC_DEP2;
+      /* 64 */
+      UInt guest_CC_OP;
+      UInt guest_CC_DEP1;
+      UInt guest_CC_DEP2;
+      UInt guest_CC_NDEP;
 
+      /* Various pseudo-regs mandated by Vex or Valgrind. */
       /* Emulation warnings */
-      UInt   guest_EMWARN;
-
-      /* Padding to make it have an 8-aligned size */
-      UInt   padding;
+      UInt guest_EMWARN;
+
+      /* For clflush: record start and length of area to invalidate */
+      UInt guest_TISTART;
+      UInt guest_TILEN;
+
+      /* 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. */
+      UInt guest_NRADDR;
+
+      /* Needed for Darwin (but mandated for all guest architectures):
+         program counter at the last syscall insn (int 0x80/81/82,
+         sysenter, syscall, svc).  Used when backing up to restart a
+         syscall that has been interrupted by a signal. */
+      /* 96 */
+      UInt guest_IP_AT_SYSCALL;
+
+      /* VFP state.  D0 .. D15 must be 8-aligned. */
+      /* 104 -- I guess there's 4 bytes of padding just prior to this? */
+      ULong guest_D0;
+      ULong guest_D1;
+      ULong guest_D2;
+      ULong guest_D3;
+      ULong guest_D4;
+      ULong guest_D5;
+      ULong guest_D6;
+      ULong guest_D7;
+      ULong guest_D8;
+      ULong guest_D9;
+      ULong guest_D10;
+      ULong guest_D11;
+      ULong guest_D12;
+      ULong guest_D13;
+      ULong guest_D14;
+      ULong guest_D15;
+      UInt  guest_FPSCR;
+
+      /* Not a town in Cornwall, but instead the TPIDRURO, on of the
+         Thread ID registers present in CP15 (the system control
+         coprocessor), register set "c13", register 3 (the User
+         Read-only Thread ID Register).  arm-linux apparently uses it
+         to hold the 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. */
+      UInt guest_TPIDRURO;
+
+      /* Padding to make it have an 16-aligned size */
+      /* UInt padding1; */
+      /* UInt padding2; */
    }
    VexGuestARMState;
 
@@ -115,7 +151,7 @@ void LibVEX_GuestARM_initialise ( /*OUT*/VexGuestARMState* vex_state );
 /* Calculate the ARM flag state from the saved data. */
 
 extern
-UInt LibVEX_GuestARM_get_flags ( /*IN*/VexGuestARMState* vex_state );
+UInt LibVEX_GuestARM_get_cpsr ( /*IN*/VexGuestARMState* vex_state );
 
 
 #endif /* ndef __LIBVEX_PUB_GUEST_ARM_H */
index 01ad488ae3fc00b76b44a7391d9caa08fd39a27a..e67b8caf3a6462509bfd4dd6342188d5aaefeb47 100644 (file)
@@ -531,6 +531,9 @@ typedef
       /* :: IRRoundingMode(I32) x F64 x F64 -> F64 */ 
       Iop_AddF64, Iop_SubF64, Iop_MulF64, Iop_DivF64,
 
+      /* :: IRRoundingMode(I32) x F32 x F32 -> F32 */ 
+      Iop_AddF32, Iop_SubF32, Iop_MulF32, Iop_DivF32,
+
       /* Variants of the above which produce a 64-bit result but which
          round their result to a IEEE float range first. */
       /* :: IRRoundingMode(I32) x F64 x F64 -> F64 */ 
@@ -540,10 +543,16 @@ typedef
       /* :: F64 -> F64 */
       Iop_NegF64, Iop_AbsF64,
 
+      /* :: F32 -> F32 */
+      Iop_NegF32, Iop_AbsF32,
+
       /* Unary operations, with rounding. */
       /* :: IRRoundingMode(I32) x F64 -> F64 */
       Iop_SqrtF64, Iop_SqrtF64r32,
 
+      /* :: IRRoundingMode(I32) x F32 -> F32 */
+      Iop_SqrtF32,
+
       /* Comparison, yielding GT/LT/EQ/UN(ordered), as per the following:
             0x45 Unordered
             0x01 LT
@@ -552,13 +561,15 @@ typedef
          This just happens to be the Intel encoding.  The values
          are recorded in the type IRCmpF64Result.
       */
+      /* :: F64 x F64 -> IRCmpF64Result(I32) */
       Iop_CmpF64,
 
       /* --- Int to/from FP conversions. --- */
 
-      /* For the most part, these take a first argument :: Ity_I32
-         (as IRRoundingMode) which is an indication of the rounding
-         mode to use, as per the following encoding:
+      /* For the most part, these take a first argument :: Ity_I32 (as
+         IRRoundingMode) which is an indication of the rounding mode
+         to use, as per the following encoding ("the standard
+         encoding"):
             00b  to nearest (the default)
             01b  to -infinity
             10b  to +infinity
@@ -570,25 +581,43 @@ typedef
             10b  to +infinity
             11b  to -infinity
          Any PPC -> IR front end will have to translate these PPC
-         encodings to the standard encodings.
+         encodings, as encoded in the guest state, to the standard
+         encodings, to pass to the primops.
+         For reference only, the ARM VFP encoding is:
+            00b  to nearest
+            01b  to +infinity
+            10b  to -infinity
+            11b  to zero
+         Again, this will have to be converted to the standard encoding
+         to pass to primops.
 
          If one of these conversions gets an out-of-range condition,
          or a NaN, as an argument, the result is host-defined.  On x86
-         the "integer indefinite" value 0x80..00 is produced.
-         On PPC it is either 0x80..00 or 0x7F..FF depending on the sign
-         of the argument.
+         the "integer indefinite" value 0x80..00 is produced.  On PPC
+         it is either 0x80..00 or 0x7F..FF depending on the sign of
+         the argument.
+
+         On ARMvfp, when converting to a signed integer result, the
+         overflow result is 0x80..00 for negative args and 0x7F..FF
+         for positive args.  For unsigned integer results it is
+         0x00..00 and 0xFF..FF respectively.
 
          Rounding is required whenever the destination type cannot
          represent exactly all values of the source type.
       */
-      Iop_F64toI16,  /* IRRoundingMode(I32) x F64 -> I16 */
-      Iop_F64toI32,  /* IRRoundingMode(I32) x F64 -> I32 */
-      Iop_F64toI64,  /* IRRoundingMode(I32) x F64 -> I64 */
+      Iop_F64toI16S, /* IRRoundingMode(I32) x F64 -> signed I16 */
+      Iop_F64toI32S, /* IRRoundingMode(I32) x F64 -> signed I32 */
+      Iop_F64toI64S, /* IRRoundingMode(I32) x F64 -> signed I64 */
+
+      Iop_F64toI32U, /* IRRoundingMode(I32) x F64 -> unsigned I32 */
+
+      Iop_I16StoF64, /*                       signed I16 -> F64 */
+      Iop_I32StoF64, /*                       signed I32 -> F64 */
+      Iop_I64StoF64, /* IRRoundingMode(I32) x signed I64 -> F64 */
 
-      Iop_I16toF64,  /*                       I16 -> F64 */
-      Iop_I32toF64,  /*                       I32 -> F64 */
-      Iop_I64toF64,  /* IRRoundingMode(I32) x I64 -> F64 */
+      Iop_I32UtoF64, /*                       unsigned I32 -> F64 */
 
+      /* Conversion between floating point formats */
       Iop_F32toF64,  /*                       F32 -> F64 */
       Iop_F64toF32,  /* IRRoundingMode(I32) x F64 -> F32 */
 
@@ -1233,7 +1262,7 @@ typedef
       Ijk_SigBUS,         /* current instruction synths SIGBUS */
       /* Unfortunately, various guest-dependent syscall kinds.  They
         all mean: do a syscall before continuing. */
-      Ijk_Sys_syscall,    /* amd64 'syscall', ppc 'sc' */
+      Ijk_Sys_syscall,    /* amd64 'syscall', ppc 'sc', arm 'svc #0' */
       Ijk_Sys_int32,      /* amd64/x86 'int $0x20' */
       Ijk_Sys_int128,     /* amd64/x86 'int $0x80' */
       Ijk_Sys_int129,     /* amd64/x86 'int $0x81' */