Skip to content

Commit 9f10252

Browse files
authored
Add ConstantRangeList::subtract(ConstantRange) (#97093)
Add ConstantRangeList::subtract(ConstantRange). This API will be used in the "initializes" attribute inference as well (for load instructions).
1 parent b6ba10c commit 9f10252

File tree

3 files changed

+113
-0
lines changed

3 files changed

+113
-0
lines changed

llvm/include/llvm/IR/ConstantRangeList.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ class [[nodiscard]] ConstantRangeList {
7272
APInt(64, Upper, /*isSigned=*/true)));
7373
}
7474

75+
void subtract(const ConstantRange &SubRange);
76+
7577
/// Return the range list that results from the union of this
7678
/// ConstantRangeList with another ConstantRangeList, "CRL".
7779
ConstantRangeList unionWith(const ConstantRangeList &CRL) const;

llvm/lib/IR/ConstantRangeList.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,65 @@ void ConstantRangeList::insert(const ConstantRange &NewRange) {
8181
}
8282
}
8383

84+
void ConstantRangeList::subtract(const ConstantRange &SubRange) {
85+
if (SubRange.isEmptySet() || empty())
86+
return;
87+
assert(!SubRange.isFullSet() && "Do not support full set");
88+
assert(SubRange.getLower().slt(SubRange.getUpper()));
89+
assert(getBitWidth() == SubRange.getBitWidth());
90+
// Handle common cases.
91+
if (Ranges.back().getUpper().sle(SubRange.getLower()))
92+
return;
93+
if (SubRange.getUpper().sle(Ranges.front().getLower()))
94+
return;
95+
96+
SmallVector<ConstantRange, 2> Result;
97+
auto AppendRangeIfNonEmpty = [&Result](APInt Start, APInt End) {
98+
if (Start.slt(End))
99+
Result.push_back(ConstantRange(Start, End));
100+
};
101+
for (auto &Range : Ranges) {
102+
if (SubRange.getUpper().sle(Range.getLower()) ||
103+
Range.getUpper().sle(SubRange.getLower())) {
104+
// "Range" and "SubRange" do not overlap.
105+
// L---U : Range
106+
// L---U : SubRange (Case1)
107+
// L---U : SubRange (Case2)
108+
Result.push_back(Range);
109+
} else if (Range.getLower().sle(SubRange.getLower()) &&
110+
SubRange.getUpper().sle(Range.getUpper())) {
111+
// "Range" contains "SubRange".
112+
// L---U : Range
113+
// L-U : SubRange
114+
// Note that ConstantRange::contains(ConstantRange) checks unsigned,
115+
// but we need signed checking here.
116+
AppendRangeIfNonEmpty(Range.getLower(), SubRange.getLower());
117+
AppendRangeIfNonEmpty(SubRange.getUpper(), Range.getUpper());
118+
} else if (SubRange.getLower().sle(Range.getLower()) &&
119+
Range.getUpper().sle(SubRange.getUpper())) {
120+
// "SubRange" contains "Range".
121+
// L-U : Range
122+
// L---U : SubRange
123+
continue;
124+
} else if (Range.getLower().sge(SubRange.getLower()) &&
125+
Range.getLower().sle(SubRange.getUpper())) {
126+
// "Range" and "SubRange" overlap at the left.
127+
// L---U : Range
128+
// L---U : SubRange
129+
AppendRangeIfNonEmpty(SubRange.getUpper(), Range.getUpper());
130+
} else {
131+
// "Range" and "SubRange" overlap at the right.
132+
// L---U : Range
133+
// L---U : SubRange
134+
assert(SubRange.getLower().sge(Range.getLower()) &&
135+
SubRange.getLower().sle(Range.getUpper()));
136+
AppendRangeIfNonEmpty(Range.getLower(), SubRange.getLower());
137+
}
138+
}
139+
140+
Ranges = Result;
141+
}
142+
84143
ConstantRangeList
85144
ConstantRangeList::unionWith(const ConstantRangeList &CRL) const {
86145
assert(getBitWidth() == CRL.getBitWidth() &&

llvm/unittests/IR/ConstantRangeListTest.cpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,58 @@ ConstantRangeList GetCRL(ArrayRef<std::pair<APInt, APInt>> Pairs) {
101101
return ConstantRangeList(Ranges);
102102
}
103103

104+
TEST_F(ConstantRangeListTest, Subtract) {
105+
APInt AP0 = APInt(64, 0, /*isSigned=*/true);
106+
APInt AP2 = APInt(64, 2, /*isSigned=*/true);
107+
APInt AP3 = APInt(64, 3, /*isSigned=*/true);
108+
APInt AP4 = APInt(64, 4, /*isSigned=*/true);
109+
APInt AP8 = APInt(64, 8, /*isSigned=*/true);
110+
APInt AP10 = APInt(64, 10, /*isSigned=*/true);
111+
APInt AP11 = APInt(64, 11, /*isSigned=*/true);
112+
APInt AP12 = APInt(64, 12, /*isSigned=*/true);
113+
ConstantRangeList CRL = GetCRL({{AP0, AP4}, {AP8, AP12}});
114+
115+
// Execute ConstantRangeList::subtract(ConstantRange) and check the result
116+
// is expected. Pass "CRL" by value so that subtract() does not affect the
117+
// argument in caller.
118+
auto SubtractAndCheck = [](ConstantRangeList CRL,
119+
const std::pair<int64_t, int64_t> &Range,
120+
const ConstantRangeList &ExpectedCRL) {
121+
CRL.subtract(ConstantRange(APInt(64, Range.first, /*isSigned=*/true),
122+
APInt(64, Range.second, /*isSigned=*/true)));
123+
EXPECT_EQ(CRL, ExpectedCRL);
124+
};
125+
126+
// No overlap
127+
SubtractAndCheck(CRL, {-4, 0}, CRL);
128+
SubtractAndCheck(CRL, {4, 8}, CRL);
129+
SubtractAndCheck(CRL, {12, 16}, CRL);
130+
131+
// Overlap (left, right, or both)
132+
SubtractAndCheck(CRL, {-4, 2}, GetCRL({{AP2, AP4}, {AP8, AP12}}));
133+
SubtractAndCheck(CRL, {-4, 4}, GetCRL({{AP8, AP12}}));
134+
SubtractAndCheck(CRL, {-4, 8}, GetCRL({{AP8, AP12}}));
135+
SubtractAndCheck(CRL, {0, 2}, GetCRL({{AP2, AP4}, {AP8, AP12}}));
136+
SubtractAndCheck(CRL, {0, 4}, GetCRL({{AP8, AP12}}));
137+
SubtractAndCheck(CRL, {0, 8}, GetCRL({{AP8, AP12}}));
138+
SubtractAndCheck(CRL, {10, 12}, GetCRL({{AP0, AP4}, {AP8, AP10}}));
139+
SubtractAndCheck(CRL, {8, 12}, GetCRL({{AP0, AP4}}));
140+
SubtractAndCheck(CRL, {6, 12}, GetCRL({{AP0, AP4}}));
141+
SubtractAndCheck(CRL, {10, 16}, GetCRL({{AP0, AP4}, {AP8, AP10}}));
142+
SubtractAndCheck(CRL, {8, 16}, GetCRL({{AP0, AP4}}));
143+
SubtractAndCheck(CRL, {6, 16}, GetCRL({{AP0, AP4}}));
144+
SubtractAndCheck(CRL, {2, 10}, GetCRL({{AP0, AP2}, {AP10, AP12}}));
145+
146+
// Subset
147+
SubtractAndCheck(CRL, {2, 3}, GetCRL({{AP0, AP2}, {AP3, AP4}, {AP8, AP12}}));
148+
SubtractAndCheck(CRL, {10, 11},
149+
GetCRL({{AP0, AP4}, {AP8, AP10}, {AP11, AP12}}));
150+
151+
// Superset
152+
SubtractAndCheck(CRL, {0, 12}, GetCRL({}));
153+
SubtractAndCheck(CRL, {-4, 16}, GetCRL({}));
154+
}
155+
104156
TEST_F(ConstantRangeListTest, Union) {
105157
APInt APN4 = APInt(64, -4, /*isSigned=*/true);
106158
APInt APN2 = APInt(64, -2, /*isSigned=*/true);

0 commit comments

Comments
 (0)