diff --git a/llvm/include/llvm/Support/KnownBits.h b/llvm/include/llvm/Support/KnownBits.h --- a/llvm/include/llvm/Support/KnownBits.h +++ b/llvm/include/llvm/Support/KnownBits.h @@ -422,6 +422,14 @@ return KnownBits(Zero.reverseBits(), One.reverseBits()); } + /// Compute known bits for X & -X, which has only the lowest bit set of X set. + /// The name comes from the X86 BMI instruction + KnownBits blsi() const; + + /// Compute known bits for X ^ (X - 1), which has all bits up to and including + /// the lowest set bit of X set. The name comes from the X86 BMI instruction. + KnownBits blsmsk() const; + bool operator==(const KnownBits &Other) const { return Zero == Other.Zero && One == Other.One; } diff --git a/llvm/lib/Support/KnownBits.cpp b/llvm/lib/Support/KnownBits.cpp --- a/llvm/lib/Support/KnownBits.cpp +++ b/llvm/lib/Support/KnownBits.cpp @@ -623,6 +623,27 @@ return *this; } +KnownBits KnownBits::blsi() const { + unsigned BitWidth = getBitWidth(); + KnownBits Known(Zero, APInt(BitWidth, 0)); + unsigned Max = countMaxTrailingZeros(); + Known.Zero.setBitsFrom(std::min(Max + 1, BitWidth)); + unsigned Min = countMinTrailingZeros(); + if (Max == Min && Max < BitWidth) + Known.One.setBit(Max); + return Known; +} + +KnownBits KnownBits::blsmsk() const { + unsigned BitWidth = getBitWidth(); + KnownBits Known(BitWidth); + unsigned Max = countMaxTrailingZeros(); + Known.Zero.setBitsFrom(std::min(Max + 1, BitWidth)); + unsigned Min = countMinTrailingZeros(); + Known.One.setLowBits(std::min(Min + 1, BitWidth)); + return Known; +} + void KnownBits::print(raw_ostream &OS) const { OS << "{Zero=" << Zero << ", One=" << One << "}"; } diff --git a/llvm/unittests/Support/KnownBitsTest.cpp b/llvm/unittests/Support/KnownBitsTest.cpp --- a/llvm/unittests/Support/KnownBitsTest.cpp +++ b/llvm/unittests/Support/KnownBitsTest.cpp @@ -284,6 +284,12 @@ KnownAbs.Zero.setAllBits(); KnownAbs.One.setAllBits(); KnownBits KnownAbsPoison(KnownAbs); + KnownBits KnownBlsi(Bits); + KnownBlsi.Zero.setAllBits(); + KnownBlsi.One.setAllBits(); + KnownBits KnownBlsmsk(Bits); + KnownBlsmsk.Zero.setAllBits(); + KnownBlsmsk.One.setAllBits(); ForeachNumInKnownBits(Known, [&](const APInt &N) { APInt Res = N.abs(); @@ -294,6 +300,14 @@ KnownAbsPoison.One &= Res; KnownAbsPoison.Zero &= ~Res; } + + Res = N & -N; + KnownBlsi.One &= Res; + KnownBlsi.Zero &= ~Res; + + Res = N ^ (N - 1); + KnownBlsmsk.One &= Res; + KnownBlsmsk.Zero &= ~Res; }); // abs() is conservatively correct, but not guaranteed to be precise. @@ -304,6 +318,12 @@ KnownBits ComputedAbsPoison = Known.abs(true); EXPECT_TRUE(ComputedAbsPoison.Zero.isSubsetOf(KnownAbsPoison.Zero)); EXPECT_TRUE(ComputedAbsPoison.One.isSubsetOf(KnownAbsPoison.One)); + + KnownBits ComputedBlsi = Known.blsi(); + EXPECT_EQ(KnownBlsi, ComputedBlsi); + + KnownBits ComputedBlsmsk = Known.blsmsk(); + EXPECT_EQ(KnownBlsmsk, ComputedBlsmsk); }); }