[llvm] [SimplifyCFG] Use the unsigned case range for lookup tables when narrower (PR #221489)
Nazar Mokrynskyi via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 12 09:49:40 PDT 2026
================
@@ -7570,6 +7577,38 @@ static bool simplifySwitchLookup(SwitchInst *SI, IRBuilder<> &Builder,
DefaultResults[PHI] = Result;
}
+ // A switch only compares its condition for equality, so the case values have
+ // no inherent signedness and the table can be laid out over whichever of the
+ // two ranges is narrower. The unsigned one wins whenever the condition has
+ // been narrowed to the smallest type holding all case values (InstCombine
+ // does this), because that wraps a contiguous unsigned range such as
+ // [0, 150) around into the sign-wrapped i8 range [-128, 127]. Note that a
+ // strictly narrower unsigned range implies a non-negative unsigned minimum:
+ // if every case value had the sign bit set, both orderings would agree.
+ APInt SignedRange = MaxCaseVal->getValue() - MinCaseVal->getValue();
+ APInt UnsignedRange =
+ UnsignedMaxCaseVal->getValue() - UnsignedMinCaseVal->getValue();
+ bool UseUnsignedRange = UnsignedRange.ult(SignedRange);
+ // The one thing the wider signed range can buy is a table spanning every
+ // value the condition can take, which then needs no range check. That only
+ // pays off if the default is reachable in the first place, and if its
+ // results can fill the table's holes: without them the holes are poison and
+ // the table needs a mask check anyway, which is no cheaper than the range
+ // check we would be avoiding.
+ if (UseUnsignedRange && SignedRange.isAllOnes() && HasDefaultResults &&
+ !SI->defaultDestUnreachable()) {
+ // Keep the signed range only if such a table would actually be built. The
+ // size below saturates for wide types, where it never is.
+ uint64_t CoveringTableSize =
+ SignedRange.getLimitedValue(UINT64_MAX - 1) + 1;
----------------
nazar-pc wrote:
`shouldBuildLookupTable()` opens with:
```c++
if (SI->getNumCases() > TableSize)
return false; // TableSize overflowed.
```
which always fires when the size wraps to 0. I've switched my call to the same `getLimitedValue() + 1` expression the main path uses and updated the comment.
https://github.com/llvm/llvm-project/pull/221489
More information about the llvm-commits
mailing list