xref: /llvm-project/llvm/lib/IR/ConstantRangeList.cpp (revision 4028bb10c3a396023b877d025c5776d207f29f91)
15ece35dfSHaopeng Liu //===- ConstantRangeList.cpp - ConstantRangeList implementation -----------===//
25ece35dfSHaopeng Liu //
35ece35dfSHaopeng Liu // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ece35dfSHaopeng Liu // See https://llvm.org/LICENSE.txt for license information.
55ece35dfSHaopeng Liu // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ece35dfSHaopeng Liu //
75ece35dfSHaopeng Liu //===----------------------------------------------------------------------===//
85ece35dfSHaopeng Liu 
95ece35dfSHaopeng Liu #include "llvm/IR/ConstantRangeList.h"
105ece35dfSHaopeng Liu #include <cstddef>
115ece35dfSHaopeng Liu 
125ece35dfSHaopeng Liu using namespace llvm;
135ece35dfSHaopeng Liu 
145ece35dfSHaopeng Liu bool ConstantRangeList::isOrderedRanges(ArrayRef<ConstantRange> RangesRef) {
155ece35dfSHaopeng Liu   if (RangesRef.empty())
165ece35dfSHaopeng Liu     return true;
175ece35dfSHaopeng Liu   auto Range = RangesRef[0];
185ece35dfSHaopeng Liu   if (Range.getLower().sge(Range.getUpper()))
195ece35dfSHaopeng Liu     return false;
205ece35dfSHaopeng Liu   for (unsigned i = 1; i < RangesRef.size(); i++) {
215ece35dfSHaopeng Liu     auto CurRange = RangesRef[i];
225ece35dfSHaopeng Liu     auto PreRange = RangesRef[i - 1];
235ece35dfSHaopeng Liu     if (CurRange.getLower().sge(CurRange.getUpper()) ||
245ece35dfSHaopeng Liu         CurRange.getLower().sle(PreRange.getUpper()))
255ece35dfSHaopeng Liu       return false;
265ece35dfSHaopeng Liu   }
275ece35dfSHaopeng Liu   return true;
285ece35dfSHaopeng Liu }
295ece35dfSHaopeng Liu 
305ece35dfSHaopeng Liu std::optional<ConstantRangeList>
315ece35dfSHaopeng Liu ConstantRangeList::getConstantRangeList(ArrayRef<ConstantRange> RangesRef) {
325ece35dfSHaopeng Liu   if (!isOrderedRanges(RangesRef))
335ece35dfSHaopeng Liu     return std::nullopt;
345ece35dfSHaopeng Liu   return ConstantRangeList(RangesRef);
355ece35dfSHaopeng Liu }
365ece35dfSHaopeng Liu 
375ece35dfSHaopeng Liu void ConstantRangeList::insert(const ConstantRange &NewRange) {
385ece35dfSHaopeng Liu   if (NewRange.isEmptySet())
395ece35dfSHaopeng Liu     return;
405ece35dfSHaopeng Liu   assert(!NewRange.isFullSet() && "Do not support full set");
415ece35dfSHaopeng Liu   assert(NewRange.getLower().slt(NewRange.getUpper()));
425ece35dfSHaopeng Liu   // Handle common cases.
435ece35dfSHaopeng Liu   if (empty() || Ranges.back().getUpper().slt(NewRange.getLower())) {
445ece35dfSHaopeng Liu     Ranges.push_back(NewRange);
455ece35dfSHaopeng Liu     return;
465ece35dfSHaopeng Liu   }
47*4028bb10SMatt Arsenault 
48*4028bb10SMatt Arsenault   assert(getBitWidth() == NewRange.getBitWidth());
49*4028bb10SMatt Arsenault 
505ece35dfSHaopeng Liu   if (NewRange.getUpper().slt(Ranges.front().getLower())) {
515ece35dfSHaopeng Liu     Ranges.insert(Ranges.begin(), NewRange);
525ece35dfSHaopeng Liu     return;
535ece35dfSHaopeng Liu   }
545ece35dfSHaopeng Liu 
555ece35dfSHaopeng Liu   auto LowerBound = lower_bound(
565ece35dfSHaopeng Liu       Ranges, NewRange, [](const ConstantRange &a, const ConstantRange &b) {
575ece35dfSHaopeng Liu         return a.getLower().slt(b.getLower());
585ece35dfSHaopeng Liu       });
595ece35dfSHaopeng Liu   if (LowerBound != Ranges.end() && LowerBound->contains(NewRange))
605ece35dfSHaopeng Liu     return;
615ece35dfSHaopeng Liu 
625ece35dfSHaopeng Liu   // Slow insert.
635ece35dfSHaopeng Liu   SmallVector<ConstantRange, 2> ExistingTail(LowerBound, Ranges.end());
645ece35dfSHaopeng Liu   Ranges.erase(LowerBound, Ranges.end());
655ece35dfSHaopeng Liu   // Merge consecutive ranges.
665ece35dfSHaopeng Liu   if (!Ranges.empty() && NewRange.getLower().sle(Ranges.back().getUpper())) {
675ece35dfSHaopeng Liu     APInt NewLower = Ranges.back().getLower();
685ece35dfSHaopeng Liu     APInt NewUpper =
695ece35dfSHaopeng Liu         APIntOps::smax(NewRange.getUpper(), Ranges.back().getUpper());
705ece35dfSHaopeng Liu     Ranges.back() = ConstantRange(NewLower, NewUpper);
715ece35dfSHaopeng Liu   } else {
725ece35dfSHaopeng Liu     Ranges.push_back(NewRange);
735ece35dfSHaopeng Liu   }
745ece35dfSHaopeng Liu   for (auto Iter = ExistingTail.begin(); Iter != ExistingTail.end(); Iter++) {
755ece35dfSHaopeng Liu     if (Ranges.back().getUpper().slt(Iter->getLower())) {
765ece35dfSHaopeng Liu       Ranges.push_back(*Iter);
775ece35dfSHaopeng Liu     } else {
785ece35dfSHaopeng Liu       APInt NewLower = Ranges.back().getLower();
795ece35dfSHaopeng Liu       APInt NewUpper =
805ece35dfSHaopeng Liu           APIntOps::smax(Iter->getUpper(), Ranges.back().getUpper());
815ece35dfSHaopeng Liu       Ranges.back() = ConstantRange(NewLower, NewUpper);
825ece35dfSHaopeng Liu     }
835ece35dfSHaopeng Liu   }
845ece35dfSHaopeng Liu }
855ece35dfSHaopeng Liu 
869f10252cSHaopeng Liu void ConstantRangeList::subtract(const ConstantRange &SubRange) {
879f10252cSHaopeng Liu   if (SubRange.isEmptySet() || empty())
889f10252cSHaopeng Liu     return;
899f10252cSHaopeng Liu   assert(!SubRange.isFullSet() && "Do not support full set");
909f10252cSHaopeng Liu   assert(SubRange.getLower().slt(SubRange.getUpper()));
919f10252cSHaopeng Liu   assert(getBitWidth() == SubRange.getBitWidth());
929f10252cSHaopeng Liu   // Handle common cases.
939f10252cSHaopeng Liu   if (Ranges.back().getUpper().sle(SubRange.getLower()))
949f10252cSHaopeng Liu     return;
959f10252cSHaopeng Liu   if (SubRange.getUpper().sle(Ranges.front().getLower()))
969f10252cSHaopeng Liu     return;
979f10252cSHaopeng Liu 
989f10252cSHaopeng Liu   SmallVector<ConstantRange, 2> Result;
999f10252cSHaopeng Liu   auto AppendRangeIfNonEmpty = [&Result](APInt Start, APInt End) {
1009f10252cSHaopeng Liu     if (Start.slt(End))
1019f10252cSHaopeng Liu       Result.push_back(ConstantRange(Start, End));
1029f10252cSHaopeng Liu   };
1039f10252cSHaopeng Liu   for (auto &Range : Ranges) {
1049f10252cSHaopeng Liu     if (SubRange.getUpper().sle(Range.getLower()) ||
1059f10252cSHaopeng Liu         Range.getUpper().sle(SubRange.getLower())) {
1069f10252cSHaopeng Liu       // "Range" and "SubRange" do not overlap.
1079f10252cSHaopeng Liu       //       L---U        : Range
1089f10252cSHaopeng Liu       // L---U              : SubRange (Case1)
1099f10252cSHaopeng Liu       //             L---U  : SubRange (Case2)
1109f10252cSHaopeng Liu       Result.push_back(Range);
1119f10252cSHaopeng Liu     } else if (Range.getLower().sle(SubRange.getLower()) &&
1129f10252cSHaopeng Liu                SubRange.getUpper().sle(Range.getUpper())) {
1139f10252cSHaopeng Liu       // "Range" contains "SubRange".
1149f10252cSHaopeng Liu       //       L---U        : Range
1159f10252cSHaopeng Liu       //        L-U         : SubRange
1169f10252cSHaopeng Liu       // Note that ConstantRange::contains(ConstantRange) checks unsigned,
1179f10252cSHaopeng Liu       // but we need signed checking here.
1189f10252cSHaopeng Liu       AppendRangeIfNonEmpty(Range.getLower(), SubRange.getLower());
1199f10252cSHaopeng Liu       AppendRangeIfNonEmpty(SubRange.getUpper(), Range.getUpper());
1209f10252cSHaopeng Liu     } else if (SubRange.getLower().sle(Range.getLower()) &&
1219f10252cSHaopeng Liu                Range.getUpper().sle(SubRange.getUpper())) {
1229f10252cSHaopeng Liu       // "SubRange" contains "Range".
1239f10252cSHaopeng Liu       //        L-U        : Range
1249f10252cSHaopeng Liu       //       L---U       : SubRange
1259f10252cSHaopeng Liu       continue;
1269f10252cSHaopeng Liu     } else if (Range.getLower().sge(SubRange.getLower()) &&
1279f10252cSHaopeng Liu                Range.getLower().sle(SubRange.getUpper())) {
1289f10252cSHaopeng Liu       // "Range" and "SubRange" overlap at the left.
1299f10252cSHaopeng Liu       //       L---U        : Range
1309f10252cSHaopeng Liu       //     L---U          : SubRange
1319f10252cSHaopeng Liu       AppendRangeIfNonEmpty(SubRange.getUpper(), Range.getUpper());
1329f10252cSHaopeng Liu     } else {
1339f10252cSHaopeng Liu       // "Range" and "SubRange" overlap at the right.
1349f10252cSHaopeng Liu       //       L---U        : Range
1359f10252cSHaopeng Liu       //         L---U      : SubRange
1369f10252cSHaopeng Liu       assert(SubRange.getLower().sge(Range.getLower()) &&
1379f10252cSHaopeng Liu              SubRange.getLower().sle(Range.getUpper()));
1389f10252cSHaopeng Liu       AppendRangeIfNonEmpty(Range.getLower(), SubRange.getLower());
1399f10252cSHaopeng Liu     }
1409f10252cSHaopeng Liu   }
1419f10252cSHaopeng Liu 
1429f10252cSHaopeng Liu   Ranges = Result;
1439f10252cSHaopeng Liu }
1449f10252cSHaopeng Liu 
145e6c22169SHaopeng Liu ConstantRangeList
146e6c22169SHaopeng Liu ConstantRangeList::unionWith(const ConstantRangeList &CRL) const {
147e6c22169SHaopeng Liu   // Handle common cases.
148e6c22169SHaopeng Liu   if (empty())
149e6c22169SHaopeng Liu     return CRL;
150e6c22169SHaopeng Liu   if (CRL.empty())
151e6c22169SHaopeng Liu     return *this;
152e6c22169SHaopeng Liu 
153*4028bb10SMatt Arsenault   assert(getBitWidth() == CRL.getBitWidth() &&
154*4028bb10SMatt Arsenault          "ConstantRangeList bitwidths don't agree!");
155*4028bb10SMatt Arsenault 
156e6c22169SHaopeng Liu   ConstantRangeList Result;
157e6c22169SHaopeng Liu   size_t i = 0, j = 0;
158e6c22169SHaopeng Liu   // "PreviousRange" tracks the lowest unioned range that is being processed.
159e6c22169SHaopeng Liu   // Its lower is fixed and the upper may be updated over iterations.
160e6c22169SHaopeng Liu   ConstantRange PreviousRange(getBitWidth(), false);
161e6c22169SHaopeng Liu   if (Ranges[i].getLower().slt(CRL.Ranges[j].getLower())) {
162e6c22169SHaopeng Liu     PreviousRange = Ranges[i++];
163e6c22169SHaopeng Liu   } else {
164e6c22169SHaopeng Liu     PreviousRange = CRL.Ranges[j++];
165e6c22169SHaopeng Liu   }
166e6c22169SHaopeng Liu 
167e6c22169SHaopeng Liu   // Try to union "PreviousRange" and "CR". If they are disjoint, push
168e6c22169SHaopeng Liu   // "PreviousRange" to the result and assign it to "CR", a new union range.
169e6c22169SHaopeng Liu   // Otherwise, update the upper of "PreviousRange" to cover "CR". Note that,
170e6c22169SHaopeng Liu   // the lower of "PreviousRange" is always less or equal the lower of "CR".
171e6c22169SHaopeng Liu   auto UnionAndUpdateRange = [&PreviousRange,
172e6c22169SHaopeng Liu                               &Result](const ConstantRange &CR) {
173e6c22169SHaopeng Liu     if (PreviousRange.getUpper().slt(CR.getLower())) {
174e6c22169SHaopeng Liu       Result.Ranges.push_back(PreviousRange);
175e6c22169SHaopeng Liu       PreviousRange = CR;
176e6c22169SHaopeng Liu     } else {
177e6c22169SHaopeng Liu       PreviousRange = ConstantRange(
178e6c22169SHaopeng Liu           PreviousRange.getLower(),
179e6c22169SHaopeng Liu           APIntOps::smax(PreviousRange.getUpper(), CR.getUpper()));
180e6c22169SHaopeng Liu     }
181e6c22169SHaopeng Liu   };
182e6c22169SHaopeng Liu   while (i < size() || j < CRL.size()) {
183e6c22169SHaopeng Liu     if (j == CRL.size() ||
184e6c22169SHaopeng Liu         (i < size() && Ranges[i].getLower().slt(CRL.Ranges[j].getLower()))) {
185e6c22169SHaopeng Liu       // Merge PreviousRange with this.
186e6c22169SHaopeng Liu       UnionAndUpdateRange(Ranges[i++]);
187e6c22169SHaopeng Liu     } else {
188e6c22169SHaopeng Liu       // Merge PreviousRange with CRL.
189e6c22169SHaopeng Liu       UnionAndUpdateRange(CRL.Ranges[j++]);
190e6c22169SHaopeng Liu     }
191e6c22169SHaopeng Liu   }
192e6c22169SHaopeng Liu   Result.Ranges.push_back(PreviousRange);
193e6c22169SHaopeng Liu   return Result;
194e6c22169SHaopeng Liu }
195e6c22169SHaopeng Liu 
196e6c22169SHaopeng Liu ConstantRangeList
197e6c22169SHaopeng Liu ConstantRangeList::intersectWith(const ConstantRangeList &CRL) const {
198e6c22169SHaopeng Liu   // Handle common cases.
199e6c22169SHaopeng Liu   if (empty())
200e6c22169SHaopeng Liu     return *this;
201e6c22169SHaopeng Liu   if (CRL.empty())
202e6c22169SHaopeng Liu     return CRL;
203e6c22169SHaopeng Liu 
204*4028bb10SMatt Arsenault   assert(getBitWidth() == CRL.getBitWidth() &&
205*4028bb10SMatt Arsenault          "ConstantRangeList bitwidths don't agree!");
206*4028bb10SMatt Arsenault 
207e6c22169SHaopeng Liu   ConstantRangeList Result;
208e6c22169SHaopeng Liu   size_t i = 0, j = 0;
209e6c22169SHaopeng Liu   while (i < size() && j < CRL.size()) {
210e6c22169SHaopeng Liu     auto &Range = this->Ranges[i];
211e6c22169SHaopeng Liu     auto &OtherRange = CRL.Ranges[j];
212e6c22169SHaopeng Liu 
213e6c22169SHaopeng Liu     // The intersection of two Ranges is (max(lowers), min(uppers)), and it's
214e6c22169SHaopeng Liu     // possible that max(lowers) > min(uppers) if they don't have intersection.
215e6c22169SHaopeng Liu     // Add the intersection to result only if it's non-empty.
216e6c22169SHaopeng Liu     // To keep simple, we don't call ConstantRange::intersectWith() as it
217e6c22169SHaopeng Liu     // considers the complex upper wrapped case and may result two ranges,
218e6c22169SHaopeng Liu     // like (2, 8) && (6, 4) = {(2, 4), (6, 8)}.
219e6c22169SHaopeng Liu     APInt Start = APIntOps::smax(Range.getLower(), OtherRange.getLower());
220e6c22169SHaopeng Liu     APInt End = APIntOps::smin(Range.getUpper(), OtherRange.getUpper());
221e6c22169SHaopeng Liu     if (Start.slt(End))
222e6c22169SHaopeng Liu       Result.Ranges.push_back(ConstantRange(Start, End));
223e6c22169SHaopeng Liu 
224e6c22169SHaopeng Liu     // Move to the next Range in one list determined by the uppers.
225e6c22169SHaopeng Liu     // For example: A = {(0, 2), (4, 8)}; B = {(-2, 5), (6, 10)}
226e6c22169SHaopeng Liu     // We need to intersect three pairs: A0 && B0; A1 && B0; A1 && B1.
227e6c22169SHaopeng Liu     if (Range.getUpper().slt(OtherRange.getUpper()))
228e6c22169SHaopeng Liu       i++;
229e6c22169SHaopeng Liu     else
230e6c22169SHaopeng Liu       j++;
231e6c22169SHaopeng Liu   }
232e6c22169SHaopeng Liu   return Result;
233e6c22169SHaopeng Liu }
234e6c22169SHaopeng Liu 
2355ece35dfSHaopeng Liu void ConstantRangeList::print(raw_ostream &OS) const {
2365ece35dfSHaopeng Liu   interleaveComma(Ranges, OS, [&](ConstantRange CR) {
2375ece35dfSHaopeng Liu     OS << "(" << CR.getLower() << ", " << CR.getUpper() << ")";
2385ece35dfSHaopeng Liu   });
2395ece35dfSHaopeng Liu }
2405ece35dfSHaopeng Liu 
2415ece35dfSHaopeng Liu #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
2425ece35dfSHaopeng Liu LLVM_DUMP_METHOD void ConstantRangeList::dump() const {
2435ece35dfSHaopeng Liu   print(dbgs());
2445ece35dfSHaopeng Liu   dbgs() << '\n';
2455ece35dfSHaopeng Liu }
2465ece35dfSHaopeng Liu #endif
247