Fix problems due to generating Neon instructions on non-Neon capable
hosts:

* iselNeon64Expr, iselNeonExpr: assert that the host is actually
  Neon-capable.

* iselIntExpr_R_wrk, existing cases for Iop_GetElem8x8,
  Iop_GetElem16x4, Iop_GetElem32x2, Iop_GetElem8x16, Iop_GetElem16x8,
  Iop_GetElem32x4:
  Limit these to cases where the host is Neon capable, else we wind up
  generating code which can't run on the host.

* iselIntExpr_R_wrk: add alternative implementation for
  Iop_GetElem32x2 for non-Neon capable hosts.



git-svn-id: svn://svn.valgrind.org/vex/trunk@3098 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/host_arm_isel.c b/priv/host_arm_isel.c
index c55d83b..023fb74 100644
--- a/priv/host_arm_isel.c
+++ b/priv/host_arm_isel.c
@@ -1373,51 +1373,70 @@
       if (e->Iex.Binop.op == Iop_GetElem8x8
           || e->Iex.Binop.op == Iop_GetElem16x4
           || e->Iex.Binop.op == Iop_GetElem32x2) {
-         HReg res = newVRegI(env);
-         HReg arg = iselNeon64Expr(env, e->Iex.Binop.arg1);
-         UInt index, size;
-         if (e->Iex.Binop.arg2->tag != Iex_Const ||
-             typeOfIRExpr(env->type_env, e->Iex.Binop.arg2) != Ity_I8) {
-            vpanic("ARM target supports GetElem with constant "
-                   "second argument only\n");
+         if (env->hwcaps & VEX_HWCAPS_ARM_NEON) {
+            HReg res = newVRegI(env);
+            HReg arg = iselNeon64Expr(env, e->Iex.Binop.arg1);
+            UInt index, size;
+            if (e->Iex.Binop.arg2->tag != Iex_Const ||
+                typeOfIRExpr(env->type_env, e->Iex.Binop.arg2) != Ity_I8) {
+               vpanic("ARM target supports GetElem with constant "
+                      "second argument only (neon)\n");
+            }
+            index = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
+            switch (e->Iex.Binop.op) {
+               case Iop_GetElem8x8: vassert(index < 8); size = 0; break;
+               case Iop_GetElem16x4: vassert(index < 4); size = 1; break;
+               case Iop_GetElem32x2: vassert(index < 2); size = 2; break;
+               default: vassert(0);
+            }
+            addInstr(env, ARMInstr_NUnaryS(ARMneon_GETELEMS,
+                                           mkARMNRS(ARMNRS_Reg, res, 0),
+                                           mkARMNRS(ARMNRS_Scalar, arg, index),
+                                           size, False));
+            return res;
          }
-         index = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
-         switch (e->Iex.Binop.op) {
-            case Iop_GetElem8x8: vassert(index < 8); size = 0; break;
-            case Iop_GetElem16x4: vassert(index < 4); size = 1; break;
-            case Iop_GetElem32x2: vassert(index < 2); size = 2; break;
-            default: vassert(0);
+      }
+
+      if (e->Iex.Binop.op == Iop_GetElem32x2
+          && e->Iex.Binop.arg2->tag == Iex_Const
+          && !(env->hwcaps & VEX_HWCAPS_ARM_NEON)) {
+         /* We may have to do GetElem32x2 on a non-NEON capable
+            target. */
+         IRConst* con = e->Iex.Binop.arg2->Iex.Const.con;
+         vassert(con->tag == Ico_U8); /* else IR is ill-typed */
+         UInt index = con->Ico.U8;
+         if (index >= 0 && index <= 1) {
+            HReg rHi, rLo;
+            iselInt64Expr(&rHi, &rLo, env, e->Iex.Binop.arg1);
+            return index == 0 ? rLo : rHi;
          }
-         addInstr(env, ARMInstr_NUnaryS(ARMneon_GETELEMS,
-                                        mkARMNRS(ARMNRS_Reg, res, 0),
-                                        mkARMNRS(ARMNRS_Scalar, arg, index),
-                                        size, False));
-         return res;
       }
 
       if (e->Iex.Binop.op == Iop_GetElem8x16
           || e->Iex.Binop.op == Iop_GetElem16x8
           || e->Iex.Binop.op == Iop_GetElem32x4) {
-         HReg res = newVRegI(env);
-         HReg arg = iselNeonExpr(env, e->Iex.Binop.arg1);
-         UInt index, size;
-         if (e->Iex.Binop.arg2->tag != Iex_Const ||
-             typeOfIRExpr(env->type_env, e->Iex.Binop.arg2) != Ity_I8) {
-            vpanic("ARM target supports GetElem with constant "
-                   "second argument only\n");
+         if (env->hwcaps & VEX_HWCAPS_ARM_NEON) {
+            HReg res = newVRegI(env);
+            HReg arg = iselNeonExpr(env, e->Iex.Binop.arg1);
+            UInt index, size;
+            if (e->Iex.Binop.arg2->tag != Iex_Const ||
+                typeOfIRExpr(env->type_env, e->Iex.Binop.arg2) != Ity_I8) {
+               vpanic("ARM target supports GetElem with constant "
+                      "second argument only (neon)\n");
+            }
+            index = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
+            switch (e->Iex.Binop.op) {
+               case Iop_GetElem8x16: vassert(index < 16); size = 0; break;
+               case Iop_GetElem16x8: vassert(index < 8); size = 1; break;
+               case Iop_GetElem32x4: vassert(index < 4); size = 2; break;
+               default: vassert(0);
+            }
+            addInstr(env, ARMInstr_NUnaryS(ARMneon_GETELEMS,
+                                           mkARMNRS(ARMNRS_Reg, res, 0),
+                                           mkARMNRS(ARMNRS_Scalar, arg, index),
+                                           size, True));
+            return res;
          }
-         index = e->Iex.Binop.arg2->Iex.Const.con->Ico.U8;
-         switch (e->Iex.Binop.op) {
-            case Iop_GetElem8x16: vassert(index < 16); size = 0; break;
-            case Iop_GetElem16x8: vassert(index < 8); size = 1; break;
-            case Iop_GetElem32x4: vassert(index < 4); size = 2; break;
-            default: vassert(0);
-         }
-         addInstr(env, ARMInstr_NUnaryS(ARMneon_GETELEMS,
-                                        mkARMNRS(ARMNRS_Reg, res, 0),
-                                        mkARMNRS(ARMNRS_Scalar, arg, index),
-                                        size, True));
-         return res;
       }
 
       /* All cases involving host-side helper calls. */
@@ -2165,7 +2184,9 @@
 
 static HReg iselNeon64Expr ( ISelEnv* env, IRExpr* e )
 {
-   HReg r = iselNeon64Expr_wrk( env, e );
+   HReg r;
+   vassert(env->hwcaps & VEX_HWCAPS_ARM_NEON);
+   r = iselNeon64Expr_wrk( env, e );
    vassert(hregClass(r) == HRcFlt64);
    vassert(hregIsVirtual(r));
    return r;
@@ -3773,9 +3794,12 @@
    vpanic("iselNeon64Expr");
 }
 
+
 static HReg iselNeonExpr ( ISelEnv* env, IRExpr* e )
 {
-   HReg r = iselNeonExpr_wrk( env, e );
+   HReg r;
+   vassert(env->hwcaps & VEX_HWCAPS_ARM_NEON);
+   r = iselNeonExpr_wrk( env, e );
    vassert(hregClass(r) == HRcVec128);
    vassert(hregIsVirtual(r));
    return r;