[llvm] [ADT][APInt] add sfloordiv_ov APInt's member function (PR #84720)

via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 14 06:44:46 PDT 2024


https://github.com/lipracer updated https://github.com/llvm/llvm-project/pull/84720

>From 0db9531587eb1ea67c1c8886d1550ae1563a2073 Mon Sep 17 00:00:00 2001
From: lipracer <lipracer at gmail.com>
Date: Mon, 11 Mar 2024 13:10:43 +0800
Subject: [PATCH 1/4] [APInt] add sfloordiv_ov APInt's member function for mlir
 fold to avoid too many overflow state check

---
 llvm/include/llvm/ADT/APInt.h    |  1 +
 llvm/lib/Support/APInt.cpp       |  8 +++++++
 llvm/unittests/ADT/APIntTest.cpp | 38 ++++++++++++++++++++++++++++++++
 3 files changed, 47 insertions(+)

diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h
index b10e2107b794a3..b91aaa688013a9 100644
--- a/llvm/include/llvm/ADT/APInt.h
+++ b/llvm/include/llvm/ADT/APInt.h
@@ -996,6 +996,7 @@ class [[nodiscard]] APInt {
   APInt sshl_ov(unsigned Amt, bool &Overflow) const;
   APInt ushl_ov(const APInt &Amt, bool &Overflow) const;
   APInt ushl_ov(unsigned Amt, bool &Overflow) const;
+  APInt sfloordiv_ov(const APInt &RHS, bool &Overflow) const;
 
   // Operations that saturate
   APInt sadd_sat(const APInt &RHS) const;
diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp
index 7053f3b87682f8..8fad85b2d0bccb 100644
--- a/llvm/lib/Support/APInt.cpp
+++ b/llvm/lib/Support/APInt.cpp
@@ -2022,6 +2022,14 @@ APInt APInt::ushl_ov(unsigned ShAmt, bool &Overflow) const {
   return *this << ShAmt;
 }
 
+APInt APInt::sfloordiv_ov(const APInt &RHS, bool &Overflow) const {
+  auto quotient = sdiv_ov(RHS, Overflow);
+  if ((quotient * RHS != *this) && (isNegative() != RHS.isNegative()))
+    return quotient - 1;
+  else
+    return quotient;
+}
+
 APInt APInt::sadd_sat(const APInt &RHS) const {
   bool Overflow;
   APInt Res = sadd_ov(RHS, Overflow);
diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp
index 400313a6234677..749dd98efd260c 100644
--- a/llvm/unittests/ADT/APIntTest.cpp
+++ b/llvm/unittests/ADT/APIntTest.cpp
@@ -15,6 +15,7 @@
 #include "gtest/gtest.h"
 #include <array>
 #include <climits>
+#include <limits>
 #include <optional>
 
 using namespace llvm;
@@ -3048,6 +3049,43 @@ TEST(APIntTest, smul_ov) {
       }
 }
 
+TEST(APIntTest, sfloordiv_ov) {
+  // test negative quotient
+  {
+    APInt divisor(32, -3, true);
+    APInt dividend(32, 2, true);
+    bool Overflow = false;
+    auto quotient = divisor.sfloordiv_ov(dividend, Overflow);
+    EXPECT_FALSE(Overflow);
+    EXPECT_EQ(-2, quotient.getSExtValue());
+  }
+  // test positive quotient
+  {
+    APInt divisor(32, 3, true);
+    APInt dividend(32, 2, true);
+    bool Overflow = false;
+    auto quotient = divisor.sfloordiv_ov(dividend, Overflow);
+    EXPECT_FALSE(Overflow);
+    EXPECT_EQ(1, quotient.getSExtValue());
+  }
+  // test overflow
+  {
+    auto check_overflow_one = [](auto arg) {
+      using IntTy = decltype(arg);
+      APInt divisor(8 * sizeof(arg), std::numeric_limits<IntTy>::lowest(),
+                    true);
+      APInt dividend(8 * sizeof(arg), IntTy(-1), true);
+      bool Overflow = false;
+      [[maybe_unused]] auto quotient = divisor.sfloordiv_ov(dividend, Overflow);
+      EXPECT_TRUE(Overflow);
+    };
+    auto check_overflow_all = [&](auto... args) {
+      (void)std::initializer_list<int>{(check_overflow_one(args), 0)...};
+    };
+    std::apply(check_overflow_all, std::tuple<char, short, int, int64_t>());
+  }
+}
+
 TEST(APIntTest, SolveQuadraticEquationWrap) {
   // Verify that "Solution" is the first non-negative integer that solves
   // Ax^2 + Bx + C = "0 or overflow", i.e. that it is a correct solution

>From d1a2ea9b0434c3f979be17a2649a7f9e52efe7f8 Mon Sep 17 00:00:00 2001
From: lipracer <lipracer at gmail.com>
Date: Mon, 11 Mar 2024 14:29:16 +0800
Subject: [PATCH 2/4] refine

---
 llvm/lib/Support/APInt.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp
index 8fad85b2d0bccb..2f86c3932ab155 100644
--- a/llvm/lib/Support/APInt.cpp
+++ b/llvm/lib/Support/APInt.cpp
@@ -2026,8 +2026,7 @@ APInt APInt::sfloordiv_ov(const APInt &RHS, bool &Overflow) const {
   auto quotient = sdiv_ov(RHS, Overflow);
   if ((quotient * RHS != *this) && (isNegative() != RHS.isNegative()))
     return quotient - 1;
-  else
-    return quotient;
+  return quotient;
 }
 
 APInt APInt::sadd_sat(const APInt &RHS) const {

>From 199bf4232aeadc54c62596c0e5eafb13e7e01918 Mon Sep 17 00:00:00 2001
From: lipracer <lipracer at gmail.com>
Date: Thu, 14 Mar 2024 14:13:56 +0800
Subject: [PATCH 3/4] refine

---
 llvm/include/llvm/ADT/APInt.h    |  5 +++
 llvm/lib/Support/APInt.cpp       |  2 +-
 llvm/unittests/ADT/APIntTest.cpp | 76 ++++++++++++++++++++++++++------
 3 files changed, 68 insertions(+), 15 deletions(-)

diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h
index b91aaa688013a9..1abea9eb24a3c4 100644
--- a/llvm/include/llvm/ADT/APInt.h
+++ b/llvm/include/llvm/ADT/APInt.h
@@ -996,6 +996,11 @@ class [[nodiscard]] APInt {
   APInt sshl_ov(unsigned Amt, bool &Overflow) const;
   APInt ushl_ov(const APInt &Amt, bool &Overflow) const;
   APInt ushl_ov(unsigned Amt, bool &Overflow) const;
+
+  /// Signed integer floor division operation.
+  ///
+  /// Rounds towards negative infinity, i.e. 5 / -2 = -3. Iff minimum value
+  /// divided by -1 set Overflow to true.
   APInt sfloordiv_ov(const APInt &RHS, bool &Overflow) const;
 
   // Operations that saturate
diff --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp
index 2f86c3932ab155..fb7c45cece2970 100644
--- a/llvm/lib/Support/APInt.cpp
+++ b/llvm/lib/Support/APInt.cpp
@@ -2023,7 +2023,7 @@ APInt APInt::ushl_ov(unsigned ShAmt, bool &Overflow) const {
 }
 
 APInt APInt::sfloordiv_ov(const APInt &RHS, bool &Overflow) const {
-  auto quotient = sdiv_ov(RHS, Overflow);
+  APInt quotient = sdiv_ov(RHS, Overflow);
   if ((quotient * RHS != *this) && (isNegative() != RHS.isNegative()))
     return quotient - 1;
   return quotient;
diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp
index 749dd98efd260c..076a0c6fe24b05 100644
--- a/llvm/unittests/ADT/APIntTest.cpp
+++ b/llvm/unittests/ADT/APIntTest.cpp
@@ -3068,21 +3068,69 @@ TEST(APIntTest, sfloordiv_ov) {
     EXPECT_FALSE(Overflow);
     EXPECT_EQ(1, quotient.getSExtValue());
   }
-  // test overflow
+  // int8 test overflow
   {
-    auto check_overflow_one = [](auto arg) {
-      using IntTy = decltype(arg);
-      APInt divisor(8 * sizeof(arg), std::numeric_limits<IntTy>::lowest(),
-                    true);
-      APInt dividend(8 * sizeof(arg), IntTy(-1), true);
-      bool Overflow = false;
-      [[maybe_unused]] auto quotient = divisor.sfloordiv_ov(dividend, Overflow);
-      EXPECT_TRUE(Overflow);
-    };
-    auto check_overflow_all = [&](auto... args) {
-      (void)std::initializer_list<int>{(check_overflow_one(args), 0)...};
-    };
-    std::apply(check_overflow_all, std::tuple<char, short, int, int64_t>());
+    using IntTy = int8_t;
+    APInt divisor(8 * sizeof(IntTy), std::numeric_limits<IntTy>::lowest(),
+                  true);
+    APInt dividend(8 * sizeof(IntTy), IntTy(-1), true);
+    bool Overflow = false;
+    (void)divisor.sfloordiv_ov(dividend, Overflow);
+    EXPECT_TRUE(Overflow);
+  }
+  // int16 test overflow
+  {
+    using IntTy = int16_t;
+    APInt divisor(8 * sizeof(IntTy), std::numeric_limits<IntTy>::lowest(),
+                  true);
+    APInt dividend(8 * sizeof(IntTy), IntTy(-1), true);
+    bool Overflow = false;
+    (void)divisor.sfloordiv_ov(dividend, Overflow);
+    EXPECT_TRUE(Overflow);
+  }
+  // int32 test overflow
+  {
+    using IntTy = int32_t;
+    APInt divisor(8 * sizeof(IntTy), std::numeric_limits<IntTy>::lowest(),
+                  true);
+    APInt dividend(8 * sizeof(IntTy), IntTy(-1), true);
+    bool Overflow = false;
+    (void)divisor.sfloordiv_ov(dividend, Overflow);
+    EXPECT_TRUE(Overflow);
+  }
+  // int64 test overflow
+  {
+    using IntTy = int64_t;
+    APInt divisor(8 * sizeof(IntTy), std::numeric_limits<IntTy>::lowest(),
+                  true);
+    APInt dividend(8 * sizeof(IntTy), IntTy(-1), true);
+    bool Overflow = false;
+    (void)divisor.sfloordiv_ov(dividend, Overflow);
+    EXPECT_TRUE(Overflow);
+  }
+  // test all of int8
+  {
+    bool Overflow = true;
+    for (int i = -128; i < 128; ++i) {
+      for (int j = -128; j < 128; ++j) {
+        if (j == 0 || (i == -128 && j == -1))
+          continue;
+        int8_t a = static_cast<int8_t>(i);
+        int8_t b = static_cast<int8_t>(j);
+
+        APInt divisor(8, a, true);
+        APInt dividend(8, b, true);
+        if (((i >= 0 && j > 0) || (i <= 0 && j < 0)) ||
+            (i % j == 0)) // if quotient >= 0 and remain == 0 floordiv
+                          // equivalent to div
+          EXPECT_EQ(divisor.sfloordiv_ov(dividend, Overflow).getSExtValue(),
+                    a / b);
+        else
+          EXPECT_EQ(divisor.sfloordiv_ov(dividend, Overflow).getSExtValue(),
+                    a / b - 1);
+        EXPECT_FALSE(Overflow);
+      }
+    }
   }
 }
 

>From 91666309f53b9c0955447495bac38da2138cbfe2 Mon Sep 17 00:00:00 2001
From: lipracer <lipracer at gmail.com>
Date: Thu, 14 Mar 2024 21:49:26 +0800
Subject: [PATCH 4/4] remove redundant test case

---
 llvm/unittests/ADT/APIntTest.cpp | 46 +++++++++-----------------------
 1 file changed, 12 insertions(+), 34 deletions(-)

diff --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp
index 076a0c6fe24b05..6aec1049584bbe 100644
--- a/llvm/unittests/ADT/APIntTest.cpp
+++ b/llvm/unittests/ADT/APIntTest.cpp
@@ -3050,34 +3050,6 @@ TEST(APIntTest, smul_ov) {
 }
 
 TEST(APIntTest, sfloordiv_ov) {
-  // test negative quotient
-  {
-    APInt divisor(32, -3, true);
-    APInt dividend(32, 2, true);
-    bool Overflow = false;
-    auto quotient = divisor.sfloordiv_ov(dividend, Overflow);
-    EXPECT_FALSE(Overflow);
-    EXPECT_EQ(-2, quotient.getSExtValue());
-  }
-  // test positive quotient
-  {
-    APInt divisor(32, 3, true);
-    APInt dividend(32, 2, true);
-    bool Overflow = false;
-    auto quotient = divisor.sfloordiv_ov(dividend, Overflow);
-    EXPECT_FALSE(Overflow);
-    EXPECT_EQ(1, quotient.getSExtValue());
-  }
-  // int8 test overflow
-  {
-    using IntTy = int8_t;
-    APInt divisor(8 * sizeof(IntTy), std::numeric_limits<IntTy>::lowest(),
-                  true);
-    APInt dividend(8 * sizeof(IntTy), IntTy(-1), true);
-    bool Overflow = false;
-    (void)divisor.sfloordiv_ov(dividend, Overflow);
-    EXPECT_TRUE(Overflow);
-  }
   // int16 test overflow
   {
     using IntTy = int16_t;
@@ -3110,24 +3082,30 @@ TEST(APIntTest, sfloordiv_ov) {
   }
   // test all of int8
   {
-    bool Overflow = true;
+    bool Overflow = false;
     for (int i = -128; i < 128; ++i) {
       for (int j = -128; j < 128; ++j) {
-        if (j == 0 || (i == -128 && j == -1))
+        if (j == 0)
           continue;
+
         int8_t a = static_cast<int8_t>(i);
         int8_t b = static_cast<int8_t>(j);
 
         APInt divisor(8, a, true);
         APInt dividend(8, b, true);
+        APInt quotient = divisor.sfloordiv_ov(dividend, Overflow);
+
+        if (i == -128 && j == -1) {
+          EXPECT_TRUE(Overflow);
+          continue;
+        }
+
         if (((i >= 0 && j > 0) || (i <= 0 && j < 0)) ||
             (i % j == 0)) // if quotient >= 0 and remain == 0 floordiv
                           // equivalent to div
-          EXPECT_EQ(divisor.sfloordiv_ov(dividend, Overflow).getSExtValue(),
-                    a / b);
+          EXPECT_EQ(quotient.getSExtValue(), a / b);
         else
-          EXPECT_EQ(divisor.sfloordiv_ov(dividend, Overflow).getSExtValue(),
-                    a / b - 1);
+          EXPECT_EQ(quotient.getSExtValue(), a / b - 1);
         EXPECT_FALSE(Overflow);
       }
     }



More information about the llvm-commits mailing list