]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Implement the following instructions, in both ARM and Thumb
authorJulian Seward <jseward@acm.org>
Thu, 4 Jul 2013 20:35:42 +0000 (20:35 +0000)
committerJulian Seward <jseward@acm.org>
Thu, 4 Jul 2013 20:35:42 +0000 (20:35 +0000)
encodings:
  SSAX SXTAB16 SHASX SHSAX SHSUB16 SHSUB8
  UASX USAX UQADD16 UQASX UQSAX UHASX UHSAX REVSH

Fixes
  321363 321364 321466 321467 321468 321619 321704
  321620 321621 321692 321694 321696 321697 321703

(Vasily, w.golubev@mail.ru)

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

VEX/priv/guest_arm_toIR.c
VEX/priv/host_arm_isel.c

index 08c75edb8de7576bf6d96a0130f6232096db4e46..48324b184813baf8b8874dde6b557e8d8ab19c64 100644 (file)
@@ -10135,12 +10135,6 @@ static Bool decode_V6MEDIA_instruction (
      /* fall through */
    }
 
-   /////////////////////////////////////////////////////////////////
-   /////////////////////////////////////////////////////////////////
-   /////////////////////////////////////////////////////////////////
-   /////////////////////////////////////////////////////////////////
-   /////////////////////////////////////////////////////////////////
-
    /* ------------------- qsax<c> <Rd>,<Rn>,<Rm> ------------------- */
    /* note: the hardware seems to construct the result differently
       from wot the manual says. */
@@ -10969,39 +10963,798 @@ static Bool decode_V6MEDIA_instruction (
         }
      }
 
-     if (gate) {
-        IRTemp rNt   = newTemp(Ity_I32);
-        IRTemp rMt   = newTemp(Ity_I32);
-        IRTemp res_q = newTemp(Ity_I32);
+     if (gate) {
+        IRTemp rNt   = newTemp(Ity_I32);
+        IRTemp rMt   = newTemp(Ity_I32);
+        IRTemp res_q = newTemp(Ity_I32);
+
+        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
+        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
+
+        assign(res_q, binop(Iop_QAdd32S, mkexpr(rMt), mkexpr(rNt)));
+        if (isT)
+           putIRegT( regD, mkexpr(res_q), condT );
+        else
+           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
+
+        or_into_QFLAG32(
+           signed_overflow_after_Add32(
+              binop(Iop_Add32, mkexpr(rMt), mkexpr(rNt)), rMt, rNt),
+           condT
+        );
+
+        DIP("qadd%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
+        return True;
+     }
+     /* fall through */
+   }
+
+   /* ------------------ qdadd<c> <Rd>,<Rm>,<Rn> ------------------- */
+   {
+     UInt regD = 99, regN = 99, regM = 99;
+     Bool gate = False;
+
+     if (isT) {
+        if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF090) {
+           regN = INSNT0(3,0);
+           regD = INSNT1(11,8);
+           regM = INSNT1(3,0);
+           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
+              gate = True;
+        }
+     } else {
+        if (INSNA(27,20) == BITS8(0,0,0,1,0,1,0,0) &&
+            INSNA(11,8)  == BITS4(0,0,0,0)         &&
+            INSNA(7,4)   == BITS4(0,1,0,1)) {
+           regD = INSNA(15,12);
+           regN = INSNA(19,16);
+           regM = INSNA(3,0);
+           if (regD != 15 && regN != 15 && regM != 15)
+              gate = True;
+        }
+     }
+
+     if (gate) {
+        IRTemp rNt   = newTemp(Ity_I32);
+        IRTemp rMt   = newTemp(Ity_I32);
+        IRTemp rN_d  = newTemp(Ity_I32);
+        IRTemp res_q = newTemp(Ity_I32);
+
+        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
+        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
+
+        or_into_QFLAG32(
+           signed_overflow_after_Add32(
+              binop(Iop_Add32, mkexpr(rNt), mkexpr(rNt)), rNt, rNt),
+           condT
+        );
+
+        assign(rN_d,  binop(Iop_QAdd32S, mkexpr(rNt), mkexpr(rNt)));
+        assign(res_q, binop(Iop_QAdd32S, mkexpr(rMt), mkexpr(rN_d)));
+        if (isT)
+           putIRegT( regD, mkexpr(res_q), condT );
+        else
+           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
+
+        or_into_QFLAG32(
+           signed_overflow_after_Add32(
+              binop(Iop_Add32, mkexpr(rMt), mkexpr(rN_d)), rMt, rN_d),
+           condT
+        );
+
+        DIP("qdadd%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
+        return True;
+     }
+     /* fall through */
+   }
+
+   /* ------------------ qsub<c> <Rd>,<Rn>,<Rm> ------------------- */
+   {
+     UInt regD = 99, regN = 99, regM = 99;
+     Bool gate = False;
+
+     if (isT) {
+        if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF0A0) {
+           regN = INSNT0(3,0);
+           regD = INSNT1(11,8);
+           regM = INSNT1(3,0);
+           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
+              gate = True;
+        }
+     } else {
+        if (INSNA(27,20) == BITS8(0,0,0,1,0,0,1,0) &&
+            INSNA(11,8)  == BITS4(0,0,0,0)         &&
+            INSNA(7,4)   == BITS4(0,1,0,1)) {
+           regD = INSNA(15,12);
+           regN = INSNA(19,16);
+           regM = INSNA(3,0);
+           if (regD != 15 && regN != 15 && regM != 15)
+              gate = True;
+        }
+     }
+
+     if (gate) {
+        IRTemp rNt   = newTemp(Ity_I32);
+        IRTemp rMt   = newTemp(Ity_I32);
+        IRTemp res_q = newTemp(Ity_I32);
+
+        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
+        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
+
+        assign(res_q, binop(Iop_QSub32S, mkexpr(rMt), mkexpr(rNt)));
+        if (isT)
+           putIRegT( regD, mkexpr(res_q), condT );
+        else
+           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
+
+        or_into_QFLAG32(
+           signed_overflow_after_Sub32(
+              binop(Iop_Sub32, mkexpr(rMt), mkexpr(rNt)), rMt, rNt),
+           condT
+        );
+
+        DIP("qsub%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
+        return True;
+     }
+     /* fall through */
+   }
+
+   /* ------------------ qdsub<c> <Rd>,<Rm>,<Rn> ------------------- */
+   {
+     UInt regD = 99, regN = 99, regM = 99;
+     Bool gate = False;
+
+     if (isT) {
+        if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF0B0) {
+           regN = INSNT0(3,0);
+           regD = INSNT1(11,8);
+           regM = INSNT1(3,0);
+           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
+              gate = True;
+        }
+     } else {
+        if (INSNA(27,20) == BITS8(0,0,0,1,0,1,1,0) &&
+            INSNA(11,8)  == BITS4(0,0,0,0)         &&
+            INSNA(7,4)   == BITS4(0,1,0,1)) {
+           regD = INSNA(15,12);
+           regN = INSNA(19,16);
+           regM = INSNA(3,0);
+           if (regD != 15 && regN != 15 && regM != 15)
+              gate = True;
+        }
+     }
+
+     if (gate) {
+        IRTemp rNt   = newTemp(Ity_I32);
+        IRTemp rMt   = newTemp(Ity_I32);
+        IRTemp rN_d  = newTemp(Ity_I32);
+        IRTemp res_q = newTemp(Ity_I32);
+
+        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
+        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
+
+        or_into_QFLAG32(
+           signed_overflow_after_Add32(
+              binop(Iop_Add32, mkexpr(rNt), mkexpr(rNt)), rNt, rNt),
+           condT
+        );
+
+        assign(rN_d,  binop(Iop_QAdd32S, mkexpr(rNt), mkexpr(rNt)));
+        assign(res_q, binop(Iop_QSub32S, mkexpr(rMt), mkexpr(rN_d)));
+        if (isT)
+           putIRegT( regD, mkexpr(res_q), condT );
+        else
+           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
+
+        or_into_QFLAG32(
+           signed_overflow_after_Sub32(
+              binop(Iop_Sub32, mkexpr(rMt), mkexpr(rN_d)), rMt, rN_d),
+           condT
+        );
+
+        DIP("qdsub%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
+        return True;
+     }
+     /* fall through */
+   }
+
+   /* ------------------ uqsub16<c> <Rd>,<Rn>,<Rm> ------------------ */
+   {
+     UInt regD = 99, regN = 99, regM = 99;
+     Bool gate = False;
+
+     if (isT) {
+        if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
+           regN = INSNT0(3,0);
+           regD = INSNT1(11,8);
+           regM = INSNT1(3,0);
+           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
+              gate = True;
+        }
+     } else {
+        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
+            INSNA(11,8)  == BITS4(1,1,1,1)         &&
+            INSNA(7,4)   == BITS4(0,1,1,1)) {
+           regD = INSNA(15,12);
+           regN = INSNA(19,16);
+           regM = INSNA(3,0);
+           if (regD != 15 && regN != 15 && regM != 15)
+             gate = True;
+        }
+     }
+
+     if (gate) {
+        IRTemp rNt   = newTemp(Ity_I32);
+        IRTemp rMt   = newTemp(Ity_I32);
+        IRTemp res_q = newTemp(Ity_I32);
+
+        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
+        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
+
+        assign(res_q, binop(Iop_QSub16Ux2, mkexpr(rNt), mkexpr(rMt)));
+        if (isT)
+           putIRegT( regD, mkexpr(res_q), condT );
+        else
+           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
+
+        DIP("uqsub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
+        return True;
+     }
+     /* fall through */
+   }
+
+   /* ----------------- shadd16<c> <Rd>,<Rn>,<Rm> ------------------- */
+   {
+     UInt regD = 99, regN = 99, regM = 99;
+     Bool gate = False;
+
+     if (isT) {
+        if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
+           regN = INSNT0(3,0);
+           regD = INSNT1(11,8);
+           regM = INSNT1(3,0);
+           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
+              gate = True;
+        }
+     } else {
+        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,1) &&
+            INSNA(11,8)  == BITS4(1,1,1,1)         &&
+            INSNA(7,4)   == BITS4(0,0,0,1)) {
+           regD = INSNA(15,12);
+           regN = INSNA(19,16);
+           regM = INSNA(3,0);
+           if (regD != 15 && regN != 15 && regM != 15)
+              gate = True;
+        }
+     }
+
+     if (gate) {
+        IRTemp rNt   = newTemp(Ity_I32);
+        IRTemp rMt   = newTemp(Ity_I32);
+        IRTemp res_q = newTemp(Ity_I32);
+
+        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
+        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
+
+        assign(res_q, binop(Iop_HAdd16Sx2, mkexpr(rNt), mkexpr(rMt)));
+        if (isT)
+           putIRegT( regD, mkexpr(res_q), condT );
+        else
+           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
+
+        DIP("shadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
+        return True;
+     }
+     /* fall through */
+   }
+
+   /* ----------------- uhsub8<c> <Rd>,<Rn>,<Rm> ------------------- */
+   {
+     UInt regD = 99, regN = 99, regM = 99;
+     Bool gate = False;
+
+     if (isT) {
+        if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
+           regN = INSNT0(3,0);
+           regD = INSNT1(11,8);
+           regM = INSNT1(3,0);
+           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
+              gate = True;
+        }
+     } else {
+        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
+            INSNA(11,8)  == BITS4(1,1,1,1)         &&
+            INSNA(7,4)   == BITS4(1,1,1,1)) {
+           regD = INSNA(15,12);
+           regN = INSNA(19,16);
+           regM = INSNA(3,0);
+           if (regD != 15 && regN != 15 && regM != 15)
+              gate = True;
+        }
+     }
+
+     if (gate) {
+        IRTemp rNt   = newTemp(Ity_I32);
+        IRTemp rMt   = newTemp(Ity_I32);
+        IRTemp res_q = newTemp(Ity_I32);
+
+        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
+        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
+
+        assign(res_q, binop(Iop_HSub8Ux4, mkexpr(rNt), mkexpr(rMt)));
+        if (isT)
+           putIRegT( regD, mkexpr(res_q), condT );
+        else
+           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
+
+        DIP("uhsub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
+        return True;
+     }
+     /* fall through */
+   }
+
+   /* ----------------- uhsub16<c> <Rd>,<Rn>,<Rm> ------------------- */
+   {
+     UInt regD = 99, regN = 99, regM = 99;
+     Bool gate = False;
+
+     if (isT) {
+        if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
+           regN = INSNT0(3,0);
+           regD = INSNT1(11,8);
+           regM = INSNT1(3,0);
+           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
+              gate = True;
+        }
+     } else {
+        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
+            INSNA(11,8)  == BITS4(1,1,1,1)         &&
+            INSNA(7,4)   == BITS4(0,1,1,1)) {
+           regD = INSNA(15,12);
+           regN = INSNA(19,16);
+           regM = INSNA(3,0);
+           if (regD != 15 && regN != 15 && regM != 15)
+              gate = True;
+        }
+     }
+
+     if (gate) {
+        IRTemp rNt   = newTemp(Ity_I32);
+        IRTemp rMt   = newTemp(Ity_I32);
+        IRTemp res_q = newTemp(Ity_I32);
+
+        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
+        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
+
+        assign(res_q, binop(Iop_HSub16Ux2, mkexpr(rNt), mkexpr(rMt)));
+        if (isT)
+           putIRegT( regD, mkexpr(res_q), condT );
+        else
+           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
+
+        DIP("uhsub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
+        return True;
+     }
+     /* fall through */
+   }
+
+   /* ------------------ uqadd16<c> <Rd>,<Rn>,<Rm> ------------------ */
+   {
+     UInt regD = 99, regN = 99, regM = 99;
+     Bool gate = False;
+
+     if (isT) {
+        if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
+           regN = INSNT0(3,0);
+           regD = INSNT1(11,8);
+           regM = INSNT1(3,0);
+           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
+              gate = True;
+        }
+     } else {
+        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
+            INSNA(11,8)  == BITS4(1,1,1,1)         &&
+            INSNA(7,4)   == BITS4(0,0,0,1)) {
+           regD = INSNA(15,12);
+           regN = INSNA(19,16);
+           regM = INSNA(3,0);
+           if (regD != 15 && regN != 15 && regM != 15)
+              gate = True;
+        }
+     }
+
+     if (gate) {
+        IRTemp rNt   = newTemp(Ity_I32);
+        IRTemp rMt   = newTemp(Ity_I32);
+        IRTemp res_q = newTemp(Ity_I32);
+
+        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
+        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
+
+        assign(res_q, binop(Iop_QAdd16Ux2, mkexpr(rNt), mkexpr(rMt)));
+        if (isT)
+           putIRegT( regD, mkexpr(res_q), condT );
+        else
+           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
+
+        DIP("uqadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
+        return True;
+     }
+     /* fall through */
+   }
+
+   /* ------------------- uqsax<c> <Rd>,<Rn>,<Rm> ------------------- */
+   {
+     UInt regD = 99, regN = 99, regM = 99;
+     Bool gate = False;
+
+     if (isT) {
+        if (INSNT0(15,4) == 0xFAE && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
+           regN = INSNT0(3,0);
+           regD = INSNT1(11,8);
+           regM = INSNT1(3,0);
+           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
+              gate = True;
+        }
+     } else {
+        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
+            INSNA(11,8)  == BITS4(1,1,1,1)         &&
+            INSNA(7,4)   == BITS4(0,1,0,1)) {
+           regD = INSNA(15,12);
+           regN = INSNA(19,16);
+           regM = INSNA(3,0);
+           if (regD != 15 && regN != 15 && regM != 15)
+              gate = True;
+        }
+     }
+
+     if (gate) {
+        IRTemp irt_regN     = newTemp(Ity_I32);
+        IRTemp irt_regM     = newTemp(Ity_I32);
+        IRTemp irt_sum      = newTemp(Ity_I32);
+        IRTemp irt_diff     = newTemp(Ity_I32);
+        IRTemp irt_sum_res  = newTemp(Ity_I32);
+        IRTemp irt_diff_res = newTemp(Ity_I32);
+
+        assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
+        assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
+
+        assign( irt_diff, 
+                binop( Iop_Sub32, 
+                       binop( Iop_Shr32, mkexpr(irt_regN), mkU8(16) ),
+                       binop( Iop_Shr32, 
+                              binop(Iop_Shl32, mkexpr(irt_regM), mkU8(16)), 
+                              mkU8(16) ) ) );
+        armUnsignedSatQ( &irt_diff_res, NULL, irt_diff, 0x10);
+
+        assign( irt_sum, 
+                binop( Iop_Add32, 
+                       binop( Iop_Shr32, 
+                              binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ), 
+                              mkU8(16) ), 
+                       binop( Iop_Shr32, mkexpr(irt_regM), mkU8(16) )) );
+        armUnsignedSatQ( &irt_sum_res, NULL, irt_sum, 0x10 );
+
+        IRExpr* ire_result = binop( Iop_Or32, 
+                                    binop( Iop_Shl32, mkexpr(irt_diff_res), 
+                                           mkU8(16) ), 
+                                    binop( Iop_And32, mkexpr(irt_sum_res), 
+                                           mkU32(0xFFFF)) );
+
+        if (isT) 
+           putIRegT( regD, ire_result, condT );
+        else
+           putIRegA( regD, ire_result, condT, Ijk_Boring );
+
+        DIP( "uqsax%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
+        return True;
+     }
+     /* fall through */
+   }
+
+   /* ------------------- uqasx<c> <Rd>,<Rn>,<Rm> ------------------- */
+   {
+     UInt regD = 99, regN = 99, regM = 99;
+     Bool gate = False;
+
+     if (isT) {
+        if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
+           regN = INSNT0(3,0);
+           regD = INSNT1(11,8);
+           regM = INSNT1(3,0);
+           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
+              gate = True;
+        }
+     } else {
+        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
+            INSNA(11,8)  == BITS4(1,1,1,1)         &&
+            INSNA(7,4)   == BITS4(0,0,1,1)) {
+           regD = INSNA(15,12);
+           regN = INSNA(19,16);
+           regM = INSNA(3,0);
+           if (regD != 15 && regN != 15 && regM != 15)
+              gate = True;
+        }
+     }
+
+     if (gate) {
+        IRTemp irt_regN     = newTemp(Ity_I32);
+        IRTemp irt_regM     = newTemp(Ity_I32);
+        IRTemp irt_sum      = newTemp(Ity_I32);
+        IRTemp irt_diff     = newTemp(Ity_I32);
+        IRTemp irt_res_sum  = newTemp(Ity_I32);
+        IRTemp irt_res_diff = newTemp(Ity_I32);
+
+        assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
+        assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
+
+        assign( irt_diff,  
+                binop( Iop_Sub32,
+                       binop( Iop_Shr32, 
+                              binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ), 
+                              mkU8(16) ), 
+                       binop( Iop_Shr32, mkexpr(irt_regM), mkU8(16) ) ) );
+        armUnsignedSatQ( &irt_res_diff, NULL, irt_diff, 0x10 );
+
+        assign( irt_sum, 
+                binop( Iop_Add32, 
+                       binop( Iop_Shr32, mkexpr(irt_regN), mkU8(16) ), 
+                       binop( Iop_Shr32, 
+                              binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ), 
+                              mkU8(16) ) ) );
+        armUnsignedSatQ( &irt_res_sum, NULL, irt_sum, 0x10 );
+       
+        IRExpr* ire_result 
+          = binop( Iop_Or32, 
+                   binop( Iop_Shl32, mkexpr(irt_res_sum), mkU8(16) ), 
+                   binop( Iop_And32, mkexpr(irt_res_diff), mkU32(0xFFFF) ) );
+
+        if (isT)
+           putIRegT( regD, ire_result, condT );
+        else
+           putIRegA( regD, ire_result, condT, Ijk_Boring );
+
+        DIP( "uqasx%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
+        return True;
+     }
+     /* fall through */
+   }
+
+   /* ------------------- usax<c> <Rd>,<Rn>,<Rm> ------------------- */
+   {
+     UInt regD = 99, regN = 99, regM = 99;
+     Bool gate = False;
+
+     if (isT) {
+        if (INSNT0(15,4) == 0xFAE && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
+           regN = INSNT0(3,0);
+           regD = INSNT1(11,8);
+           regM = INSNT1(3,0);
+           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
+              gate = True;
+        }
+     } else {
+        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
+            INSNA(11,8)  == BITS4(1,1,1,1)         &&
+            INSNA(7,4)   == BITS4(0,1,0,1)) {
+           regD = INSNA(15,12);
+           regN = INSNA(19,16);
+           regM = INSNA(3,0);
+           if (regD != 15 && regN != 15 && regM != 15)
+              gate = True;
+        }
+     }
+
+     if (gate) {
+        IRTemp irt_regN = newTemp(Ity_I32);
+        IRTemp irt_regM = newTemp(Ity_I32);
+        IRTemp irt_sum  = newTemp(Ity_I32);
+        IRTemp irt_diff = newTemp(Ity_I32);
+
+        assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
+        assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
+
+        assign( irt_sum,  
+                binop( Iop_Add32, 
+                       unop( Iop_16Uto32,
+                             unop( Iop_32to16, mkexpr(irt_regN) )
+                       ),  
+                       binop( Iop_Shr32, mkexpr(irt_regM), mkU8(16) ) ) );
+
+        assign( irt_diff, 
+                binop( Iop_Sub32, 
+                       binop( Iop_Shr32, mkexpr(irt_regN), mkU8(16) ), 
+                       unop( Iop_16Uto32, 
+                             unop( Iop_32to16, mkexpr(irt_regM) )
+                       )
+                )
+        );
+       
+        IRExpr* ire_result 
+          = binop( Iop_Or32, 
+                   binop( Iop_Shl32, mkexpr(irt_diff), mkU8(16) ), 
+                   binop( Iop_And32, mkexpr(irt_sum), mkU32(0xFFFF) ) );
+
+        IRTemp ge10 = newTemp(Ity_I32);
+        assign( ge10, IRExpr_ITE( binop( Iop_CmpLE32U, 
+                                         mkU32(0x10000), mkexpr(irt_sum) ),
+                                  mkU32(1), mkU32(0) ) );
+        put_GEFLAG32( 0, 0, mkexpr(ge10), condT );
+        put_GEFLAG32( 1, 0, mkexpr(ge10), condT );
+
+        IRTemp ge32 = newTemp(Ity_I32);
+        assign(ge32, unop(Iop_Not32, mkexpr(irt_diff)));
+        put_GEFLAG32( 2, 31, mkexpr(ge32), condT );
+        put_GEFLAG32( 3, 31, mkexpr(ge32), condT );
+
+        if (isT)
+           putIRegT( regD, ire_result, condT );
+        else
+           putIRegA( regD, ire_result, condT, Ijk_Boring );
+
+        DIP( "usax%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
+        return True;
+     }
+     /* fall through */
+   }
+
+   /* ------------------- uasx<c> <Rd>,<Rn>,<Rm> ------------------- */
+   {
+     UInt regD = 99, regN = 99, regM = 99;
+     Bool gate = False;
+
+     if (isT) {
+        if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF040) {
+           regN = INSNT0(3,0);
+           regD = INSNT1(11,8);
+           regM = INSNT1(3,0);
+           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
+              gate = True;
+        }
+     } else {
+        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,0,1) &&
+            INSNA(11,8)  == BITS4(1,1,1,1)         &&
+            INSNA(7,4)   == BITS4(0,0,1,1)) {
+           regD = INSNA(15,12);
+           regN = INSNA(19,16);
+           regM = INSNA(3,0);
+           if (regD != 15 && regN != 15 && regM != 15)
+              gate = True;
+        }
+     }
+
+     if (gate) {
+        IRTemp irt_regN = newTemp(Ity_I32);
+        IRTemp irt_regM = newTemp(Ity_I32);
+        IRTemp irt_sum  = newTemp(Ity_I32);
+        IRTemp irt_diff = newTemp(Ity_I32);
+
+        assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
+        assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
+
+        assign( irt_diff,  
+                binop( Iop_Sub32, 
+                       unop( Iop_16Uto32, 
+                             unop( Iop_32to16, mkexpr(irt_regN) )
+                       ), 
+                       binop( Iop_Shr32, mkexpr(irt_regM), mkU8(16) ) ) );
+
+        assign( irt_sum, 
+                binop( Iop_Add32, 
+                       binop( Iop_Shr32, mkexpr(irt_regN), mkU8(16) ), 
+                       unop( Iop_16Uto32, 
+                             unop( Iop_32to16, mkexpr(irt_regM) )
+                       ) ) );
+       
+        IRExpr* ire_result 
+          = binop( Iop_Or32, 
+                   binop( Iop_Shl32, mkexpr(irt_sum), mkU8(16) ), 
+                   binop( Iop_And32, mkexpr(irt_diff), mkU32(0xFFFF) ) );
+
+        IRTemp ge10 = newTemp(Ity_I32);
+        assign(ge10, unop(Iop_Not32, mkexpr(irt_diff)));
+        put_GEFLAG32( 0, 31, mkexpr(ge10), condT );
+        put_GEFLAG32( 1, 31, mkexpr(ge10), condT );
+
+        IRTemp ge32 = newTemp(Ity_I32);
+        assign( ge32, IRExpr_ITE( binop( Iop_CmpLE32U,
+                                         mkU32(0x10000), mkexpr(irt_sum) ),
+                                  mkU32(1), mkU32(0) ) );
+        put_GEFLAG32( 2, 0, mkexpr(ge32), condT );
+        put_GEFLAG32( 3, 0, mkexpr(ge32), condT );
+
+        if (isT)
+           putIRegT( regD, ire_result, condT );
+        else
+           putIRegA( regD, ire_result, condT, Ijk_Boring );
+
+        DIP( "uasx%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
+        return True;
+     }
+     /* fall through */
+   }
+
+   /* ------------------- ssax<c> <Rd>,<Rn>,<Rm> ------------------- */
+   {
+     UInt regD = 99, regN = 99, regM = 99;
+     Bool gate = False;
+
+     if (isT) {
+        if (INSNT0(15,4) == 0xFAE && (INSNT1(15,0) & 0xF0F0) == 0xF000) {
+           regN = INSNT0(3,0);
+           regD = INSNT1(11,8);
+           regM = INSNT1(3,0);
+           if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
+              gate = True;
+        }
+     } else {
+        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,0,1) &&
+            INSNA(11,8)  == BITS4(1,1,1,1)         &&
+            INSNA(7,4)   == BITS4(0,1,0,1)) {
+           regD = INSNA(15,12);
+           regN = INSNA(19,16);
+           regM = INSNA(3,0);
+           if (regD != 15 && regN != 15 && regM != 15)
+              gate = True;
+        }
+     }
+
+     if (gate) {
+        IRTemp irt_regN = newTemp(Ity_I32);
+        IRTemp irt_regM = newTemp(Ity_I32);
+        IRTemp irt_sum  = newTemp(Ity_I32);
+        IRTemp irt_diff = newTemp(Ity_I32);
+
+        assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
+        assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
+
+        assign( irt_sum,  
+                binop( Iop_Add32, 
+                       binop( Iop_Sar32, 
+                              binop( Iop_Shl32, mkexpr(irt_regN), mkU8(16) ), 
+                              mkU8(16) ), 
+                       binop( Iop_Sar32, mkexpr(irt_regM), mkU8(16) ) ) );
+
+        assign( irt_diff, 
+                binop( Iop_Sub32, 
+                       binop( Iop_Sar32, mkexpr(irt_regN), mkU8(16) ), 
+                       binop( Iop_Sar32, 
+                              binop( Iop_Shl32, mkexpr(irt_regM), mkU8(16) ), 
+                              mkU8(16) ) ) );
+       
+        IRExpr* ire_result 
+          = binop( Iop_Or32, 
+                   binop( Iop_Shl32, mkexpr(irt_diff), mkU8(16) ), 
+                   binop( Iop_And32, mkexpr(irt_sum), mkU32(0xFFFF) ) );
+
+        IRTemp ge10 = newTemp(Ity_I32);
+        assign(ge10, unop(Iop_Not32, mkexpr(irt_sum)));
+        put_GEFLAG32( 0, 31, mkexpr(ge10), condT );
+        put_GEFLAG32( 1, 31, mkexpr(ge10), condT );
 
-        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
-        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
+        IRTemp ge32 = newTemp(Ity_I32);
+        assign(ge32, unop(Iop_Not32, mkexpr(irt_diff)));
+        put_GEFLAG32( 2, 31, mkexpr(ge32), condT );
+        put_GEFLAG32( 3, 31, mkexpr(ge32), condT );
 
-        assign(res_q, binop(Iop_QAdd32S, mkexpr(rMt), mkexpr(rNt)));
         if (isT)
-           putIRegT( regD, mkexpr(res_q), condT );
+           putIRegT( regD, ire_result, condT );
         else
-           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
-
-        or_into_QFLAG32(
-           signed_overflow_after_Add32(
-              binop(Iop_Add32, mkexpr(rMt), mkexpr(rNt)), rMt, rNt),
-           condT
-        );
+           putIRegA( regD, ire_result, condT, Ijk_Boring );
 
-        DIP("qadd%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
+        DIP( "ssax%s r%u, r%u, r%u\n", nCC(conq), regD, regN, regM );
         return True;
      }
      /* fall through */
    }
 
-   /* ------------------ qdadd<c> <Rd>,<Rm>,<Rn> ------------------- */
+   /* ----------------- shsub8<c> <Rd>,<Rn>,<Rm> ------------------- */
    {
      UInt regD = 99, regN = 99, regM = 99;
      Bool gate = False;
 
      if (isT) {
-        if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF090) {
+        if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
            regN = INSNT0(3,0);
            regD = INSNT1(11,8);
            regM = INSNT1(3,0);
@@ -11009,9 +11762,9 @@ static Bool decode_V6MEDIA_instruction (
               gate = True;
         }
      } else {
-        if (INSNA(27,20) == BITS8(0,0,0,1,0,1,0,0) &&
-            INSNA(11,8)  == BITS4(0,0,0,0)         &&
-            INSNA(7,4)   == BITS4(0,1,0,1)) {
+        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,1) &&
+            INSNA(11,8)  == BITS4(1,1,1,1)         &&
+            INSNA(7,4)   == BITS4(1,1,1,1)) {
            regD = INSNA(15,12);
            regN = INSNA(19,16);
            regM = INSNA(3,0);
@@ -11023,95 +11776,105 @@ static Bool decode_V6MEDIA_instruction (
      if (gate) {
         IRTemp rNt   = newTemp(Ity_I32);
         IRTemp rMt   = newTemp(Ity_I32);
-        IRTemp rN_d  = newTemp(Ity_I32);
         IRTemp res_q = newTemp(Ity_I32);
 
         assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
         assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
 
-        or_into_QFLAG32(
-           signed_overflow_after_Add32(
-              binop(Iop_Add32, mkexpr(rNt), mkexpr(rNt)), rNt, rNt),
-           condT
-        );
-
-        assign(rN_d,  binop(Iop_QAdd32S, mkexpr(rNt), mkexpr(rNt)));
-        assign(res_q, binop(Iop_QAdd32S, mkexpr(rMt), mkexpr(rN_d)));
+        assign(res_q, binop(Iop_HSub8Sx4, mkexpr(rNt), mkexpr(rMt)));
         if (isT)
            putIRegT( regD, mkexpr(res_q), condT );
         else
            putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
 
-        or_into_QFLAG32(
-           signed_overflow_after_Add32(
-              binop(Iop_Add32, mkexpr(rMt), mkexpr(rN_d)), rMt, rN_d),
-           condT
-        );
-
-        DIP("qdadd%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
+        DIP("shsub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
         return True;
      }
      /* fall through */
    }
 
-   /* ------------------ qsub<c> <Rd>,<Rn>,<Rm> ------------------- */
+   /* ----------------- sxtab16<c> Rd,Rn,Rm{,rot} ------------------ */
    {
-     UInt regD = 99, regN = 99, regM = 99;
+     UInt regD = 99, regN = 99, regM = 99, rotate = 99;
      Bool gate = False;
 
      if (isT) {
-        if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF0A0) {
-           regN = INSNT0(3,0);
-           regD = INSNT1(11,8);
-           regM = INSNT1(3,0);
+        if (INSNT0(15,4) == 0xFA2 && (INSNT1(15,0) & 0xF0C0) == 0xF080) {
+           regN   = INSNT0(3,0);
+           regD   = INSNT1(11,8);
+           regM   = INSNT1(3,0);
+           rotate = INSNT1(5,4);
            if (!isBadRegT(regD) && !isBadRegT(regN) && !isBadRegT(regM))
               gate = True;
         }
      } else {
-        if (INSNA(27,20) == BITS8(0,0,0,1,0,0,1,0) &&
-            INSNA(11,8)  == BITS4(0,0,0,0)         &&
-            INSNA(7,4)   == BITS4(0,1,0,1)) {
-           regD = INSNA(15,12);
-           regN = INSNA(19,16);
-           regM = INSNA(3,0);
+        if (INSNA(27,20) == BITS8(0,1,1,0,1,0,0,0) &&
+            INSNA(9,4)   == BITS6(0,0,0,1,1,1) ) {
+           regD   = INSNA(15,12);
+           regN   = INSNA(19,16);
+           regM   = INSNA(3,0);
+           rotate = INSNA(11,10);
            if (regD != 15 && regN != 15 && regM != 15)
-              gate = True;
+             gate = True;
         }
      }
 
      if (gate) {
-        IRTemp rNt   = newTemp(Ity_I32);
-        IRTemp rMt   = newTemp(Ity_I32);
-        IRTemp res_q = newTemp(Ity_I32);
+        IRTemp irt_regN = newTemp(Ity_I32);
+        assign( irt_regN, isT ? getIRegT(regN) : getIRegA(regN) );
 
-        assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
-        assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
+        IRTemp irt_regM = newTemp(Ity_I32);
+        assign( irt_regM, isT ? getIRegT(regM) : getIRegA(regM) );
+
+        IRTemp irt_rot = newTemp(Ity_I32);
+        assign( irt_rot, genROR32(irt_regM, 8 * rotate) );
+
+        /* FIXME Maybe we can write this arithmetic in shorter form. */
+        IRExpr* resLo
+           = binop(Iop_And32,
+                   binop(Iop_Add32,
+                         mkexpr(irt_regN),
+                         unop(Iop_16Uto32,
+                              unop(Iop_8Sto16,
+                                   unop(Iop_32to8, mkexpr(irt_rot))))),
+                   mkU32(0x0000FFFF));
+
+        IRExpr* resHi
+           = binop(Iop_And32,
+                   binop(Iop_Add32,
+                         mkexpr(irt_regN),
+                         binop(Iop_Shl32,
+                               unop(Iop_16Uto32,
+                                    unop(Iop_8Sto16,
+                                         unop(Iop_32to8,
+                                              binop(Iop_Shr32,
+                                                    mkexpr(irt_rot),
+                                                    mkU8(16))))),
+                               mkU8(16))),
+                   mkU32(0xFFFF0000));
+
+        IRExpr* ire_result 
+           = binop( Iop_Or32, resHi, resLo );
 
-        assign(res_q, binop(Iop_QSub32S, mkexpr(rMt), mkexpr(rNt)));
         if (isT)
-           putIRegT( regD, mkexpr(res_q), condT );
+           putIRegT( regD, ire_result, condT );
         else
-           putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
-
-        or_into_QFLAG32(
-           signed_overflow_after_Sub32(
-              binop(Iop_Sub32, mkexpr(rMt), mkexpr(rNt)), rMt, rNt),
-           condT
-        );
+           putIRegA( regD, ire_result, condT, Ijk_Boring );
 
-        DIP("qsub%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
+        DIP( "sxtab16%s r%u, r%u, r%u, ROR #%u\n", 
+             nCC(conq), regD, regN, regM, 8 * rotate );
         return True;
      }
      /* fall through */
    }
 
-   /* ------------------ qdsub<c> <Rd>,<Rm>,<Rn> ------------------- */
+   /* ----------------- shasx<c> <Rd>,<Rn>,<Rm> ------------------- */
    {
      UInt regD = 99, regN = 99, regM = 99;
      Bool gate = False;
 
      if (isT) {
-        if (INSNT0(15,4) == 0xFA8 && (INSNT1(15,0) & 0xF0F0) == 0xF0B0) {
+        if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
            regN = INSNT0(3,0);
            regD = INSNT1(11,8);
            regM = INSNT1(3,0);
@@ -11119,9 +11882,9 @@ static Bool decode_V6MEDIA_instruction (
               gate = True;
         }
      } else {
-        if (INSNA(27,20) == BITS8(0,0,0,1,0,1,1,0) &&
-            INSNA(11,8)  == BITS4(0,0,0,0)         &&
-            INSNA(7,4)   == BITS4(0,1,0,1)) {
+        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,1) &&
+            INSNA(11,8)  == BITS4(1,1,1,1)         &&
+            INSNA(7,4)   == BITS4(0,0,1,1)) {
            regD = INSNA(15,12);
            regN = INSNA(19,16);
            regM = INSNA(3,0);
@@ -11133,44 +11896,82 @@ static Bool decode_V6MEDIA_instruction (
      if (gate) {
         IRTemp rNt   = newTemp(Ity_I32);
         IRTemp rMt   = newTemp(Ity_I32);
-        IRTemp rN_d  = newTemp(Ity_I32);
+        IRTemp irt_diff  = newTemp(Ity_I32);
+        IRTemp irt_sum   = newTemp(Ity_I32);
         IRTemp res_q = newTemp(Ity_I32);
 
         assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
         assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
 
-        or_into_QFLAG32(
-           signed_overflow_after_Add32(
-              binop(Iop_Add32, mkexpr(rNt), mkexpr(rNt)), rNt, rNt),
-           condT
+        assign( irt_diff,
+                binop(Iop_Sub32,
+                      unop(Iop_16Sto32,
+                           unop(Iop_32to16,
+                                mkexpr(rNt)
+                           )
+                      ),
+                      unop(Iop_16Sto32,
+                           unop(Iop_32to16,
+                                binop(Iop_Shr32,
+                                      mkexpr(rMt), mkU8(16)
+                                )
+                           )
+                      )
+                )
+        );
+
+        assign( irt_sum,
+                binop(Iop_Add32,
+                      unop(Iop_16Sto32,
+                           unop(Iop_32to16,
+                                binop(Iop_Shr32,
+                                      mkexpr(rNt), mkU8(16)
+                                )
+                           )
+                      ),
+                      unop(Iop_16Sto32,
+                           unop(Iop_32to16, mkexpr(rMt)
+                           )
+                      )
+                )
+        );
+
+        assign( res_q,
+                binop(Iop_Or32, 
+                      unop(Iop_16Uto32,
+                           unop(Iop_32to16,
+                                binop(Iop_Shr32,
+                                      mkexpr(irt_diff), mkU8(1)
+                                )
+                           )
+                      ),
+                      binop(Iop_Shl32,
+                            binop(Iop_Shr32,
+                                  mkexpr(irt_sum), mkU8(1)
+                            ),
+                            mkU8(16)
+                     )
+                )
         );
 
-        assign(rN_d,  binop(Iop_QAdd32S, mkexpr(rNt), mkexpr(rNt)));
-        assign(res_q, binop(Iop_QSub32S, mkexpr(rMt), mkexpr(rN_d)));
         if (isT)
            putIRegT( regD, mkexpr(res_q), condT );
         else
            putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
 
-        or_into_QFLAG32(
-           signed_overflow_after_Sub32(
-              binop(Iop_Sub32, mkexpr(rMt), mkexpr(rN_d)), rMt, rN_d),
-           condT
-        );
-
-        DIP("qdsub%s r%u, r%u, r%u\n", nCC(conq),regD,regM,regN);
+        DIP("shasx%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
         return True;
      }
      /* fall through */
    }
 
-   /* ------------------ uqsub16<c> <Rd>,<Rn>,<Rm> ------------------ */
+   /* ----------------- uhasx<c> <Rd>,<Rn>,<Rm> ------------------- */
    {
      UInt regD = 99, regN = 99, regM = 99;
      Bool gate = False;
 
      if (isT) {
-        if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF050) {
+        if (INSNT0(15,4) == 0xFAA && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
            regN = INSNT0(3,0);
            regD = INSNT1(11,8);
            regM = INSNT1(3,0);
@@ -11178,44 +11979,96 @@ static Bool decode_V6MEDIA_instruction (
               gate = True;
         }
      } else {
-        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,0) &&
+        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
             INSNA(11,8)  == BITS4(1,1,1,1)         &&
-            INSNA(7,4)   == BITS4(0,1,1,1)) {
+            INSNA(7,4)   == BITS4(0,0,1,1)) {
            regD = INSNA(15,12);
            regN = INSNA(19,16);
            regM = INSNA(3,0);
            if (regD != 15 && regN != 15 && regM != 15)
-             gate = True;
+              gate = True;
         }
      }
 
      if (gate) {
         IRTemp rNt   = newTemp(Ity_I32);
         IRTemp rMt   = newTemp(Ity_I32);
+        IRTemp irt_diff  = newTemp(Ity_I32);
+        IRTemp irt_sum   = newTemp(Ity_I32);
         IRTemp res_q = newTemp(Ity_I32);
 
         assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
         assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
 
-        assign(res_q, binop(Iop_QSub16Ux2, mkexpr(rNt), mkexpr(rMt)));
+        assign( irt_diff,
+                binop(Iop_Sub32,
+                      unop(Iop_16Uto32,
+                           unop(Iop_32to16,
+                                mkexpr(rNt)
+                           )
+                      ),
+                      unop(Iop_16Uto32,
+                           unop(Iop_32to16,
+                                binop(Iop_Shr32,
+                                      mkexpr(rMt), mkU8(16)
+                                )
+                           )
+                      )
+                )
+        );
+
+        assign( irt_sum,
+                binop(Iop_Add32,
+                      unop(Iop_16Uto32,
+                           unop(Iop_32to16,
+                                binop(Iop_Shr32,
+                                      mkexpr(rNt), mkU8(16)
+                                )
+                           )
+                      ),
+                      unop(Iop_16Uto32,
+                           unop(Iop_32to16, mkexpr(rMt)
+                           )
+                      )
+                )
+        );
+
+        assign( res_q,
+                binop(Iop_Or32, 
+                      unop(Iop_16Uto32,
+                           unop(Iop_32to16,
+                                binop(Iop_Shr32,
+                                      mkexpr(irt_diff), mkU8(1)
+                                )
+                           )
+                      ),
+                      binop(Iop_Shl32,
+                            binop(Iop_Shr32,
+                                  mkexpr(irt_sum), mkU8(1)
+                            ),
+                            mkU8(16)
+                     )
+                )
+        );
+
         if (isT)
            putIRegT( regD, mkexpr(res_q), condT );
         else
            putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
 
-        DIP("uqsub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
+        DIP("uhasx%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
         return True;
      }
      /* fall through */
    }
 
-   /* ----------------- shadd16<c> <Rd>,<Rn>,<Rm> ------------------- */
+   /* ----------------- shsax<c> <Rd>,<Rn>,<Rm> ------------------- */
    {
      UInt regD = 99, regN = 99, regM = 99;
      Bool gate = False;
 
      if (isT) {
-        if (INSNT0(15,4) == 0xFA9 && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
+        if (INSNT0(15,4) == 0xFAE && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
            regN = INSNT0(3,0);
            regD = INSNT1(11,8);
            regM = INSNT1(3,0);
@@ -11225,7 +12078,7 @@ static Bool decode_V6MEDIA_instruction (
      } else {
         if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,1) &&
             INSNA(11,8)  == BITS4(1,1,1,1)         &&
-            INSNA(7,4)   == BITS4(0,0,0,1)) {
+            INSNA(7,4)   == BITS4(0,1,0,1)) {
            regD = INSNA(15,12);
            regN = INSNA(19,16);
            regM = INSNA(3,0);
@@ -11237,30 +12090,82 @@ static Bool decode_V6MEDIA_instruction (
      if (gate) {
         IRTemp rNt   = newTemp(Ity_I32);
         IRTemp rMt   = newTemp(Ity_I32);
+        IRTemp irt_diff  = newTemp(Ity_I32);
+        IRTemp irt_sum   = newTemp(Ity_I32);
         IRTemp res_q = newTemp(Ity_I32);
 
         assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
         assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
 
-        assign(res_q, binop(Iop_HAdd16Sx2, mkexpr(rNt), mkexpr(rMt)));
+        assign( irt_sum,
+                binop(Iop_Add32,
+                      unop(Iop_16Sto32,
+                           unop(Iop_32to16,
+                                mkexpr(rNt)
+                           )
+                      ),
+                      unop(Iop_16Sto32,
+                           unop(Iop_32to16,
+                                binop(Iop_Shr32,
+                                      mkexpr(rMt), mkU8(16)
+                                )
+                           )
+                      )
+                )
+        );
+
+        assign( irt_diff,
+                binop(Iop_Sub32,
+                      unop(Iop_16Sto32,
+                           unop(Iop_32to16,
+                                binop(Iop_Shr32,
+                                      mkexpr(rNt), mkU8(16)
+                                )
+                           )
+                      ),
+                      unop(Iop_16Sto32,
+                           unop(Iop_32to16, mkexpr(rMt)
+                           )
+                      )
+                )
+        );
+
+        assign( res_q,
+                binop(Iop_Or32, 
+                      unop(Iop_16Uto32,
+                           unop(Iop_32to16,
+                                binop(Iop_Shr32,
+                                      mkexpr(irt_sum), mkU8(1)
+                                )
+                           )
+                      ),
+                      binop(Iop_Shl32,
+                            binop(Iop_Shr32,
+                                  mkexpr(irt_diff), mkU8(1)
+                            ),
+                            mkU8(16)
+                     )
+                )
+        );
+
         if (isT)
            putIRegT( regD, mkexpr(res_q), condT );
         else
            putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
 
-        DIP("shadd16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
+        DIP("shsax%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
         return True;
      }
      /* fall through */
    }
 
-   /* ----------------- uhsub8<c> <Rd>,<Rn>,<Rm> ------------------- */
+   /* ----------------- uhsax<c> <Rd>,<Rn>,<Rm> ------------------- */
    {
      UInt regD = 99, regN = 99, regM = 99;
      Bool gate = False;
 
      if (isT) {
-        if (INSNT0(15,4) == 0xFAC && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
+        if (INSNT0(15,4) == 0xFAE && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
            regN = INSNT0(3,0);
            regD = INSNT1(11,8);
            regM = INSNT1(3,0);
@@ -11270,7 +12175,7 @@ static Bool decode_V6MEDIA_instruction (
      } else {
         if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
             INSNA(11,8)  == BITS4(1,1,1,1)         &&
-            INSNA(7,4)   == BITS4(1,1,1,1)) {
+            INSNA(7,4)   == BITS4(0,1,0,1)) {
            regD = INSNA(15,12);
            regN = INSNA(19,16);
            regM = INSNA(3,0);
@@ -11282,30 +12187,82 @@ static Bool decode_V6MEDIA_instruction (
      if (gate) {
         IRTemp rNt   = newTemp(Ity_I32);
         IRTemp rMt   = newTemp(Ity_I32);
+        IRTemp irt_diff  = newTemp(Ity_I32);
+        IRTemp irt_sum   = newTemp(Ity_I32);
         IRTemp res_q = newTemp(Ity_I32);
 
         assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
         assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
 
-        assign(res_q, binop(Iop_HSub8Ux4, mkexpr(rNt), mkexpr(rMt)));
+        assign( irt_sum,
+                binop(Iop_Add32,
+                      unop(Iop_16Uto32,
+                           unop(Iop_32to16,
+                                mkexpr(rNt)
+                           )
+                      ),
+                      unop(Iop_16Uto32,
+                           unop(Iop_32to16,
+                                binop(Iop_Shr32,
+                                      mkexpr(rMt), mkU8(16)
+                                )
+                           )
+                      )
+                )
+        );
+
+        assign( irt_diff,
+                binop(Iop_Sub32,
+                      unop(Iop_16Uto32,
+                           unop(Iop_32to16,
+                                binop(Iop_Shr32,
+                                      mkexpr(rNt), mkU8(16)
+                                )
+                           )
+                      ),
+                      unop(Iop_16Uto32,
+                           unop(Iop_32to16, mkexpr(rMt)
+                           )
+                      )
+                )
+        );
+
+        assign( res_q,
+                binop(Iop_Or32, 
+                      unop(Iop_16Uto32,
+                           unop(Iop_32to16,
+                                binop(Iop_Shr32,
+                                      mkexpr(irt_sum), mkU8(1)
+                                )
+                           )
+                      ),
+                      binop(Iop_Shl32,
+                            binop(Iop_Shr32,
+                                  mkexpr(irt_diff), mkU8(1)
+                            ),
+                            mkU8(16)
+                     )
+                )
+        );
+
         if (isT)
            putIRegT( regD, mkexpr(res_q), condT );
         else
            putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
 
-        DIP("uhsub8%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
+        DIP("uhsax%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
         return True;
      }
      /* fall through */
    }
 
-   /* ----------------- uhsub16<c> <Rd>,<Rn>,<Rm> ------------------- */
+   /* ----------------- shsub16<c> <Rd>,<Rn>,<Rm> ------------------- */
    {
      UInt regD = 99, regN = 99, regM = 99;
      Bool gate = False;
 
      if (isT) {
-        if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF060) {
+        if (INSNT0(15,4) == 0xFAD && (INSNT1(15,0) & 0xF0F0) == 0xF020) {
            regN = INSNT0(3,0);
            regD = INSNT1(11,8);
            regM = INSNT1(3,0);
@@ -11313,7 +12270,7 @@ static Bool decode_V6MEDIA_instruction (
               gate = True;
         }
      } else {
-        if (INSNA(27,20) == BITS8(0,1,1,0,0,1,1,1) &&
+        if (INSNA(27,20) == BITS8(0,1,1,0,0,0,1,1) &&
             INSNA(11,8)  == BITS4(1,1,1,1)         &&
             INSNA(7,4)   == BITS4(0,1,1,1)) {
            regD = INSNA(15,12);
@@ -11332,13 +12289,13 @@ static Bool decode_V6MEDIA_instruction (
         assign( rNt, isT ? getIRegT(regN) : getIRegA(regN) );
         assign( rMt, isT ? getIRegT(regM) : getIRegA(regM) );
 
-        assign(res_q, binop(Iop_HSub16Ux2, mkexpr(rNt), mkexpr(rMt)));
+        assign(res_q, binop(Iop_HSub16Sx2, mkexpr(rNt), mkexpr(rMt)));
         if (isT)
            putIRegT( regD, mkexpr(res_q), condT );
         else
            putIRegA( regD, mkexpr(res_q), condT, Ijk_Boring );
 
-        DIP("uhsub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
+        DIP("shsub16%s r%u, r%u, r%u\n", nCC(conq),regD,regN,regM);
         return True;
      }
      /* fall through */
@@ -15366,6 +16323,37 @@ DisResult disInstr_ARM_WRK (
       }
    }
 
+   /* ------------------- revsh ----------------------- */
+   if (INSN(27,16) == 0x6FF && INSN(11,4) == 0xFB) {
+      UInt rM = INSN(3,0);
+      UInt rD = INSN(15,12);
+      if (rM != 15 && rD != 15) {
+         IRTemp irt_rM  = newTemp(Ity_I32);
+         IRTemp irt_hi  = newTemp(Ity_I32);
+         IRTemp irt_low = newTemp(Ity_I32);
+         IRTemp irt_res = newTemp(Ity_I32);
+         assign(irt_rM, getIRegA(rM));
+         assign(irt_hi,
+                binop(Iop_Sar32,
+                      binop(Iop_Shl32, mkexpr(irt_rM), mkU8(24)),
+                      mkU8(16)
+                )
+         );
+         assign(irt_low,
+                binop(Iop_And32,
+                      binop(Iop_Shr32, mkexpr(irt_rM), mkU8(8)),
+                      mkU32(0xFF)
+                )
+         );
+         assign(irt_res,
+                binop(Iop_Or32, mkexpr(irt_hi), mkexpr(irt_low))
+         );
+         putIRegA(rD, mkexpr(irt_res), condT, Ijk_Boring);
+         DIP("revsh%s r%u, r%u\n", nCC(INSN_COND), rD, rM);
+         goto decode_success;
+      }
+   }
+
    /* ------------------- rbit ------------------ */
    if (INSN(27,16) == 0x6FF && INSN(11,4) == 0xF3) {
       UInt rD = INSN(15,12);
@@ -16386,6 +17374,35 @@ DisResult disInstr_THUMB_WRK (
       goto decode_success;
    }
 
+   case 0x2EB: { // REVSH
+      /* ---------------- REVSH Rd, Rn ---------------- */
+      UInt rM = INSN0(5,3);
+      UInt rD = INSN0(2,0);
+      IRTemp irt_rM  = newTemp(Ity_I32);
+      IRTemp irt_hi  = newTemp(Ity_I32);
+      IRTemp irt_low = newTemp(Ity_I32);
+      IRTemp irt_res = newTemp(Ity_I32);
+      assign(irt_rM, getIRegT(rM));
+      assign(irt_hi,
+             binop(Iop_Sar32,
+                   binop(Iop_Shl32, mkexpr(irt_rM), mkU8(24)),
+                   mkU8(16)
+             )
+      );
+      assign(irt_low,
+             binop(Iop_And32,
+                   binop(Iop_Shr32, mkexpr(irt_rM), mkU8(8)),
+                   mkU32(0xFF)
+             )
+      );
+      assign(irt_res,
+             binop(Iop_Or32, mkexpr(irt_hi), mkexpr(irt_low))
+      );
+      putIRegT(rD, mkexpr(irt_res), condT);
+      DIP("revsh r%u, r%u\n", rD, rM);
+      goto decode_success;
+   }
+
    default:
       break; /* examine the next shortest prefix */
 
@@ -19463,6 +20480,40 @@ DisResult disInstr_THUMB_WRK (
       }
    }
 
+   /* ------------------- (T2) REVSH ------------------ */
+   if (INSN0(15,4) == 0xFA9
+       && INSN1(15,12) == BITS4(1,1,1,1)
+       && INSN1(7,4) == BITS4(1,0,1,1)) {
+      UInt rM1 = INSN0(3,0);
+      UInt rM2 = INSN1(3,0);
+      UInt rD  = INSN1(11,8);
+      if (!isBadRegT(rD) && !isBadRegT(rM1) && rM1 == rM2) {
+         IRTemp irt_rM  = newTemp(Ity_I32);
+         IRTemp irt_hi  = newTemp(Ity_I32);
+         IRTemp irt_low = newTemp(Ity_I32);
+         IRTemp irt_res = newTemp(Ity_I32);
+         assign(irt_rM, getIRegT(rM1));
+         assign(irt_hi,
+                binop(Iop_Sar32,
+                      binop(Iop_Shl32, mkexpr(irt_rM), mkU8(24)),
+                      mkU8(16)
+                )
+         );
+         assign(irt_low,
+                binop(Iop_And32,
+                      binop(Iop_Shr32, mkexpr(irt_rM), mkU8(8)),
+                      mkU32(0xFF)
+                )
+         );
+         assign(irt_res,
+                binop(Iop_Or32, mkexpr(irt_hi), mkexpr(irt_low))
+         );
+         putIRegT(rD, mkexpr(irt_res), condT);
+         DIP("revsh r%u, r%u\n", rD, rM1);
+         goto decode_success;
+      }
+   }
+
    /* -------------- (T1) MSR apsr, reg -------------- */
    if (INSN0(15,4) == 0xF38 
        && INSN1(15,12) == BITS4(1,0,0,0) && INSN1(9,0) == 0x000) {
index 1068ff0648cc8d3ee5223e649cc967469769d98b..0f1539e6b1f4f02d555a31a1af953ccd3162dd44 100644 (file)
@@ -1344,6 +1344,8 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
             fn = &h_generic_calc_HSub16Sx2; break;
          case Iop_QAdd16Sx2:
             fn = &h_generic_calc_QAdd16Sx2; break;
+         case Iop_QAdd16Ux2:
+            fn = &h_generic_calc_QAdd16Ux2; break;
          case Iop_QSub16Sx2:
             fn = &h_generic_calc_QSub16Sx2; break;
          case Iop_Add8x4: