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