[llvm] 8b4afc5 - [APInt] Add a concat method, use LLVM_UNLIKELY to help optimizer.

Chris Lattner via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 13 22:02:58 PDT 2021


Author: Chris Lattner
Date: 2021-09-13T22:02:54-07:00
New Revision: 8b4afc5aef148aff26047ca7bad4cdcf58c35e25

URL: https://github.com/llvm/llvm-project/commit/8b4afc5aef148aff26047ca7bad4cdcf58c35e25
DIFF: https://github.com/llvm/llvm-project/commit/8b4afc5aef148aff26047ca7bad4cdcf58c35e25.diff

LOG: [APInt] Add a concat method, use LLVM_UNLIKELY to help optimizer.

Three unrelated changes:

1) Add a concat method as a convenience to help write bitvector
   use cases in a nicer way.
2) Use LLVM_UNLIKELY as suggested by @xbolva00 in a previous patch.
3) Fix casing of some "slow" methods to follow naming standards.

Differential Revision: https://reviews.llvm.org/D109620

Added: 
    

Modified: 
    llvm/include/llvm/ADT/APInt.h
    llvm/lib/Support/APInt.cpp
    llvm/unittests/ADT/APIntTest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h
index e00709a54465f..03f244a67fae8 100644
--- a/llvm/include/llvm/ADT/APInt.h
+++ b/llvm/include/llvm/ADT/APInt.h
@@ -348,9 +348,10 @@ class LLVM_NODISCARD APInt {
   /// Determine if all bits are set.
   bool isAllOnes() const {
     if (isSingleWord()) {
-      if (BitWidth == 0)
-        return false;
-      return U.VAL == WORDTYPE_MAX >> (APINT_BITS_PER_WORD - BitWidth);
+      // Calculate the shift amount, handling the zero-bit wide case without UB.
+      unsigned ShiftAmt =
+          (APINT_BITS_PER_WORD - BitWidth) % APINT_BITS_PER_WORD;
+      return U.VAL == WORDTYPE_MAX >> ShiftAmt;
     }
     return countTrailingOnesSlowCase() == BitWidth;
   }
@@ -580,7 +581,7 @@ class LLVM_NODISCARD APInt {
       return *this;
     }
 
-    AssignSlowCase(RHS);
+    assignSlowCase(RHS);
     return *this;
   }
 
@@ -632,7 +633,7 @@ class LLVM_NODISCARD APInt {
     if (isSingleWord())
       U.VAL &= RHS.U.VAL;
     else
-      AndAssignSlowCase(RHS);
+      andAssignSlowCase(RHS);
     return *this;
   }
 
@@ -662,7 +663,7 @@ class LLVM_NODISCARD APInt {
     if (isSingleWord())
       U.VAL |= RHS.U.VAL;
     else
-      OrAssignSlowCase(RHS);
+      orAssignSlowCase(RHS);
     return *this;
   }
 
@@ -691,7 +692,7 @@ class LLVM_NODISCARD APInt {
     if (isSingleWord())
       U.VAL ^= RHS.U.VAL;
     else
-      XorAssignSlowCase(RHS);
+      xorAssignSlowCase(RHS);
     return *this;
   }
 
@@ -877,6 +878,17 @@ class LLVM_NODISCARD APInt {
   /// Rotate right by rotateAmt.
   APInt rotr(const APInt &rotateAmt) const;
 
+  /// Concatenate the bits from "NewLSB" onto the bottom of *this.  This is
+  /// equivalent to:
+  ///   (this->zext(NewWidth) << NewLSB.getBitWidth()) | NewLSB.zext(NewWidth)
+  APInt concat(const APInt &NewLSB) const {
+    /// If the result will be small, then both the merged values are small.
+    unsigned NewWidth = getBitWidth() + NewLSB.getBitWidth();
+    if (NewWidth <= APINT_BITS_PER_WORD)
+      return APInt(NewWidth, (U.VAL << NewLSB.getBitWidth()) | NewLSB.U.VAL);
+    return concatSlowCase(NewLSB);
+  }
+
   /// Unsigned division operation.
   ///
   /// Perform an unsigned divide operation on this APInt by RHS. Both this and
@@ -971,7 +983,7 @@ class LLVM_NODISCARD APInt {
     assert(BitWidth == RHS.BitWidth && "Comparison requires equal bit widths");
     if (isSingleWord())
       return U.VAL == RHS.U.VAL;
-    return EqualSlowCase(RHS);
+    return equalSlowCase(RHS);
   }
 
   /// Equality operator.
@@ -1491,7 +1503,7 @@ class LLVM_NODISCARD APInt {
   /// of 1 bits from the most significant to the least
   unsigned countLeadingOnes() const {
     if (isSingleWord()) {
-      if (BitWidth == 0)
+      if (LLVM_UNLIKELY(BitWidth == 0))
         return 0;
       return llvm::countLeadingOnes(U.VAL << (APINT_BITS_PER_WORD - BitWidth));
     }
@@ -1799,7 +1811,6 @@ class LLVM_NODISCARD APInt {
   unsigned BitWidth; ///< The number of bits in this APInt.
 
   friend struct DenseMapInfo<APInt>;
-
   friend class APSInt;
 
   /// This constructor is used only internally for speed of construction of
@@ -1841,7 +1852,7 @@ class LLVM_NODISCARD APInt {
 
     // Mask out the high bits.
     uint64_t mask = WORDTYPE_MAX >> (APINT_BITS_PER_WORD - WordBits);
-    if (BitWidth == 0)
+    if (LLVM_UNLIKELY(BitWidth == 0))
       mask = 0;
 
     if (isSingleWord())
@@ -1905,10 +1916,10 @@ class LLVM_NODISCARD APInt {
   void ashrSlowCase(unsigned ShiftAmt);
 
   /// out-of-line slow case for operator=
-  void AssignSlowCase(const APInt &RHS);
+  void assignSlowCase(const APInt &RHS);
 
   /// out-of-line slow case for operator==
-  bool EqualSlowCase(const APInt &RHS) const LLVM_READONLY;
+  bool equalSlowCase(const APInt &RHS) const LLVM_READONLY;
 
   /// out-of-line slow case for countLeadingZeros
   unsigned countLeadingZerosSlowCase() const LLVM_READONLY;
@@ -1937,14 +1948,17 @@ class LLVM_NODISCARD APInt {
   /// out-of-line slow case for flipAllBits.
   void flipAllBitsSlowCase();
 
+  /// out-of-line slow case for concat.
+  APInt concatSlowCase(const APInt &NewLSB) const;
+
   /// out-of-line slow case for operator&=.
-  void AndAssignSlowCase(const APInt &RHS);
+  void andAssignSlowCase(const APInt &RHS);
 
   /// out-of-line slow case for operator|=.
-  void OrAssignSlowCase(const APInt &RHS);
+  void orAssignSlowCase(const APInt &RHS);
 
   /// out-of-line slow case for operator^=.
-  void XorAssignSlowCase(const APInt &RHS);
+  void xorAssignSlowCase(const APInt &RHS);
 
   /// Unsigned comparison. Returns -1, 0, or 1 if this APInt is less than, equal
   /// to, or greater than RHS.

diff  --git a/llvm/lib/Support/APInt.cpp b/llvm/lib/Support/APInt.cpp
index a630050c0157a..d64ee053dc467 100644
--- a/llvm/lib/Support/APInt.cpp
+++ b/llvm/lib/Support/APInt.cpp
@@ -137,7 +137,7 @@ void APInt::reallocate(unsigned NewBitWidth) {
     U.pVal = getMemory(getNumWords());
 }
 
-void APInt::AssignSlowCase(const APInt& RHS) {
+void APInt::assignSlowCase(const APInt &RHS) {
   // Don't do anything for X = X
   if (this == &RHS)
     return;
@@ -235,19 +235,19 @@ APInt APInt::operator*(const APInt& RHS) const {
   return Result;
 }
 
-void APInt::AndAssignSlowCase(const APInt &RHS) {
+void APInt::andAssignSlowCase(const APInt &RHS) {
   WordType *dst = U.pVal, *rhs = RHS.U.pVal;
   for (size_t i = 0, e = getNumWords(); i != e; ++i)
     dst[i] &= rhs[i];
 }
 
-void APInt::OrAssignSlowCase(const APInt &RHS) {
+void APInt::orAssignSlowCase(const APInt &RHS) {
   WordType *dst = U.pVal, *rhs = RHS.U.pVal;
   for (size_t i = 0, e = getNumWords(); i != e; ++i)
     dst[i] |= rhs[i];
 }
 
-void APInt::XorAssignSlowCase(const APInt &RHS) {
+void APInt::xorAssignSlowCase(const APInt &RHS) {
   WordType *dst = U.pVal, *rhs = RHS.U.pVal;
   for (size_t i = 0, e = getNumWords(); i != e; ++i)
     dst[i] ^= rhs[i];
@@ -268,7 +268,7 @@ APInt& APInt::operator*=(uint64_t RHS) {
   return clearUnusedBits();
 }
 
-bool APInt::EqualSlowCase(const APInt& RHS) const {
+bool APInt::equalSlowCase(const APInt &RHS) const {
   return std::equal(U.pVal, U.pVal + getNumWords(), RHS.U.pVal);
 }
 
@@ -339,6 +339,17 @@ void APInt::flipAllBitsSlowCase() {
   clearUnusedBits();
 }
 
+/// Concatenate the bits from "NewLSB" onto the bottom of *this.  This is
+/// equivalent to:
+///   (this->zext(NewWidth) << NewLSB.getBitWidth()) | NewLSB.zext(NewWidth)
+/// In the slow case, we know the result is large.
+APInt APInt::concatSlowCase(const APInt &NewLSB) const {
+  unsigned NewWidth = getBitWidth() + NewLSB.getBitWidth();
+  APInt Result = NewLSB.zext(NewWidth);
+  Result.insertBits(*this, NewLSB.getBitWidth());
+  return Result;
+}
+
 /// Toggle a given bit to its opposite value whose position is given
 /// as "bitPosition".
 /// Toggles a given bit to its opposite value.
@@ -1064,7 +1075,7 @@ void APInt::shlSlowCase(unsigned ShiftAmt) {
 
 // Calculate the rotate amount modulo the bit width.
 static unsigned rotateModulo(unsigned BitWidth, const APInt &rotateAmt) {
-  if (BitWidth == 0)
+  if (LLVM_UNLIKELY(BitWidth == 0))
     return 0;
   unsigned rotBitWidth = rotateAmt.getBitWidth();
   APInt rot = rotateAmt;
@@ -1082,7 +1093,7 @@ APInt APInt::rotl(const APInt &rotateAmt) const {
 }
 
 APInt APInt::rotl(unsigned rotateAmt) const {
-  if (BitWidth == 0)
+  if (LLVM_UNLIKELY(BitWidth == 0))
     return *this;
   rotateAmt %= BitWidth;
   if (rotateAmt == 0)

diff  --git a/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp
index 6da9d2ddeb993..fe7a231d33fe2 100644
--- a/llvm/unittests/ADT/APIntTest.cpp
+++ b/llvm/unittests/ADT/APIntTest.cpp
@@ -2587,6 +2587,18 @@ TEST(APIntTest, truncOrSelf) {
   EXPECT_EQ(0xFFFFFFFF, val.truncOrSelf(64));
 }
 
+TEST(APIntTest, concatMSB) {
+  APInt Int1(4, 0x1ULL);
+  APInt Int3(4, 0x3ULL);
+
+  EXPECT_EQ(0x31, Int3.concat(Int1));
+  EXPECT_EQ(APInt(12, 0x313), Int3.concat(Int1).concat(Int3));
+  EXPECT_EQ(APInt(16, 0x3313), Int3.concat(Int3).concat(Int1).concat(Int3));
+
+  APInt I64(64, 0x3ULL);
+  EXPECT_EQ(I64, I64.concat(I64).lshr(64).trunc(64));
+}
+
 TEST(APIntTest, multiply) {
   APInt i64(64, 1234);
 


        


More information about the llvm-commits mailing list