diff options
author | Gábor Spaits <gaborspaits1@gmail.com> | 2025-07-02 18:16:12 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-07-02 18:16:12 +0200 |
commit | 338fd8b12ce67eff73ed0a5c2174bee077fcbcbe (patch) | |
tree | 6d752e3b83df42d5bee324ae0adac0b44f5cce16 /llvm/lib/Transforms/Utils/SimplifyCFG.cpp | |
parent | 68173c80915955bae8cfc697a98d5d7888f09c67 (diff) | |
download | llvm-338fd8b12ce67eff73ed0a5c2174bee077fcbcbe.zip llvm-338fd8b12ce67eff73ed0a5c2174bee077fcbcbe.tar.gz llvm-338fd8b12ce67eff73ed0a5c2174bee077fcbcbe.tar.bz2 |
[SimplifyCFG] Transform switch to select when common bits uniquely identify one case (#145233)
Fix #141753 .
This patch introduces a new check, that tries to decide if the
conjunction of all the values uniquely identify the accepted values by
the switch.
Diffstat (limited to 'llvm/lib/Transforms/Utils/SimplifyCFG.cpp')
-rw-r--r-- | llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 147d206..a75f290 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -6198,7 +6198,7 @@ static bool initializeUniqueCases(SwitchInst *SI, PHINode *&PHI, // TODO: Handle switches with more than 2 cases that map to the same result. static Value *foldSwitchToSelect(const SwitchCaseResultVectorTy &ResultVector, Constant *DefaultResult, Value *Condition, - IRBuilder<> &Builder) { + IRBuilder<> &Builder, const DataLayout &DL) { // If we are selecting between only two cases transform into a simple // select or a two-way select if default is possible. // Example: @@ -6234,10 +6234,33 @@ static Value *foldSwitchToSelect(const SwitchCaseResultVectorTy &ResultVector, // case 0,2,8,10 -> Cond & 0b1..0101 == 0 ? result : default if (isPowerOf2_32(CaseCount)) { ConstantInt *MinCaseVal = CaseValues[0]; - // Find mininal value. - for (auto *Case : CaseValues) + // If there are bits that are set exclusively by CaseValues, we + // can transform the switch into a select if the conjunction of + // all the values uniquely identify CaseValues. + APInt AndMask = APInt::getAllOnes(MinCaseVal->getBitWidth()); + + // Find the minimum value and compute the and of all the case values. + for (auto *Case : CaseValues) { if (Case->getValue().slt(MinCaseVal->getValue())) MinCaseVal = Case; + AndMask &= Case->getValue(); + } + KnownBits Known = computeKnownBits(Condition, DL); + + if (!AndMask.isZero() && Known.getMaxValue().uge(AndMask)) { + // Compute the number of bits that are free to vary. + unsigned FreeBits = Known.countMaxActiveBits() - AndMask.popcount(); + + // Check if the number of values covered by the mask is equal + // to the number of cases. + if (FreeBits == Log2_32(CaseCount)) { + Value *And = Builder.CreateAnd(Condition, AndMask); + Value *Cmp = Builder.CreateICmpEQ( + And, Constant::getIntegerValue(And->getType(), AndMask)); + return Builder.CreateSelect(Cmp, ResultVector[0].first, + DefaultResult); + } + } // Mark the bits case number touched. APInt BitMask = APInt::getZero(MinCaseVal->getBitWidth()); @@ -6325,7 +6348,7 @@ static bool trySwitchToSelect(SwitchInst *SI, IRBuilder<> &Builder, assert(PHI != nullptr && "PHI for value select not found"); Builder.SetInsertPoint(SI); Value *SelectValue = - foldSwitchToSelect(UniqueResults, DefaultResult, Cond, Builder); + foldSwitchToSelect(UniqueResults, DefaultResult, Cond, Builder, DL); if (!SelectValue) return false; |