From: Benjamin Kramer Date: Wed, 25 Mar 2015 16:49:59 +0000 (+0000) Subject: [APInt] Add an isSplat helper and use it in some places. X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=eaf3cbd89760215e1e9bc6979eef68ba53320905;p=oota-llvm.git [APInt] Add an isSplat helper and use it in some places. 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 --- diff --git a/include/llvm/ADT/APInt.h b/include/llvm/ADT/APInt.h index 838c59dd617..36d8159d21b 100644 --- a/include/llvm/ADT/APInt.h +++ b/include/llvm/ADT/APInt.h @@ -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 /// @{ diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index 0c66dab3267..67627a35ba8 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -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)); } diff --git a/lib/Support/APInt.cpp b/lib/Support/APInt.cpp index dc8a6525c8b..23337bebab1 100644 --- a/lib/Support/APInt.cpp +++ b/lib/Support/APInt.cpp @@ -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); diff --git a/lib/Target/PowerPC/PPCISelLowering.cpp b/lib/Target/PowerPC/PPCISelLowering.cpp index ff5a0d5afbd..c35ab7a49b1 100644 --- a/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/lib/Target/PowerPC/PPCISelLowering.cpp @@ -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); diff --git a/unittests/ADT/APIntTest.cpp b/unittests/ADT/APIntTest.cpp index 3b7ac5b8940..96fa0ddbeae 100644 --- a/unittests/ADT/APIntTest.cpp +++ b/unittests/ADT/APIntTest.cpp @@ -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