@@ -5718,15 +5718,49 @@ bool SimplifyCFGOpt::simplifyUnreachable(UnreachableInst *UI) {
5718
5718
return Changed;
5719
5719
}
5720
5720
5721
- static bool casesAreContiguous (SmallVectorImpl<ConstantInt *> &Cases) {
5721
+ static bool casesAreContiguous (Value *Condition,
5722
+ SmallVectorImpl<ConstantInt *> &Cases,
5723
+ ConstantInt *&ContiguousCasesMin,
5724
+ ConstantInt *&ContiguousCasesMax,
5725
+ bool &IsWrapping) {
5722
5726
assert (Cases.size () >= 1 );
5723
5727
5724
5728
array_pod_sort (Cases.begin (), Cases.end (), constantIntSortPredicate);
5725
- for (size_t I = 1 , E = Cases.size (); I != E; ++I) {
5726
- if (Cases[I - 1 ]->getValue () != Cases[I]->getValue () + 1 )
5729
+ auto Min = Cases.back ()->getValue ();
5730
+ auto Max = Cases.front ()->getValue ();
5731
+ auto Offset = Max - Min;
5732
+ auto ContiguousOffset = Cases.size () - 1 ;
5733
+ if (Offset == ContiguousOffset) {
5734
+ ContiguousCasesMin = Cases.back ();
5735
+ ContiguousCasesMax = Cases.front ();
5736
+ return true ;
5737
+ }
5738
+ ConstantRange CR = computeConstantRange (Condition, /* ForSigned=*/ false );
5739
+ // If this is a wrapping contiguous range, that is, [Min, OtherMin] +
5740
+ // [OtherMax, Max] (also [OtherMax, OtherMin]), [OtherMin+1, OtherMax-1] is a
5741
+ // contiguous range for the other destination. N.B. If CR is not a full range,
5742
+ // Max+1 is not equal to Min. It's not continuous in arithmetic.
5743
+ if (Max == CR.getUnsignedMax () && Min == CR.getUnsignedMin ()) {
5744
+ assert (Cases.size () >= 2 );
5745
+ auto *It =
5746
+ std::adjacent_find (Cases.begin (), Cases.end (), [](auto L, auto R) {
5747
+ return L->getValue () != R->getValue () + 1 ;
5748
+ });
5749
+ if (It == Cases.end ())
5727
5750
return false ;
5751
+ auto *OtherMax = *It;
5752
+ auto *OtherMin = *(It + 1 );
5753
+ if ((Max - OtherMax->getValue ()) + (OtherMin->getValue () - Min) ==
5754
+ Cases.size () - 2 ) {
5755
+ ContiguousCasesMin = cast<ConstantInt>(
5756
+ ConstantInt::get (OtherMin->getType (), OtherMin->getValue () + 1 ));
5757
+ ContiguousCasesMax = cast<ConstantInt>(
5758
+ ConstantInt::get (OtherMax->getType (), OtherMax->getValue () - 1 ));
5759
+ IsWrapping = true ;
5760
+ return true ;
5761
+ }
5728
5762
}
5729
- return true ;
5763
+ return false ;
5730
5764
}
5731
5765
5732
5766
static void createUnreachableSwitchDefault (SwitchInst *Switch,
@@ -5797,33 +5831,42 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI,
5797
5831
assert (!CasesA.empty () || HasDefault);
5798
5832
5799
5833
// Figure out if one of the sets of cases form a contiguous range.
5800
- SmallVectorImpl<ConstantInt *> *ContiguousCases = nullptr ;
5834
+ ConstantInt *ContiguousCasesMin = nullptr ;
5835
+ ConstantInt *ContiguousCasesMax = nullptr ;
5801
5836
BasicBlock *ContiguousDest = nullptr ;
5802
5837
BasicBlock *OtherDest = nullptr ;
5803
- if (!CasesA.empty () && casesAreContiguous (CasesA)) {
5804
- ContiguousCases = &CasesA;
5838
+ bool IsWrapping = false ;
5839
+ if (!CasesA.empty () &&
5840
+ casesAreContiguous (SI->getCondition (), CasesA, ContiguousCasesMin,
5841
+ ContiguousCasesMax, IsWrapping)) {
5805
5842
ContiguousDest = DestA;
5806
5843
OtherDest = DestB;
5807
- } else if (casesAreContiguous (CasesB)) {
5808
- ContiguousCases = &CasesB;
5844
+ } else if (casesAreContiguous (SI-> getCondition (), CasesB, ContiguousCasesMin,
5845
+ ContiguousCasesMax, IsWrapping)) {
5809
5846
ContiguousDest = DestB;
5810
5847
OtherDest = DestA;
5811
5848
} else
5812
5849
return false ;
5813
5850
5851
+ if (IsWrapping)
5852
+ std::swap (ContiguousDest, OtherDest);
5853
+
5814
5854
// Start building the compare and branch.
5815
5855
5816
- Constant *Offset = ConstantExpr::getNeg (ContiguousCases->back ());
5817
- Constant *NumCases =
5818
- ConstantInt::get (Offset->getType (), ContiguousCases->size ());
5856
+ auto ContiguousCasesSize =
5857
+ (ContiguousCasesMax->getValue () - ContiguousCasesMin->getValue ())
5858
+ .getZExtValue () +
5859
+ 1 ;
5860
+ Constant *Offset = ConstantExpr::getNeg (ContiguousCasesMin);
5861
+ Constant *NumCases = ConstantInt::get (Offset->getType (), ContiguousCasesSize);
5819
5862
5820
5863
Value *Sub = SI->getCondition ();
5821
5864
if (!Offset->isNullValue ())
5822
5865
Sub = Builder.CreateAdd (Sub, Offset, Sub->getName () + " .off" );
5823
5866
5824
5867
Value *Cmp;
5825
5868
// If NumCases overflowed, then all possible values jump to the successor.
5826
- if (NumCases->isNullValue () && !ContiguousCases-> empty () )
5869
+ if (NumCases->isNullValue () && ContiguousCasesSize != 0 )
5827
5870
Cmp = ConstantInt::getTrue (SI->getContext ());
5828
5871
else
5829
5872
Cmp = Builder.CreateICmpULT (Sub, NumCases, " switch" );
@@ -5853,14 +5896,14 @@ bool SimplifyCFGOpt::turnSwitchRangeIntoICmp(SwitchInst *SI,
5853
5896
5854
5897
// Prune obsolete incoming values off the successors' PHI nodes.
5855
5898
for (auto BBI = ContiguousDest->begin (); isa<PHINode>(BBI); ++BBI) {
5856
- unsigned PreviousEdges = ContiguousCases-> size () ;
5899
+ unsigned PreviousEdges = ContiguousCasesSize ;
5857
5900
if (ContiguousDest == SI->getDefaultDest ())
5858
5901
++PreviousEdges;
5859
5902
for (unsigned I = 0 , E = PreviousEdges - 1 ; I != E; ++I)
5860
5903
cast<PHINode>(BBI)->removeIncomingValue (SI->getParent ());
5861
5904
}
5862
5905
for (auto BBI = OtherDest->begin (); isa<PHINode>(BBI); ++BBI) {
5863
- unsigned PreviousEdges = SI->getNumCases () - ContiguousCases-> size () ;
5906
+ unsigned PreviousEdges = SI->getNumCases () - ContiguousCasesSize ;
5864
5907
if (OtherDest == SI->getDefaultDest ())
5865
5908
++PreviousEdges;
5866
5909
for (unsigned I = 0 , E = PreviousEdges - 1 ; I != E; ++I)
0 commit comments