]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
PPC64, fix for vrlwnm, vrlwmi, vrldrm, vrldmi instructions.
authorCarl Love <carll@us.ibm.com>
Fri, 22 Mar 2019 17:50:52 +0000 (12:50 -0500)
committerCarl Love <carll@us.ibm.com>
Fri, 22 Mar 2019 17:50:52 +0000 (12:50 -0500)
Fixes the case where the specified end bit is less then the start bit.

Valgrind bug 405734

NEWS
VEX/priv/guest_ppc_toIR.c

diff --git a/NEWS b/NEWS
index c2a78482f6ae4b4f9aac3f6b2497d9530f4e18b3..bf90093c59ea107365d89253ac0acbfb6dcd654c 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -119,7 +119,9 @@ where XXXXXX is the bug number as listed below.
 405363  PPC64, xvcvdpsxws, xvcvdpuxws, do not handle NaN arguments correctly.
 405365  PPC64, function _get_maxmin_fp_NaN() doesn't handle QNaN, SNaN case
         correctly.
-405733  PPC64, xvcvdpsp should write 32-bit result to upper and lower 32-bits of the 64-bit destination field.
+405733  PPC64, xvcvdpsp should write 32-bit result to upper and lower 32-bits
+        of the 64-bit destination field.
+405734  PPC64, vrlwnm, vrlwmi, vrldrm, vrldmi do not work properly when me < mb
 
 n-i-bz  add syswrap for PTRACE_GET|SET_THREAD_AREA on amd64.
 n-i-bz  Fix callgrind_annotate non deterministic order for equal total
index 9bc7c3bf7c5fa0b4254805d61bdde044f3d1aba6..ab14cf87eadb6888c89d17f2694f9a948fdf0784 100644 (file)
@@ -15619,8 +15619,12 @@ static Bool dis_av_rotate ( UInt theInstr )
    IRTemp vA_word[4];
    IRTemp left_bits[4];
    IRTemp right_bits[4];
+   IRTemp mb[4];
+   IRTemp me[4];
    IRTemp shift[4];
    IRTemp mask[4];
+   IRTemp tmp_mask[4];
+   IRTemp invert_mask[4];
    IRTemp tmp128[4];
    UInt i;
    UInt num_words;
@@ -15664,7 +15668,11 @@ static Bool dis_av_rotate ( UInt theInstr )
       left_bits[i]  = newTemp( Ity_I8 );
       right_bits[i] = newTemp( Ity_I8 );
       shift[i] = newTemp( Ity_I8 );
-      mask[i]  = newTemp( Ity_V128 );
+      mb[i] = newTemp( Ity_I64 );
+      me[i] = newTemp( Ity_I64 );
+      tmp_mask[i] = newTemp( Ity_I64 );
+      invert_mask[i] = newTemp( Ity_I64 );
+      mask[i] = newTemp( Ity_V128 );
       tmp128[i] = newTemp( Ity_V128 );
       vA_word[i] = newTemp( Ity_V128 );
 
@@ -15678,50 +15686,90 @@ static Bool dis_av_rotate ( UInt theInstr )
                                               * word_size ) ),
                                  mkexpr( field_mask ) ) ) ) );
 
+      assign( mb[i], unop( Iop_V128to64,
+                           binop( Iop_AndV128,
+                                  binop( Iop_ShrV128,
+                                         mkexpr( vB ),
+                                         mkU8( ( num_words - 1 - i )
+                                               * word_size + 16 ) ),
+                                  mkexpr( field_mask ) ) ) );
+
+      assign( me[i], unop( Iop_V128to64,
+                           binop( Iop_AndV128,
+                                  binop( Iop_ShrV128,
+                                         mkexpr( vB ),
+                                         mkU8( ( num_words - 1 - i )
+                                               * word_size + 8 ) ),
+                                  mkexpr( field_mask ) ) ) );
+
+      /* If me < mb, we have to flip things around and invert the mask */
+      assign( invert_mask[i],
+              unop( Iop_1Sto64, binop( Iop_CmpLT64U,
+                                       mkexpr( me[i] ), mkexpr( mb[i] ) ) ) );
+
       /* left_bits = 63 - mb.  Tells us how many bits to the left
        * of mb to clear. Note for a word left_bits = 32+mb, for a double
        * word left_bits = mb
        */
       assign( left_bits[i],
               unop( Iop_64to8,
-                    binop( Iop_Add64,
-                           mkU64( 64 - word_size ),
-                           unop( Iop_V128to64,
-                                 binop( Iop_AndV128,
-                                        binop( Iop_ShrV128,
-                                               mkexpr( vB ),
-                                               mkU8( ( num_words - 1 - i )
-                                                     * word_size + 16 ) ),
-                                        mkexpr( field_mask ) ) ) ) ) );
+                    binop( Iop_Or64,
+                           binop( Iop_And64,     // mb < me
+                                  unop( Iop_Not64, mkexpr( invert_mask[i] ) ),
+                                  binop( Iop_Add64,
+                                         mkU64( 64 - word_size ),
+                                         mkexpr( mb[i] ) ) ),
+                           binop( Iop_And64,     // me < mb
+                                  mkexpr( invert_mask[i] ),
+                                  binop( Iop_Add64,
+                                         mkU64( 64 + 1 - word_size ),
+                                         mkexpr( me[i] ) ) ) ) ) );
+
       /* right_bits = 63 - me.  Tells us how many bits to the right
        * of me to clear. Note for a word, left_bits = me+32, for a double
        * word left_bits = me
        */
       assign( right_bits[i],
               unop( Iop_64to8,
-                    binop( Iop_Sub64,
-                           mkU64( word_size - 1 ),
-                           unop( Iop_V128to64,
-                                 binop( Iop_AndV128,
-                                        binop( Iop_ShrV128,
-                                               mkexpr( vB ),
-                                               mkU8( ( num_words - 1 - i )
-                                                     * word_size + 8 ) ),
-                                        mkexpr( field_mask ) ) ) ) ) );
+                    binop( Iop_Or64,
+                           binop( Iop_And64,   // mb < me
+                                  unop( Iop_Not64, mkexpr( invert_mask[i] ) ),
+                                  binop( Iop_Sub64,
+                                         mkU64( word_size - 1 ),
+                                         mkexpr( me[i] ) ) ),
+                           binop( Iop_And64,   // me < mb
+                                  mkexpr( invert_mask[i] ),
+                                  binop( Iop_Sub64,
+                                         mkU64( word_size - 1 + 1),
+                                         mkexpr( mb[i] ) ) ) ) ) );
 
       /* create mask for 32-bit word or 64-bit word */
+      assign( tmp_mask[i],
+              binop( Iop_Shl64,
+                     binop( Iop_Shr64,
+                            binop( Iop_Shr64,
+                                   binop( Iop_Shl64,
+                                          mkU64( 0xFFFFFFFFFFFFFFFF ),
+                                          mkexpr( left_bits[i] ) ),
+                                   mkexpr( left_bits[i] ) ),
+                            mkexpr( right_bits[i] ) ),
+                     mkexpr( right_bits[i] ) ) );
+
       assign( mask[i],
               binop( Iop_64HLtoV128,
                      mkU64( 0 ),
-                     binop( Iop_Shl64,
-                            binop( Iop_Shr64,
-                                   binop( Iop_Shr64,
-                                          binop( Iop_Shl64,
-                                                 mkU64( 0xFFFFFFFFFFFFFFFF ),
-                                                 mkexpr( left_bits[i] ) ),
-                                          mkexpr( left_bits[i] ) ),
-                                   mkexpr( right_bits[i] ) ),
-                            mkexpr( right_bits[i] ) ) ) );
+                     binop( Iop_Or64,
+                            binop( Iop_And64,
+                                   unop( Iop_Not64, mkexpr( invert_mask[i] ) ),
+                                   mkexpr( tmp_mask[i] ) ),
+                            binop( Iop_And64,
+                                   mkexpr( invert_mask[i] ),
+                                   /* Need to make sure mask is only the size
+                                      desired word.*/
+                                   binop( Iop_And64,
+                                          mkU64( word_mask ),
+                                          unop( Iop_Not64,
+                                                mkexpr( tmp_mask[i] ) ) ) ))));
 
       /* Need to rotate vA using a left and right shift of vA OR'd together
        * then ANDed with the mask.
@@ -15750,7 +15798,7 @@ static Bool dis_av_rotate ( UInt theInstr )
                                                mkU32( word_size ),
                                                unop( Iop_8Uto32,
                                                      mkexpr( shift[i] ) ) )
-                                         ) ) ) ) );
+                                      ) ) ) ) );
    }
 
    switch (opc2) {