llvm.org GIT mirror llvm / f238d27
[APInt] Optimize umul_ov Change two costly udiv() calls to lshr(1)*RHS + left-shift + plus On one 64-bit umul_ov benchmark, I measured an obvious improvement: 12.8129s -> 3.6257s Note, there may be some value to special case 64-bit (the most common case) with __builtin_umulll_overflow(). Differential Revision: https://reviews.llvm.org/D60669 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@358730 91177308-0d34-0410-b5e6-96231b3b80d8 Fangrui Song 4 months ago
2 changed file(s) with 49 addition(s) and 6 deletion(s). Raw diff Collapse all Expand all
19131913 }
19141914
19151915 APInt APInt::umul_ov(const APInt &RHS, bool &Overflow) const {
1916 APInt Res = *this * RHS;
1917
1918 if (*this != 0 && RHS != 0)
1919 Overflow = Res.udiv(RHS) != *this || Res.udiv(*this) != RHS;
1920 else
1921 Overflow = false;
1916 if (countLeadingZeros() + RHS.countLeadingZeros() + 2 <= BitWidth) {
1917 Overflow = true;
1918 return *this * RHS;
1919 }
1920
1921 APInt Res = lshr(1) * RHS;
1922 Overflow = Res.isNegative();
1923 Res <<= 1;
1924 if ((*this)[0]) {
1925 Res += RHS;
1926 if (Res.ult(RHS))
1927 Overflow = true;
1928 }
19221929 return Res;
19231930 }
19241931
23802380 }
23812381 }
23822382
2383 TEST(APIntTest, umul_ov) {
2384 const std::pair Overflows[] = {
2385 {0x8000000000000000, 2},
2386 {0x5555555555555556, 3},
2387 {4294967296, 4294967296},
2388 {4294967295, 4294967298},
2389 };
2390 const std::pair NonOverflows[] = {
2391 {0x7fffffffffffffff, 2},
2392 {0x5555555555555555, 3},
2393 {4294967295, 4294967297},
2394 };
2395
2396 bool Overflow;
2397 for (auto &X : Overflows) {
2398 APInt A(64, X.first);
2399 APInt B(64, X.second);
2400 (void)A.umul_ov(B, Overflow);
2401 EXPECT_TRUE(Overflow);
2402 }
2403 for (auto &X : NonOverflows) {
2404 APInt A(64, X.first);
2405 APInt B(64, X.second);
2406 (void)A.umul_ov(B, Overflow);
2407 EXPECT_FALSE(Overflow);
2408 }
2409
2410 for (unsigned Bits = 1; Bits <= 5; ++Bits)
2411 for (unsigned A = 0; A != 1u << Bits; ++A)
2412 for (unsigned B = 0; B != 1u << Bits; ++B) {
2413 APInt C = APInt(Bits, A).umul_ov(APInt(Bits, B), Overflow);
2414 APInt D = APInt(2 * Bits, A) * APInt(2 * Bits, B);
2415 EXPECT_TRUE(D.getHiBits(Bits).isNullValue() != Overflow);
2416 }
2417 }
2418
23832419 TEST(APIntTest, SolveQuadraticEquationWrap) {
23842420 // Verify that "Solution" is the first non-negative integer that solves
23852421 // Ax^2 + Bx + C = "0 or overflow", i.e. that it is a correct solution