[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 {
return LinearExpression(Val, Scale * Other, Offset * Other,
IsNSW && (Other.isOne() || MulIsNSW));
// The check for zero offset is necessary, because generally
// (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(
ConstantRange::fromKnownBits(Known, /* Signed */ true),
ConstantRange::Signed);
CR = Index.Val.evaluateWith(CR).sextOrTrunc(OffsetRange.getBitWidth());
assert(OffsetRange.getBitWidth() == Scale.getBitWidth() &&
"Bit widths are normalized to MaxPointerSize");
OffsetRange = OffsetRange.add(
Index.Val.evaluateWith(CR).sextOrTrunc(OffsetRange.getBitWidth())
.smul_fast(ConstantRange(Scale)));
if (Index.IsNSW)
OffsetRange = OffsetRange.add(CR.smul_sat(ConstantRange(Scale)));
else
OffsetRange = OffsetRange.add(CR.smul_fast(ConstantRange(Scale)));
}
// 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
}
; 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.
define void @shl_nsw_of_non_negative(i8* %ptr, i64 %a) {
; CHECK-LABEL: Function: shl_nsw_of_non_negative
; 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
call void @llvm.assume(i1 %a.cmp)
%ptr.neg = getelementptr i8, i8* %ptr, i64 -2