]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
iropt-test: Constant folding for DivModU32to32 and DivModS32to32
authorFlorian Krohm <flo2030@eich-krohm.de>
Sat, 30 Aug 2025 11:28:03 +0000 (11:28 +0000)
committerFlorian Krohm <flo2030@eich-krohm.de>
Sat, 30 Aug 2025 11:28:03 +0000 (11:28 +0000)
Needed for Mips. Mips is still disabled in iropt-test because there
are miscompares between the folded the result and the result computed
by the insn sequence that implements the IROp. Several IRops are affected.

Part of fixing https://bugs.kde.org/show_bug.cgi?id=506211

VEX/priv/ir_opt.c
none/tests/iropt-test/binary.c
none/tests/iropt-test/irops.tab
none/tests/iropt-test/main.c

index 5056b677bea8276e414357412a20866a2955e220..925524e15816932da3a68598913782e1f4806f9d 100644 (file)
@@ -2193,6 +2193,31 @@ static IRExpr* fold_Expr_WRK ( IRExpr** env, IRExpr* e )
                }
                break;
             }
+            case Iop_DivModU32to32: {
+               UInt u32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
+               UInt u32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
+               if (u32b != 0) {
+                  UInt q = u32a / u32b;
+                  UInt r = u32a % u32b;
+                  e2 = IRExpr_Const(IRConst_U64(((ULong)r << 32) | q));
+               }
+               break;
+            }
+            case Iop_DivModS32to32: {
+               Int s32a = e->Iex.Binop.arg1->Iex.Const.con->Ico.U32;
+               Int s32b = e->Iex.Binop.arg2->Iex.Const.con->Ico.U32;
+               if (s32b != 0) {
+                  /* Division may trap when result overflows i.e. when
+                     attempting: INT32_MAX / -1 */
+                  if (e->Iex.Binop.arg1->Iex.Const.con->Ico.U32 == (1UL << 31)
+                      && s32b == -1)
+                     break;
+                  Int q = s32a / s32b;
+                  Int r = s32a % s32b;
+                  e2 = IRExpr_Const(IRConst_U64(((ULong)(UInt)r << 32) | (UInt)q));
+               }
+               break;
+            }
 
             /* -- Shl -- */
             case Iop_Shl8:
index 1fbe1341fc994f2d1470f00f3952b7f8dd2274ad..d8d3618b290f14f0c11aa68cbc748d2df00911a9 100644 (file)
@@ -215,6 +215,20 @@ get_expected_value(const irop_t *op, const test_data_t *data)
       expected = (int64_t)(opnd_l << 32) / (int32_t)opnd_r;
       break;
 
+   case Iop_DivModU32to32: {
+      uint32_t q = opnd_l / opnd_r;
+      uint32_t r = opnd_l % opnd_r;
+      expected = ((uint64_t)r << 32) | q;
+      break;
+   }
+
+   case Iop_DivModS32to32: {
+      int32_t q = (int32_t)opnd_l / (int32_t)opnd_r;
+      int32_t r = (int32_t)opnd_l % (int32_t)opnd_r;
+      expected  = ((uint64_t)r << 32) | (uint32_t)q;
+      break;
+   }
+
    case Iop_DivModU64to32: {
       uint64_t q = opnd_l / opnd_r;
       uint64_t r = opnd_l % opnd_r;
@@ -424,6 +438,7 @@ ok_to_run(IROp op, uint64_t o1, uint64_t o2)
    case Iop_DivS32: case Iop_DivS64:
    case Iop_DivU32E:
    case Iop_DivS32E:
+   case Iop_DivModU32to32:
       return o2 != 0;
 
    /* Check that result can be represented */
@@ -448,6 +463,16 @@ ok_to_run(IROp op, uint64_t o1, uint64_t o2)
       return q <= INT32_MAX && q >= INT32_MIN;
    }
 
+   case Iop_DivModS32to32: {
+      int32_t divisor  = o2;
+
+      if (divisor == 0) return 0;
+      /* Division may trap on overflow */
+      if (divisor == -1 && o1 == (0x1UL << 31))  // INT32_MIN
+         return 0;
+      return 1;
+   }
+
    default:
       return 1;
    }
index 954654b7cdc74c441a9763371b2ca726f39e0c24..882ba59ba9eca93e9d5cea0a6b25ca49738e9f28 100644 (file)
 // { OPNAME(DivS64E),  Ity_I32,  2, Ity_I32,  Ity_I32, }, // 128 bit
 // { OPNAME(DivS128E), Ity_I128, 2, Ity_I128, Ity_I128 }, // 128 bit
 
-// { OPNAME(DivModU32to32),  Ity_I64,  2, Ity_I32, Ity_I64  }, // mips no folding yet
+   { OPNAME(DivModU32to32),  Ity_I64,  2, Ity_I32, Ity_I32, ONLY(mipsx) },
    { OPNAME(DivModU64to32),  Ity_I64,  2, Ity_I64, Ity_I32, EXCEPT2(ppc, mipsx) },
 // { OPNAME(DivModU64to64),  Ity_I64,  2, Ity_I64, Ity_I128 }, // 128 bit
 // { OPNAME(DivModU128to64), Ity_I128, 2, Ity_I64, Ity_I128 }, // 128 bit
 
-// { OPNAME(DivModS32to32),  Ity_I64,  2, Ity_I32, Ity_I32  }, // mips no folding yet
+   { OPNAME(DivModS32to32),  Ity_I64,  2, Ity_I32, Ity_I32, ONLY(mipsx) },
    { OPNAME(DivModS64to32),  Ity_I64,  2, Ity_I64, Ity_I32, EXCEPT2(ppc, mipsx) },
 // { OPNAME(DivModS64to64),  Ity_I64,  2, Ity_I64, Ity_I128 }, // 128 bit
 // { OPNAME(DivModU128to64), Ity_I128, 2, Ity_I64, Ity_I128 }, // 128 bit
index 1ca97e9c03e5d646154e6b59e7b041280650b41c..64ad44d87651cc902a711b76274acae04efda8b7 100644 (file)
@@ -45,7 +45,7 @@ unsigned num_random_tests;
 int
 main(int argc, char *argv[])
 {
-// FIXME: temporarily until ppc has been fixed
+// FIXME: temporarily until ppc and mips have been fixed
 #if !defined(__s390x__) && !defined(__i386__) && !defined(__x86_64__)
    return 0;
 #endif
@@ -164,6 +164,9 @@ is_enabled(const irop_t *op)
 #ifdef __s390x__
    return op->enabled_arch & ARCH_s390;
 #endif
+#ifdef __mips__
+   return op->enabled_arch & ((__mips == 64) ? ARCH_mips64 : ARCH_mips32);
+#endif
 #ifdef __powerpc__    /* defined for both 32-bit and 64-bit */
 #define  MIN_POWER_ISA  "../../../tests/min_power_isa"
    int rc;