[APInt] Add an isSplat helper and use it in some places.
authorBenjamin Kramer <benny.kra@googlemail.com>
Wed, 25 Mar 2015 16:49:59 +0000 (16:49 +0000)
committerBenjamin Kramer <benny.kra@googlemail.com>
Wed, 25 Mar 2015 16:49:59 +0000 (16:49 +0000)
To complement getSplat. This is more general than the binary
decomposition method as it also handles non-pow2 splat sizes.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@233195 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/ADT/APInt.h
lib/Analysis/ValueTracking.cpp
lib/Support/APInt.cpp
lib/Target/PowerPC/PPCISelLowering.cpp
unittests/ADT/APIntTest.cpp

index 838c59dd617bf8a5c26f584afcef7fc76c9a67d5..36d8159d21ba08be1219911660033a66634264a6 100644 (file)
@@ -407,6 +407,13 @@ public:
                                                             : getZExtValue();
   }
 
+  /// \brief Check if the APInt consists of a repeated bit pattern.
+  ///
+  /// e.g. 0x01010101 satisfies isSplat(8).
+  /// \param SplatSizeInBits The size of the pattern in bits. Must divide bit
+  /// width without remainder.
+  bool isSplat(unsigned SplatSizeInBits) const;
+
   /// @}
   /// \name Value Generators
   /// @{
index 0c66dab3267ddc77187cfbb848b502069b177a60..67627a35ba8dd43419bef7e7a02b19c0079a11ec 100644 (file)
@@ -2348,9 +2348,7 @@ Value *llvm::isBytewiseValue(Value *V) {
     if (CI->getBitWidth() % 8 == 0) {
       assert(CI->getBitWidth() > 8 && "8 bits should be handled above!");
 
-      // We can check that all bytes of an integer are equal by making use of a
-      // little trick: rotate by 8 and check if it's still the same value.
-      if (CI->getValue() != CI->getValue().rotl(8))
+      if (!CI->getValue().isSplat(8))
         return nullptr;
       return ConstantInt::get(V->getContext(), CI->getValue().trunc(8));
     }
index dc8a6525c8bac0e4396c2f12ee4ed2105e88d0b0..23337bebab10a9af80eec7022e3bc4ddef4f6f39 100644 (file)
@@ -672,6 +672,14 @@ hash_code llvm::hash_value(const APInt &Arg) {
   return hash_combine_range(Arg.pVal, Arg.pVal + Arg.getNumWords());
 }
 
+bool APInt::isSplat(unsigned SplatSizeInBits) const {
+  assert(getBitWidth() % SplatSizeInBits == 0 &&
+         "SplatSizeInBits must divide width!");
+  // We can check that all parts of an integer are equal by making use of a
+  // little trick: rotate and check if it's still the same value.
+  return *this == rotl(SplatSizeInBits);
+}
+
 /// HiBits - This function returns the high "numBits" bits of this APInt.
 APInt APInt::getHiBits(unsigned numBits) const {
   return APIntOps::lshr(*this, BitWidth - numBits);
index ff5a0d5afbd1e5ea92b0219a252c736a0b374e44..c35ab7a49b111b9d3413567427c1d8e044b14c9d 100644 (file)
@@ -1403,17 +1403,10 @@ SDValue PPC::get_VSPLTI_elt(SDNode *N, unsigned ByteSize, SelectionDAG &DAG) {
   // immediate field for would be zero, and we prefer to use vxor for it.
   if (ValSizeInBytes < ByteSize) return SDValue();
 
-  // If the element value is larger than the splat value, cut it in half and
-  // check to see if the two halves are equal.  Continue doing this until we
-  // get to ByteSize.  This allows us to handle 0x01010101 as 0x01.
-  while (ValSizeInBytes > ByteSize) {
-    ValSizeInBytes >>= 1;
-
-    // If the top half equals the bottom half, we're still ok.
-    if (((Value >> (ValSizeInBytes*8)) & ((1 << (8*ValSizeInBytes))-1)) !=
-         (Value                        & ((1 << (8*ValSizeInBytes))-1)))
-      return SDValue();
-  }
+  // If the element value is larger than the splat value, check if it consists
+  // of a repeated bit pattern of size ByteSize.
+  if (!APInt(ValSizeInBytes * 8, Value).isSplat(ByteSize * 8))
+    return SDValue();
 
   // Properly sign extend the value.
   int MaskVal = SignExtend32(Value, ByteSize * 8);
index 3b7ac5b89402960959415bde6dfb4328a427dd6b..96fa0ddbeaec896782cc15ec6a90a0dd7586fbc8 100644 (file)
@@ -678,6 +678,46 @@ TEST(APIntTest, nearestLogBase2) {
   EXPECT_EQ(A9.nearestLogBase2(), UINT32_MAX);
 }
 
+TEST(APIntTest, IsSplat) {
+  APInt A(32, 0x01010101);
+  EXPECT_FALSE(A.isSplat(1));
+  EXPECT_FALSE(A.isSplat(2));
+  EXPECT_FALSE(A.isSplat(4));
+  EXPECT_TRUE(A.isSplat(8));
+  EXPECT_TRUE(A.isSplat(16));
+  EXPECT_TRUE(A.isSplat(32));
+
+  APInt B(24, 0xAAAAAA);
+  EXPECT_FALSE(B.isSplat(1));
+  EXPECT_TRUE(B.isSplat(2));
+  EXPECT_TRUE(B.isSplat(4));
+  EXPECT_TRUE(B.isSplat(8));
+  EXPECT_TRUE(B.isSplat(24));
+
+  APInt C(24, 0xABAAAB);
+  EXPECT_FALSE(C.isSplat(1));
+  EXPECT_FALSE(C.isSplat(2));
+  EXPECT_FALSE(C.isSplat(4));
+  EXPECT_FALSE(C.isSplat(8));
+  EXPECT_TRUE(C.isSplat(24));
+
+  APInt D(32, 0xABBAABBA);
+  EXPECT_FALSE(D.isSplat(1));
+  EXPECT_FALSE(D.isSplat(2));
+  EXPECT_FALSE(D.isSplat(4));
+  EXPECT_FALSE(D.isSplat(8));
+  EXPECT_TRUE(D.isSplat(16));
+  EXPECT_TRUE(D.isSplat(32));
+
+  APInt E(32, 0);
+  EXPECT_TRUE(E.isSplat(1));
+  EXPECT_TRUE(E.isSplat(2));
+  EXPECT_TRUE(E.isSplat(4));
+  EXPECT_TRUE(E.isSplat(8));
+  EXPECT_TRUE(E.isSplat(16));
+  EXPECT_TRUE(E.isSplat(32));
+}
+
 #if defined(__clang__)
 // Disable the pragma warning from versions of Clang without -Wself-move
 #pragma clang diagnostic push