]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Fix problems due to generating Neon instructions on non-Neon capable
authorJulian Seward <jseward@acm.org>
Wed, 4 Mar 2015 12:35:54 +0000 (12:35 +0000)
committerJulian Seward <jseward@acm.org>
Wed, 4 Mar 2015 12:35:54 +0000 (12:35 +0000)
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

VEX/priv/host_arm_isel.c

index c55d83b6d949bd841311d8819ab2f5ab550c4437..023fb74022189944defdadff55f7fdac52cb37b6 100644 (file)
@@ -1373,51 +1373,70 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
       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");
-         }
-         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;
+         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;
+         }
+      }
+
+      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;
+         }
       }
 
       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");
-         }
-         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;
+         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;
+         }
       }
 
       /* All cases involving host-side helper calls. */
@@ -2165,7 +2184,9 @@ static void iselInt64Expr_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e )
 
 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 @@ static HReg iselNeon64Expr_wrk ( ISelEnv* env, IRExpr* e )
    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;