1*0fca6ea1SDimitry Andric //===- ConstantRangeList.cpp - ConstantRangeList implementation -----------===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric 9*0fca6ea1SDimitry Andric #include "llvm/IR/ConstantRangeList.h" 10*0fca6ea1SDimitry Andric #include <cstddef> 11*0fca6ea1SDimitry Andric 12*0fca6ea1SDimitry Andric using namespace llvm; 13*0fca6ea1SDimitry Andric 14*0fca6ea1SDimitry Andric bool ConstantRangeList::isOrderedRanges(ArrayRef<ConstantRange> RangesRef) { 15*0fca6ea1SDimitry Andric if (RangesRef.empty()) 16*0fca6ea1SDimitry Andric return true; 17*0fca6ea1SDimitry Andric auto Range = RangesRef[0]; 18*0fca6ea1SDimitry Andric if (Range.getLower().sge(Range.getUpper())) 19*0fca6ea1SDimitry Andric return false; 20*0fca6ea1SDimitry Andric for (unsigned i = 1; i < RangesRef.size(); i++) { 21*0fca6ea1SDimitry Andric auto CurRange = RangesRef[i]; 22*0fca6ea1SDimitry Andric auto PreRange = RangesRef[i - 1]; 23*0fca6ea1SDimitry Andric if (CurRange.getLower().sge(CurRange.getUpper()) || 24*0fca6ea1SDimitry Andric CurRange.getLower().sle(PreRange.getUpper())) 25*0fca6ea1SDimitry Andric return false; 26*0fca6ea1SDimitry Andric } 27*0fca6ea1SDimitry Andric return true; 28*0fca6ea1SDimitry Andric } 29*0fca6ea1SDimitry Andric 30*0fca6ea1SDimitry Andric std::optional<ConstantRangeList> 31*0fca6ea1SDimitry Andric ConstantRangeList::getConstantRangeList(ArrayRef<ConstantRange> RangesRef) { 32*0fca6ea1SDimitry Andric if (!isOrderedRanges(RangesRef)) 33*0fca6ea1SDimitry Andric return std::nullopt; 34*0fca6ea1SDimitry Andric return ConstantRangeList(RangesRef); 35*0fca6ea1SDimitry Andric } 36*0fca6ea1SDimitry Andric 37*0fca6ea1SDimitry Andric void ConstantRangeList::insert(const ConstantRange &NewRange) { 38*0fca6ea1SDimitry Andric if (NewRange.isEmptySet()) 39*0fca6ea1SDimitry Andric return; 40*0fca6ea1SDimitry Andric assert(!NewRange.isFullSet() && "Do not support full set"); 41*0fca6ea1SDimitry Andric assert(NewRange.getLower().slt(NewRange.getUpper())); 42*0fca6ea1SDimitry Andric assert(getBitWidth() == NewRange.getBitWidth()); 43*0fca6ea1SDimitry Andric // Handle common cases. 44*0fca6ea1SDimitry Andric if (empty() || Ranges.back().getUpper().slt(NewRange.getLower())) { 45*0fca6ea1SDimitry Andric Ranges.push_back(NewRange); 46*0fca6ea1SDimitry Andric return; 47*0fca6ea1SDimitry Andric } 48*0fca6ea1SDimitry Andric if (NewRange.getUpper().slt(Ranges.front().getLower())) { 49*0fca6ea1SDimitry Andric Ranges.insert(Ranges.begin(), NewRange); 50*0fca6ea1SDimitry Andric return; 51*0fca6ea1SDimitry Andric } 52*0fca6ea1SDimitry Andric 53*0fca6ea1SDimitry Andric auto LowerBound = lower_bound( 54*0fca6ea1SDimitry Andric Ranges, NewRange, [](const ConstantRange &a, const ConstantRange &b) { 55*0fca6ea1SDimitry Andric return a.getLower().slt(b.getLower()); 56*0fca6ea1SDimitry Andric }); 57*0fca6ea1SDimitry Andric if (LowerBound != Ranges.end() && LowerBound->contains(NewRange)) 58*0fca6ea1SDimitry Andric return; 59*0fca6ea1SDimitry Andric 60*0fca6ea1SDimitry Andric // Slow insert. 61*0fca6ea1SDimitry Andric SmallVector<ConstantRange, 2> ExistingTail(LowerBound, Ranges.end()); 62*0fca6ea1SDimitry Andric Ranges.erase(LowerBound, Ranges.end()); 63*0fca6ea1SDimitry Andric // Merge consecutive ranges. 64*0fca6ea1SDimitry Andric if (!Ranges.empty() && NewRange.getLower().sle(Ranges.back().getUpper())) { 65*0fca6ea1SDimitry Andric APInt NewLower = Ranges.back().getLower(); 66*0fca6ea1SDimitry Andric APInt NewUpper = 67*0fca6ea1SDimitry Andric APIntOps::smax(NewRange.getUpper(), Ranges.back().getUpper()); 68*0fca6ea1SDimitry Andric Ranges.back() = ConstantRange(NewLower, NewUpper); 69*0fca6ea1SDimitry Andric } else { 70*0fca6ea1SDimitry Andric Ranges.push_back(NewRange); 71*0fca6ea1SDimitry Andric } 72*0fca6ea1SDimitry Andric for (auto Iter = ExistingTail.begin(); Iter != ExistingTail.end(); Iter++) { 73*0fca6ea1SDimitry Andric if (Ranges.back().getUpper().slt(Iter->getLower())) { 74*0fca6ea1SDimitry Andric Ranges.push_back(*Iter); 75*0fca6ea1SDimitry Andric } else { 76*0fca6ea1SDimitry Andric APInt NewLower = Ranges.back().getLower(); 77*0fca6ea1SDimitry Andric APInt NewUpper = 78*0fca6ea1SDimitry Andric APIntOps::smax(Iter->getUpper(), Ranges.back().getUpper()); 79*0fca6ea1SDimitry Andric Ranges.back() = ConstantRange(NewLower, NewUpper); 80*0fca6ea1SDimitry Andric } 81*0fca6ea1SDimitry Andric } 82*0fca6ea1SDimitry Andric } 83*0fca6ea1SDimitry Andric 84*0fca6ea1SDimitry Andric void ConstantRangeList::subtract(const ConstantRange &SubRange) { 85*0fca6ea1SDimitry Andric if (SubRange.isEmptySet() || empty()) 86*0fca6ea1SDimitry Andric return; 87*0fca6ea1SDimitry Andric assert(!SubRange.isFullSet() && "Do not support full set"); 88*0fca6ea1SDimitry Andric assert(SubRange.getLower().slt(SubRange.getUpper())); 89*0fca6ea1SDimitry Andric assert(getBitWidth() == SubRange.getBitWidth()); 90*0fca6ea1SDimitry Andric // Handle common cases. 91*0fca6ea1SDimitry Andric if (Ranges.back().getUpper().sle(SubRange.getLower())) 92*0fca6ea1SDimitry Andric return; 93*0fca6ea1SDimitry Andric if (SubRange.getUpper().sle(Ranges.front().getLower())) 94*0fca6ea1SDimitry Andric return; 95*0fca6ea1SDimitry Andric 96*0fca6ea1SDimitry Andric SmallVector<ConstantRange, 2> Result; 97*0fca6ea1SDimitry Andric auto AppendRangeIfNonEmpty = [&Result](APInt Start, APInt End) { 98*0fca6ea1SDimitry Andric if (Start.slt(End)) 99*0fca6ea1SDimitry Andric Result.push_back(ConstantRange(Start, End)); 100*0fca6ea1SDimitry Andric }; 101*0fca6ea1SDimitry Andric for (auto &Range : Ranges) { 102*0fca6ea1SDimitry Andric if (SubRange.getUpper().sle(Range.getLower()) || 103*0fca6ea1SDimitry Andric Range.getUpper().sle(SubRange.getLower())) { 104*0fca6ea1SDimitry Andric // "Range" and "SubRange" do not overlap. 105*0fca6ea1SDimitry Andric // L---U : Range 106*0fca6ea1SDimitry Andric // L---U : SubRange (Case1) 107*0fca6ea1SDimitry Andric // L---U : SubRange (Case2) 108*0fca6ea1SDimitry Andric Result.push_back(Range); 109*0fca6ea1SDimitry Andric } else if (Range.getLower().sle(SubRange.getLower()) && 110*0fca6ea1SDimitry Andric SubRange.getUpper().sle(Range.getUpper())) { 111*0fca6ea1SDimitry Andric // "Range" contains "SubRange". 112*0fca6ea1SDimitry Andric // L---U : Range 113*0fca6ea1SDimitry Andric // L-U : SubRange 114*0fca6ea1SDimitry Andric // Note that ConstantRange::contains(ConstantRange) checks unsigned, 115*0fca6ea1SDimitry Andric // but we need signed checking here. 116*0fca6ea1SDimitry Andric AppendRangeIfNonEmpty(Range.getLower(), SubRange.getLower()); 117*0fca6ea1SDimitry Andric AppendRangeIfNonEmpty(SubRange.getUpper(), Range.getUpper()); 118*0fca6ea1SDimitry Andric } else if (SubRange.getLower().sle(Range.getLower()) && 119*0fca6ea1SDimitry Andric Range.getUpper().sle(SubRange.getUpper())) { 120*0fca6ea1SDimitry Andric // "SubRange" contains "Range". 121*0fca6ea1SDimitry Andric // L-U : Range 122*0fca6ea1SDimitry Andric // L---U : SubRange 123*0fca6ea1SDimitry Andric continue; 124*0fca6ea1SDimitry Andric } else if (Range.getLower().sge(SubRange.getLower()) && 125*0fca6ea1SDimitry Andric Range.getLower().sle(SubRange.getUpper())) { 126*0fca6ea1SDimitry Andric // "Range" and "SubRange" overlap at the left. 127*0fca6ea1SDimitry Andric // L---U : Range 128*0fca6ea1SDimitry Andric // L---U : SubRange 129*0fca6ea1SDimitry Andric AppendRangeIfNonEmpty(SubRange.getUpper(), Range.getUpper()); 130*0fca6ea1SDimitry Andric } else { 131*0fca6ea1SDimitry Andric // "Range" and "SubRange" overlap at the right. 132*0fca6ea1SDimitry Andric // L---U : Range 133*0fca6ea1SDimitry Andric // L---U : SubRange 134*0fca6ea1SDimitry Andric assert(SubRange.getLower().sge(Range.getLower()) && 135*0fca6ea1SDimitry Andric SubRange.getLower().sle(Range.getUpper())); 136*0fca6ea1SDimitry Andric AppendRangeIfNonEmpty(Range.getLower(), SubRange.getLower()); 137*0fca6ea1SDimitry Andric } 138*0fca6ea1SDimitry Andric } 139*0fca6ea1SDimitry Andric 140*0fca6ea1SDimitry Andric Ranges = Result; 141*0fca6ea1SDimitry Andric } 142*0fca6ea1SDimitry Andric 143*0fca6ea1SDimitry Andric ConstantRangeList 144*0fca6ea1SDimitry Andric ConstantRangeList::unionWith(const ConstantRangeList &CRL) const { 145*0fca6ea1SDimitry Andric assert(getBitWidth() == CRL.getBitWidth() && 146*0fca6ea1SDimitry Andric "ConstantRangeList bitwidths don't agree!"); 147*0fca6ea1SDimitry Andric // Handle common cases. 148*0fca6ea1SDimitry Andric if (empty()) 149*0fca6ea1SDimitry Andric return CRL; 150*0fca6ea1SDimitry Andric if (CRL.empty()) 151*0fca6ea1SDimitry Andric return *this; 152*0fca6ea1SDimitry Andric 153*0fca6ea1SDimitry Andric ConstantRangeList Result; 154*0fca6ea1SDimitry Andric size_t i = 0, j = 0; 155*0fca6ea1SDimitry Andric // "PreviousRange" tracks the lowest unioned range that is being processed. 156*0fca6ea1SDimitry Andric // Its lower is fixed and the upper may be updated over iterations. 157*0fca6ea1SDimitry Andric ConstantRange PreviousRange(getBitWidth(), false); 158*0fca6ea1SDimitry Andric if (Ranges[i].getLower().slt(CRL.Ranges[j].getLower())) { 159*0fca6ea1SDimitry Andric PreviousRange = Ranges[i++]; 160*0fca6ea1SDimitry Andric } else { 161*0fca6ea1SDimitry Andric PreviousRange = CRL.Ranges[j++]; 162*0fca6ea1SDimitry Andric } 163*0fca6ea1SDimitry Andric 164*0fca6ea1SDimitry Andric // Try to union "PreviousRange" and "CR". If they are disjoint, push 165*0fca6ea1SDimitry Andric // "PreviousRange" to the result and assign it to "CR", a new union range. 166*0fca6ea1SDimitry Andric // Otherwise, update the upper of "PreviousRange" to cover "CR". Note that, 167*0fca6ea1SDimitry Andric // the lower of "PreviousRange" is always less or equal the lower of "CR". 168*0fca6ea1SDimitry Andric auto UnionAndUpdateRange = [&PreviousRange, 169*0fca6ea1SDimitry Andric &Result](const ConstantRange &CR) { 170*0fca6ea1SDimitry Andric if (PreviousRange.getUpper().slt(CR.getLower())) { 171*0fca6ea1SDimitry Andric Result.Ranges.push_back(PreviousRange); 172*0fca6ea1SDimitry Andric PreviousRange = CR; 173*0fca6ea1SDimitry Andric } else { 174*0fca6ea1SDimitry Andric PreviousRange = ConstantRange( 175*0fca6ea1SDimitry Andric PreviousRange.getLower(), 176*0fca6ea1SDimitry Andric APIntOps::smax(PreviousRange.getUpper(), CR.getUpper())); 177*0fca6ea1SDimitry Andric } 178*0fca6ea1SDimitry Andric }; 179*0fca6ea1SDimitry Andric while (i < size() || j < CRL.size()) { 180*0fca6ea1SDimitry Andric if (j == CRL.size() || 181*0fca6ea1SDimitry Andric (i < size() && Ranges[i].getLower().slt(CRL.Ranges[j].getLower()))) { 182*0fca6ea1SDimitry Andric // Merge PreviousRange with this. 183*0fca6ea1SDimitry Andric UnionAndUpdateRange(Ranges[i++]); 184*0fca6ea1SDimitry Andric } else { 185*0fca6ea1SDimitry Andric // Merge PreviousRange with CRL. 186*0fca6ea1SDimitry Andric UnionAndUpdateRange(CRL.Ranges[j++]); 187*0fca6ea1SDimitry Andric } 188*0fca6ea1SDimitry Andric } 189*0fca6ea1SDimitry Andric Result.Ranges.push_back(PreviousRange); 190*0fca6ea1SDimitry Andric return Result; 191*0fca6ea1SDimitry Andric } 192*0fca6ea1SDimitry Andric 193*0fca6ea1SDimitry Andric ConstantRangeList 194*0fca6ea1SDimitry Andric ConstantRangeList::intersectWith(const ConstantRangeList &CRL) const { 195*0fca6ea1SDimitry Andric assert(getBitWidth() == CRL.getBitWidth() && 196*0fca6ea1SDimitry Andric "ConstantRangeList bitwidths don't agree!"); 197*0fca6ea1SDimitry Andric 198*0fca6ea1SDimitry Andric // Handle common cases. 199*0fca6ea1SDimitry Andric if (empty()) 200*0fca6ea1SDimitry Andric return *this; 201*0fca6ea1SDimitry Andric if (CRL.empty()) 202*0fca6ea1SDimitry Andric return CRL; 203*0fca6ea1SDimitry Andric 204*0fca6ea1SDimitry Andric ConstantRangeList Result; 205*0fca6ea1SDimitry Andric size_t i = 0, j = 0; 206*0fca6ea1SDimitry Andric while (i < size() && j < CRL.size()) { 207*0fca6ea1SDimitry Andric auto &Range = this->Ranges[i]; 208*0fca6ea1SDimitry Andric auto &OtherRange = CRL.Ranges[j]; 209*0fca6ea1SDimitry Andric 210*0fca6ea1SDimitry Andric // The intersection of two Ranges is (max(lowers), min(uppers)), and it's 211*0fca6ea1SDimitry Andric // possible that max(lowers) > min(uppers) if they don't have intersection. 212*0fca6ea1SDimitry Andric // Add the intersection to result only if it's non-empty. 213*0fca6ea1SDimitry Andric // To keep simple, we don't call ConstantRange::intersectWith() as it 214*0fca6ea1SDimitry Andric // considers the complex upper wrapped case and may result two ranges, 215*0fca6ea1SDimitry Andric // like (2, 8) && (6, 4) = {(2, 4), (6, 8)}. 216*0fca6ea1SDimitry Andric APInt Start = APIntOps::smax(Range.getLower(), OtherRange.getLower()); 217*0fca6ea1SDimitry Andric APInt End = APIntOps::smin(Range.getUpper(), OtherRange.getUpper()); 218*0fca6ea1SDimitry Andric if (Start.slt(End)) 219*0fca6ea1SDimitry Andric Result.Ranges.push_back(ConstantRange(Start, End)); 220*0fca6ea1SDimitry Andric 221*0fca6ea1SDimitry Andric // Move to the next Range in one list determined by the uppers. 222*0fca6ea1SDimitry Andric // For example: A = {(0, 2), (4, 8)}; B = {(-2, 5), (6, 10)} 223*0fca6ea1SDimitry Andric // We need to intersect three pairs: A0 && B0; A1 && B0; A1 && B1. 224*0fca6ea1SDimitry Andric if (Range.getUpper().slt(OtherRange.getUpper())) 225*0fca6ea1SDimitry Andric i++; 226*0fca6ea1SDimitry Andric else 227*0fca6ea1SDimitry Andric j++; 228*0fca6ea1SDimitry Andric } 229*0fca6ea1SDimitry Andric return Result; 230*0fca6ea1SDimitry Andric } 231*0fca6ea1SDimitry Andric 232*0fca6ea1SDimitry Andric void ConstantRangeList::print(raw_ostream &OS) const { 233*0fca6ea1SDimitry Andric interleaveComma(Ranges, OS, [&](ConstantRange CR) { 234*0fca6ea1SDimitry Andric OS << "(" << CR.getLower() << ", " << CR.getUpper() << ")"; 235*0fca6ea1SDimitry Andric }); 236*0fca6ea1SDimitry Andric } 237*0fca6ea1SDimitry Andric 238*0fca6ea1SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 239*0fca6ea1SDimitry Andric LLVM_DUMP_METHOD void ConstantRangeList::dump() const { 240*0fca6ea1SDimitry Andric print(dbgs()); 241*0fca6ea1SDimitry Andric dbgs() << '\n'; 242*0fca6ea1SDimitry Andric } 243*0fca6ea1SDimitry Andric #endif 244