llvm.org GIT mirror llvm / e003b9c
[ConstantRange] Clarify makeGuaranteedNoWrapRegion() guarantees; NFC makeGuaranteedNoWrapRegion() is actually makeExactNoWrapRegion() as long as only one of NUW or NSW is specified. This is not obvious from the current documentation, and some code seems to think that it is only exact for single-element ranges. Clarify docs and add tests to be more confident this really holds. There are currently no users of makeGuaranteedNoWrapRegion() that pass both NUW and NSW. I think it would be best to drop support for this entirely and then rename the function to makeExactNoWrapRegion(). Knowing that the no-wrap region is exact is useful, because we can backwards-constrain values. What I have in mind in particular is that LVI should be able to constrain values on edges where the with.overflow overflow flag is false. Differential Revision: https://reviews.llvm.org/D60598 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@358305 91177308-0d34-0410-b5e6-96231b3b80d8 Nikita Popov 6 months ago
3 changed file(s) with 76 addition(s) and 5 deletion(s). Raw diff Collapse all Expand all
118118 /// Return the largest range containing all X such that "X BinOpC Y" is
119119 /// guaranteed not to wrap (overflow) for all Y in Other.
120120 ///
121 /// NB! The returned set does *not* contain **all** possible values of X for
122 /// which "X BinOpC Y" does not wrap -- some viable values of X may be
123 /// missing, so you cannot use this to constrain X's range. E.g. in the
121 /// If only one of NoUnsignedWrap or NoSignedWrap is specified, the returned
122 /// range is exact: It contains *all* possible values of X for which
123 /// "X BinOpC Y" does not wrap. However, if both NUW and NSW are specified, it
124 /// may return only a subset of non-wrapping values. In this case the
125 /// returned region cannot be used to constrain X's range. E.g. in the
124126 /// fourth example, "(-2) + 1" is both nsw and nuw (so the "X" could be -2),
125127 /// but (-2) is not in the set returned.
126128 ///
868868 ConstantRange ConstantRange::addWithNoSignedWrap(const APInt &Other) const {
869869 // Calculate the subset of this range such that "X + Other" is
870870 // guaranteed not to wrap (overflow) for all X in this subset.
871 // makeGuaranteedNoWrapRegion will produce an exact NSW range since we are
872 // passing a single element range.
871 // makeGuaranteedNoWrapRegion will produce an exact NSW range.
873872 auto NSWRange = ConstantRange::makeGuaranteedNoWrapRegion(BinaryOperator::Add,
874873 ConstantRange(Other),
875874 OverflowingBinaryOperator::NoSignedWrap);
11501150 ConstantRange(APInt::getMinValue(32) + 1, APInt::getSignedMinValue(32)));
11511151 }
11521152
1153 template
1154 void TestNoWrapRegionExhaustive(Instruction::BinaryOps BinOp,
1155 unsigned NoWrapKind, Fn OverflowFn) {
1156 // When using 4 bits this test needs ~3s on a debug build.
1157 unsigned Bits = 3;
1158 EnumerateTwoConstantRanges(Bits,
1159 [&](const ConstantRange &CR1, const ConstantRange &CR2) {
1160 if (CR2.isEmptySet())
1161 return;
1162
1163 ConstantRange NoWrap =
1164 ConstantRange::makeGuaranteedNoWrapRegion(BinOp, CR2, NoWrapKind);
1165 ForeachNumInConstantRange(CR1, [&](const APInt &N1) {
1166 bool NoOverflow = true;
1167 ForeachNumInConstantRange(CR2, [&](const APInt &N2) {
1168 if (OverflowFn(N1, N2))
1169 NoOverflow = false;
1170 });
1171 EXPECT_EQ(NoOverflow, NoWrap.contains(N1));
1172 });
1173 });
1174 }
1175
1176 // Show that makeGuaranteedNoWrapRegion is precise if only one of
1177 // NoUnsignedWrap or NoSignedWrap is used.
1178 TEST(ConstantRange, NoWrapRegionExhaustive) {
1179 TestNoWrapRegionExhaustive(
1180 Instruction::Add, OverflowingBinaryOperator::NoUnsignedWrap,
1181 [](const APInt &N1, const APInt &N2) {
1182 bool Overflow;
1183 (void) N1.uadd_ov(N2, Overflow);
1184 return Overflow;
1185 });
1186 TestNoWrapRegionExhaustive(
1187 Instruction::Add, OverflowingBinaryOperator::NoSignedWrap,
1188 [](const APInt &N1, const APInt &N2) {
1189 bool Overflow;
1190 (void) N1.sadd_ov(N2, Overflow);
1191 return Overflow;
1192 });
1193 TestNoWrapRegionExhaustive(
1194 Instruction::Sub, OverflowingBinaryOperator::NoUnsignedWrap,
1195 [](const APInt &N1, const APInt &N2) {
1196 bool Overflow;
1197 (void) N1.usub_ov(N2, Overflow);
1198 return Overflow;
1199 });
1200 TestNoWrapRegionExhaustive(
1201 Instruction::Sub, OverflowingBinaryOperator::NoSignedWrap,
1202 [](const APInt &N1, const APInt &N2) {
1203 bool Overflow;
1204 (void) N1.ssub_ov(N2, Overflow);
1205 return Overflow;
1206 });
1207 TestNoWrapRegionExhaustive(
1208 Instruction::Mul, OverflowingBinaryOperator::NoUnsignedWrap,
1209 [](const APInt &N1, const APInt &N2) {
1210 bool Overflow;
1211 (void) N1.umul_ov(N2, Overflow);
1212 return Overflow;
1213 });
1214 TestNoWrapRegionExhaustive(
1215 Instruction::Mul, OverflowingBinaryOperator::NoSignedWrap,
1216 [](const APInt &N1, const APInt &N2) {
1217 bool Overflow;
1218 (void) N1.smul_ov(N2, Overflow);
1219 return Overflow;
1220 });
1221 }
1222
11531223 TEST(ConstantRange, GetEquivalentICmp) {
11541224 APInt RHS;
11551225 CmpInst::Predicate Pred;