[BasicAA] Use saturating multiply on range if nsw

If we know that the var * scale multiplication is nsw, we can use
a saturating multiplication on the range (as a good approximation
of an nsw multiply). This recovers some cases where the fix from
D112611 is unnecessarily strict. (This can be further strengthened
by using a saturating add, but we currently don't track all the
necessary information for that.)

This exposes an issue in our NSW tracking for multiplies. The code
was assuming that (X +nsw Y) *nsw Z results in
(X *nsw Z) +nsw (Y *nsw Z) -- however, it is possible that the
distributed multiplications overflow, even if the non-distributed
one does not. We should discard the nsw flag if the the offset is
non-zero. If we just have (X *nsw Y) *nsw Z then concluding
X *nsw (Y *nsw Z) is fine.

Differential Revision: https://reviews.llvm.org/D112848
This commit is contained in:
Nikita Popov 2021-10-29 23:38:44 +02:00
parent f1d32a521e
commit 51e9f33603
2 changed files with 11 additions and 7 deletions

View File

@ -360,8 +360,10 @@ struct LinearExpression {
} }
LinearExpression mul(const APInt &Other, bool MulIsNSW) const { LinearExpression mul(const APInt &Other, bool MulIsNSW) const {
return LinearExpression(Val, Scale * Other, Offset * Other, // The check for zero offset is necessary, because generally
IsNSW && (Other.isOne() || MulIsNSW)); // (X +nsw Y) *nsw Z does not imply (X *nsw Z) +nsw (Y *nsw Z).
bool NSW = IsNSW && (Other.isOne() || (MulIsNSW && Offset.isZero()));
return LinearExpression(Val, Scale * Other, Offset * Other, NSW);
} }
}; };
} }
@ -1249,12 +1251,14 @@ AliasResult BasicAAResult::aliasGEP(
CR = CR.intersectWith( CR = CR.intersectWith(
ConstantRange::fromKnownBits(Known, /* Signed */ true), ConstantRange::fromKnownBits(Known, /* Signed */ true),
ConstantRange::Signed); ConstantRange::Signed);
CR = Index.Val.evaluateWith(CR).sextOrTrunc(OffsetRange.getBitWidth());
assert(OffsetRange.getBitWidth() == Scale.getBitWidth() && assert(OffsetRange.getBitWidth() == Scale.getBitWidth() &&
"Bit widths are normalized to MaxPointerSize"); "Bit widths are normalized to MaxPointerSize");
OffsetRange = OffsetRange.add( if (Index.IsNSW)
Index.Val.evaluateWith(CR).sextOrTrunc(OffsetRange.getBitWidth()) OffsetRange = OffsetRange.add(CR.smul_sat(ConstantRange(Scale)));
.smul_fast(ConstantRange(Scale))); else
OffsetRange = OffsetRange.add(CR.smul_fast(ConstantRange(Scale)));
} }
// We now have accesses at two offsets from the same base: // We now have accesses at two offsets from the same base:

View File

@ -145,12 +145,12 @@ define void @shl_of_non_negative(i8* %ptr, i64 %a) {
ret void ret void
} }
; TODO: Unlike the previous case, %ptr.neg and %ptr.shl can't alias, because ; Unlike the previous case, %ptr.neg and %ptr.shl can't alias, because
; shl nsw of non-negative is non-negative. ; shl nsw of non-negative is non-negative.
define void @shl_nsw_of_non_negative(i8* %ptr, i64 %a) { define void @shl_nsw_of_non_negative(i8* %ptr, i64 %a) {
; CHECK-LABEL: Function: shl_nsw_of_non_negative ; CHECK-LABEL: Function: shl_nsw_of_non_negative
; CHECK: NoAlias: i8* %ptr.a, i8* %ptr.neg ; CHECK: NoAlias: i8* %ptr.a, i8* %ptr.neg
; CHECK: MayAlias: i8* %ptr.neg, i8* %ptr.shl ; CHECK: NoAlias: i8* %ptr.neg, i8* %ptr.shl
%a.cmp = icmp sge i64 %a, 0 %a.cmp = icmp sge i64 %a, 0
call void @llvm.assume(i1 %a.cmp) call void @llvm.assume(i1 %a.cmp)
%ptr.neg = getelementptr i8, i8* %ptr, i64 -2 %ptr.neg = getelementptr i8, i8* %ptr, i64 -2