|  | //===- ConstantRangeList.cpp - ConstantRangeList implementation -----------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/IR/ConstantRangeList.h" | 
|  | #include <cstddef> | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | bool ConstantRangeList::isOrderedRanges(ArrayRef<ConstantRange> RangesRef) { | 
|  | if (RangesRef.empty()) | 
|  | return true; | 
|  | auto Range = RangesRef[0]; | 
|  | if (Range.getLower().sge(Range.getUpper())) | 
|  | return false; | 
|  | for (unsigned i = 1; i < RangesRef.size(); i++) { | 
|  | auto CurRange = RangesRef[i]; | 
|  | auto PreRange = RangesRef[i - 1]; | 
|  | if (CurRange.getLower().sge(CurRange.getUpper()) || | 
|  | CurRange.getLower().sle(PreRange.getUpper())) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | std::optional<ConstantRangeList> | 
|  | ConstantRangeList::getConstantRangeList(ArrayRef<ConstantRange> RangesRef) { | 
|  | if (!isOrderedRanges(RangesRef)) | 
|  | return std::nullopt; | 
|  | return ConstantRangeList(RangesRef); | 
|  | } | 
|  |  | 
|  | void ConstantRangeList::insert(const ConstantRange &NewRange) { | 
|  | if (NewRange.isEmptySet()) | 
|  | return; | 
|  | assert(!NewRange.isFullSet() && "Do not support full set"); | 
|  | assert(NewRange.getLower().slt(NewRange.getUpper())); | 
|  | // Handle common cases. | 
|  | if (empty() || Ranges.back().getUpper().slt(NewRange.getLower())) { | 
|  | Ranges.push_back(NewRange); | 
|  | return; | 
|  | } | 
|  |  | 
|  | assert(getBitWidth() == NewRange.getBitWidth()); | 
|  |  | 
|  | if (NewRange.getUpper().slt(Ranges.front().getLower())) { | 
|  | Ranges.insert(Ranges.begin(), NewRange); | 
|  | return; | 
|  | } | 
|  |  | 
|  | auto LowerBound = lower_bound( | 
|  | Ranges, NewRange, [](const ConstantRange &a, const ConstantRange &b) { | 
|  | return a.getLower().slt(b.getLower()); | 
|  | }); | 
|  | if (LowerBound != Ranges.end() && LowerBound->contains(NewRange)) | 
|  | return; | 
|  |  | 
|  | // Slow insert. | 
|  | SmallVector<ConstantRange, 2> ExistingTail(LowerBound, Ranges.end()); | 
|  | Ranges.erase(LowerBound, Ranges.end()); | 
|  | // Merge consecutive ranges. | 
|  | if (!Ranges.empty() && NewRange.getLower().sle(Ranges.back().getUpper())) { | 
|  | APInt NewLower = Ranges.back().getLower(); | 
|  | APInt NewUpper = | 
|  | APIntOps::smax(NewRange.getUpper(), Ranges.back().getUpper()); | 
|  | Ranges.back() = ConstantRange(NewLower, NewUpper); | 
|  | } else { | 
|  | Ranges.push_back(NewRange); | 
|  | } | 
|  | for (auto Iter = ExistingTail.begin(); Iter != ExistingTail.end(); Iter++) { | 
|  | if (Ranges.back().getUpper().slt(Iter->getLower())) { | 
|  | Ranges.push_back(*Iter); | 
|  | } else { | 
|  | APInt NewLower = Ranges.back().getLower(); | 
|  | APInt NewUpper = | 
|  | APIntOps::smax(Iter->getUpper(), Ranges.back().getUpper()); | 
|  | Ranges.back() = ConstantRange(NewLower, NewUpper); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void ConstantRangeList::subtract(const ConstantRange &SubRange) { | 
|  | if (SubRange.isEmptySet() || empty()) | 
|  | return; | 
|  | assert(!SubRange.isFullSet() && "Do not support full set"); | 
|  | assert(SubRange.getLower().slt(SubRange.getUpper())); | 
|  | assert(getBitWidth() == SubRange.getBitWidth()); | 
|  | // Handle common cases. | 
|  | if (Ranges.back().getUpper().sle(SubRange.getLower())) | 
|  | return; | 
|  | if (SubRange.getUpper().sle(Ranges.front().getLower())) | 
|  | return; | 
|  |  | 
|  | SmallVector<ConstantRange, 2> Result; | 
|  | auto AppendRangeIfNonEmpty = [&Result](APInt Start, APInt End) { | 
|  | if (Start.slt(End)) | 
|  | Result.push_back(ConstantRange(Start, End)); | 
|  | }; | 
|  | for (auto &Range : Ranges) { | 
|  | if (SubRange.getUpper().sle(Range.getLower()) || | 
|  | Range.getUpper().sle(SubRange.getLower())) { | 
|  | // "Range" and "SubRange" do not overlap. | 
|  | //       L---U        : Range | 
|  | // L---U              : SubRange (Case1) | 
|  | //             L---U  : SubRange (Case2) | 
|  | Result.push_back(Range); | 
|  | } else if (Range.getLower().sle(SubRange.getLower()) && | 
|  | SubRange.getUpper().sle(Range.getUpper())) { | 
|  | // "Range" contains "SubRange". | 
|  | //       L---U        : Range | 
|  | //        L-U         : SubRange | 
|  | // Note that ConstantRange::contains(ConstantRange) checks unsigned, | 
|  | // but we need signed checking here. | 
|  | AppendRangeIfNonEmpty(Range.getLower(), SubRange.getLower()); | 
|  | AppendRangeIfNonEmpty(SubRange.getUpper(), Range.getUpper()); | 
|  | } else if (SubRange.getLower().sle(Range.getLower()) && | 
|  | Range.getUpper().sle(SubRange.getUpper())) { | 
|  | // "SubRange" contains "Range". | 
|  | //        L-U        : Range | 
|  | //       L---U       : SubRange | 
|  | continue; | 
|  | } else if (Range.getLower().sge(SubRange.getLower()) && | 
|  | Range.getLower().sle(SubRange.getUpper())) { | 
|  | // "Range" and "SubRange" overlap at the left. | 
|  | //       L---U        : Range | 
|  | //     L---U          : SubRange | 
|  | AppendRangeIfNonEmpty(SubRange.getUpper(), Range.getUpper()); | 
|  | } else { | 
|  | // "Range" and "SubRange" overlap at the right. | 
|  | //       L---U        : Range | 
|  | //         L---U      : SubRange | 
|  | assert(SubRange.getLower().sge(Range.getLower()) && | 
|  | SubRange.getLower().sle(Range.getUpper())); | 
|  | AppendRangeIfNonEmpty(Range.getLower(), SubRange.getLower()); | 
|  | } | 
|  | } | 
|  |  | 
|  | Ranges = Result; | 
|  | } | 
|  |  | 
|  | ConstantRangeList | 
|  | ConstantRangeList::unionWith(const ConstantRangeList &CRL) const { | 
|  | // Handle common cases. | 
|  | if (empty()) | 
|  | return CRL; | 
|  | if (CRL.empty()) | 
|  | return *this; | 
|  |  | 
|  | assert(getBitWidth() == CRL.getBitWidth() && | 
|  | "ConstantRangeList bitwidths don't agree!"); | 
|  |  | 
|  | ConstantRangeList Result; | 
|  | size_t i = 0, j = 0; | 
|  | // "PreviousRange" tracks the lowest unioned range that is being processed. | 
|  | // Its lower is fixed and the upper may be updated over iterations. | 
|  | ConstantRange PreviousRange(getBitWidth(), false); | 
|  | if (Ranges[i].getLower().slt(CRL.Ranges[j].getLower())) { | 
|  | PreviousRange = Ranges[i++]; | 
|  | } else { | 
|  | PreviousRange = CRL.Ranges[j++]; | 
|  | } | 
|  |  | 
|  | // Try to union "PreviousRange" and "CR". If they are disjoint, push | 
|  | // "PreviousRange" to the result and assign it to "CR", a new union range. | 
|  | // Otherwise, update the upper of "PreviousRange" to cover "CR". Note that, | 
|  | // the lower of "PreviousRange" is always less or equal the lower of "CR". | 
|  | auto UnionAndUpdateRange = [&PreviousRange, | 
|  | &Result](const ConstantRange &CR) { | 
|  | if (PreviousRange.getUpper().slt(CR.getLower())) { | 
|  | Result.Ranges.push_back(PreviousRange); | 
|  | PreviousRange = CR; | 
|  | } else { | 
|  | PreviousRange = ConstantRange( | 
|  | PreviousRange.getLower(), | 
|  | APIntOps::smax(PreviousRange.getUpper(), CR.getUpper())); | 
|  | } | 
|  | }; | 
|  | while (i < size() || j < CRL.size()) { | 
|  | if (j == CRL.size() || | 
|  | (i < size() && Ranges[i].getLower().slt(CRL.Ranges[j].getLower()))) { | 
|  | // Merge PreviousRange with this. | 
|  | UnionAndUpdateRange(Ranges[i++]); | 
|  | } else { | 
|  | // Merge PreviousRange with CRL. | 
|  | UnionAndUpdateRange(CRL.Ranges[j++]); | 
|  | } | 
|  | } | 
|  | Result.Ranges.push_back(PreviousRange); | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | ConstantRangeList | 
|  | ConstantRangeList::intersectWith(const ConstantRangeList &CRL) const { | 
|  | // Handle common cases. | 
|  | if (empty()) | 
|  | return *this; | 
|  | if (CRL.empty()) | 
|  | return CRL; | 
|  |  | 
|  | assert(getBitWidth() == CRL.getBitWidth() && | 
|  | "ConstantRangeList bitwidths don't agree!"); | 
|  |  | 
|  | ConstantRangeList Result; | 
|  | size_t i = 0, j = 0; | 
|  | while (i < size() && j < CRL.size()) { | 
|  | auto &Range = this->Ranges[i]; | 
|  | auto &OtherRange = CRL.Ranges[j]; | 
|  |  | 
|  | // The intersection of two Ranges is (max(lowers), min(uppers)), and it's | 
|  | // possible that max(lowers) > min(uppers) if they don't have intersection. | 
|  | // Add the intersection to result only if it's non-empty. | 
|  | // To keep simple, we don't call ConstantRange::intersectWith() as it | 
|  | // considers the complex upper wrapped case and may result two ranges, | 
|  | // like (2, 8) && (6, 4) = {(2, 4), (6, 8)}. | 
|  | APInt Start = APIntOps::smax(Range.getLower(), OtherRange.getLower()); | 
|  | APInt End = APIntOps::smin(Range.getUpper(), OtherRange.getUpper()); | 
|  | if (Start.slt(End)) | 
|  | Result.Ranges.push_back(ConstantRange(Start, End)); | 
|  |  | 
|  | // Move to the next Range in one list determined by the uppers. | 
|  | // For example: A = {(0, 2), (4, 8)}; B = {(-2, 5), (6, 10)} | 
|  | // We need to intersect three pairs: A0 && B0; A1 && B0; A1 && B1. | 
|  | if (Range.getUpper().slt(OtherRange.getUpper())) | 
|  | i++; | 
|  | else | 
|  | j++; | 
|  | } | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | void ConstantRangeList::print(raw_ostream &OS) const { | 
|  | interleaveComma(Ranges, OS, [&](ConstantRange CR) { | 
|  | OS << "(" << CR.getLower() << ", " << CR.getUpper() << ")"; | 
|  | }); | 
|  | } | 
|  |  | 
|  | #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) | 
|  | LLVM_DUMP_METHOD void ConstantRangeList::dump() const { | 
|  | print(dbgs()); | 
|  | dbgs() << '\n'; | 
|  | } | 
|  | #endif |