]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
putGST_masked: correctly handle the case where the mask is for
authorJulian Seward <jseward@acm.org>
Wed, 20 Aug 2014 08:54:06 +0000 (08:54 +0000)
committerJulian Seward <jseward@acm.org>
Wed, 20 Aug 2014 08:54:06 +0000 (08:54 +0000)
FPSCR.RN or FPSCR.DRN, but does not cover the entire field.  Then it
is important to update the exposed parts but leave the not-exposed
parts unchanged.  This is a regression relative to circa 5 years ago.

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

VEX/priv/guest_ppc_toIR.c

index b561de28efc90e2786e6bd3d3f6f5cd06a33a27d..fc289ed9bdb2745a8e748951d42f52a7d8cfa1cb 100644 (file)
@@ -2933,21 +2933,59 @@ static void putGST_masked ( PPC_GST reg, IRExpr* src, ULong mask )
    switch (reg) {
    case PPC_GST_FPSCR: {
       /* Allow writes to either binary or decimal floating point
-       * Rounding Mode
-       */
+         Rounding Mode.
+      */
+      /* If any part of |mask| covers FPSCR.RN, update the bits of
+         FPSCR.RN by copying in |src| for locations where the
+         corresponding bit in |mask| is 1, and leaving it unchanged
+         for corresponding |mask| zero bits. */
       if (mask & MASK_FPSCR_RN) {
-         stmt( IRStmt_Put( OFFB_FPROUND,
-                           unop( Iop_32to8,
-                                 binop( Iop_And32,
-                                        unop( Iop_64to32, src ),
-                                        mkU32( MASK_FPSCR_RN & mask ) ) ) ) );
-      } else if (mask & MASK_FPSCR_DRN) {
-         stmt( IRStmt_Put( OFFB_DFPROUND,
-                           unop( Iop_32to8,
-                                 binop( Iop_And32,
-                                        unop( Iop_64HIto32, src ),
-                                        mkU32( ( MASK_FPSCR_DRN & mask )
-                                                 >> 32 ) ) ) ) );
+         stmt( 
+            IRStmt_Put(
+               OFFB_FPROUND,
+               unop(
+                  Iop_32to8,
+                  binop(
+                     Iop_Or32, 
+                     binop(
+                        Iop_And32,
+                        unop(Iop_64to32, src),
+                        mkU32(MASK_FPSCR_RN & mask)
+                     ),
+                     binop(
+                        Iop_And32, 
+                        unop(Iop_8Uto32, IRExpr_Get(OFFB_FPROUND,Ity_I8)),
+                        mkU32(MASK_FPSCR_RN & ~mask)
+                     )
+                  )
+               )
+            )
+         );
+      }
+      /* Similarly, update FPSCR.DRN if any bits of |mask|
+         corresponding to FPSCR.DRN are set. */
+      if (mask & MASK_FPSCR_DRN) {
+         stmt( 
+            IRStmt_Put(
+               OFFB_DFPROUND,
+               unop(
+                  Iop_32to8,
+                  binop(
+                     Iop_Or32, 
+                     binop(
+                        Iop_And32,
+                        unop(Iop_64HIto32, src),
+                        mkU32((MASK_FPSCR_DRN & mask) >> 32)
+                     ),
+                     binop(
+                        Iop_And32, 
+                        unop(Iop_8Uto32, IRExpr_Get(OFFB_DFPROUND,Ity_I8)),
+                        mkU32((MASK_FPSCR_DRN & ~mask) >> 32)
+                     )
+                  )
+               )
+            )
+         );
       }
 
       /* Give EmNote for attempted writes to: