diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp --- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp +++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp @@ -254,6 +254,16 @@ return DerefBytes; } +/// Return the maximal extent from \p V to the end of the underlying object, +/// assuming the result is used in an aliasing query. +static uint64_t getMaximalExtentFrom(const Value &V, + const LocationSize &LocSize, + const DataLayout &DL) { + // This is an over-approximation of the number of bytes until the end of + // the object. This approximation ignores the offset in \p V. + return V.getPointerMaxObjSizeBytes(DL); +} + /// Returns true if we can prove that the object specified by V has size Size. static bool isObjectSize(const Value *V, uint64_t Size, const DataLayout &DL, const TargetLibraryInfo &TLI, bool NullIsValidLoc) { @@ -1824,12 +1834,16 @@ // If the size of one access is larger than the entire object on the other // side, then we know such behavior is undefined and can assume no alias. bool NullIsValidLocation = NullPointerIsDefined(&F); - if ((isObjectSmallerThan( - O2, getMinimalExtentFrom(*V1, V1Size, DL, NullIsValidLocation), DL, - TLI, NullIsValidLocation)) || - (isObjectSmallerThan( - O1, getMinimalExtentFrom(*V2, V2Size, DL, NullIsValidLocation), DL, - TLI, NullIsValidLocation))) + uint64_t V1MinSize = + getMinimalExtentFrom(*V1, V1Size, DL, NullIsValidLocation); + uint64_t V2MinSize = + getMinimalExtentFrom(*V2, V2Size, DL, NullIsValidLocation); + uint64_t V1MaxSize = getMaximalExtentFrom(*V1, V1Size, DL); + uint64_t V2MaxSize = getMaximalExtentFrom(*V2, V2Size, DL); + + if (V1MaxSize < V2MinSize || V2MaxSize < V1MinSize || + isObjectSmallerThan(O2, V1MinSize, DL, TLI, NullIsValidLocation) || + isObjectSmallerThan(O1, V2MinSize, DL, TLI, NullIsValidLocation)) return NoAlias; // Check the cache before climbing up use-def chains. This also terminates diff --git a/llvm/test/Analysis/BasicAA/maxobjsize.ll b/llvm/test/Analysis/BasicAA/maxobjsize.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Analysis/BasicAA/maxobjsize.ll @@ -0,0 +1,29 @@ +; RUN: opt < %s -basic-aa -print-no-aliases -print-may-aliases -print-must-aliases -aa-eval -disable-output 2>&1 | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + +define void @no_alias_1(i8* dereferenceable(1) maxobjsize(4) %a, i8* dereferenceable(5) maxobjsize(8) %b) { +; CHECK: NoAlias: + ret void +} + +define void @no_alias_2(i8* dereferenceable(5) maxobjsize(8) %a, i8* dereferenceable(1) maxobjsize(4) %b) { +; CHECK: NoAlias: + ret void +} + +define void @may_alias_1(i8* dereferenceable(1) maxobjsize(4) %a, i8* dereferenceable(2) maxobjsize(8) %b) { +; CHECK: MayAlias: + ret void +} + +define void @may_alias_2(i8* dereferenceable(2) maxobjsize(8) %a, i8* dereferenceable(1) maxobjsize(4) %b) { +; CHECK: MayAlias: + ret void +} + +define void @may_alias_3(i8* dereferenceable(4) maxobjsize(4) %a, i8* dereferenceable(4) maxobjsize(4) %b) { +; CHECK: MayAlias: + ret void +} + diff --git a/llvm/test/Transforms/Attributor/ArgumentPromotion/sret.ll b/llvm/test/Transforms/Attributor/ArgumentPromotion/sret.ll --- a/llvm/test/Transforms/Attributor/ArgumentPromotion/sret.ll +++ b/llvm/test/Transforms/Attributor/ArgumentPromotion/sret.ll @@ -11,7 +11,7 @@ ; ; IS__TUNIT_OPM: Function Attrs: argmemonly nofree nosync nounwind willreturn ; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@add -; IS__TUNIT_OPM-SAME: ({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* nocapture nofree noundef nonnull writeonly sret align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { +; IS__TUNIT_OPM-SAME: ({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { ; IS__TUNIT_OPM-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0 ; IS__TUNIT_OPM-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1 ; IS__TUNIT_OPM-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8 @@ -22,7 +22,7 @@ ; ; IS__TUNIT_NPM: Function Attrs: argmemonly nofree nosync nounwind willreturn ; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@add -; IS__TUNIT_NPM-SAME: ({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* noalias nocapture nofree noundef nonnull writeonly sret align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { +; IS__TUNIT_NPM-SAME: ({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* noalias nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { ; IS__TUNIT_NPM-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0 ; IS__TUNIT_NPM-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1 ; IS__TUNIT_NPM-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8 @@ -33,7 +33,7 @@ ; ; IS__CGSCC_OPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn ; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@add -; IS__CGSCC_OPM-SAME: ({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* nocapture nofree noundef nonnull writeonly sret align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { +; IS__CGSCC_OPM-SAME: ({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { ; IS__CGSCC_OPM-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0 ; IS__CGSCC_OPM-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1 ; IS__CGSCC_OPM-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8 @@ -44,7 +44,7 @@ ; ; IS__CGSCC_NPM: Function Attrs: argmemonly nofree norecurse nosync nounwind willreturn ; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@add -; IS__CGSCC_NPM-SAME: ({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* noalias nocapture nofree noundef nonnull writeonly sret align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { +; IS__CGSCC_NPM-SAME: ({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[THIS:%.*]], i32* noalias nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R:%.*]]) [[ATTR0:#.*]] { ; IS__CGSCC_NPM-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0 ; IS__CGSCC_NPM-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1 ; IS__CGSCC_NPM-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8 @@ -68,7 +68,7 @@ ; IS__TUNIT_OPM-SAME: () [[ATTR1:#.*]] { ; IS__TUNIT_OPM-NEXT: [[R:%.*]] = alloca i32, align 4 ; IS__TUNIT_OPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }, align 8 -; IS__TUNIT_OPM-NEXT: call void @add({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* nocapture nofree noundef nonnull writeonly sret align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] +; IS__TUNIT_OPM-NEXT: call void @add({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] ; IS__TUNIT_OPM-NEXT: ret void ; ; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn @@ -76,7 +76,7 @@ ; IS__TUNIT_NPM-SAME: () [[ATTR1:#.*]] { ; IS__TUNIT_NPM-NEXT: [[R:%.*]] = alloca i32, align 4 ; IS__TUNIT_NPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }, align 8 -; IS__TUNIT_NPM-NEXT: call void @add({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* noalias nocapture nofree noundef nonnull writeonly sret align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] +; IS__TUNIT_NPM-NEXT: call void @add({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* noalias nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] ; IS__TUNIT_NPM-NEXT: ret void ; ; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn @@ -84,7 +84,7 @@ ; IS__CGSCC_OPM-SAME: () [[ATTR1:#.*]] { ; IS__CGSCC_OPM-NEXT: [[R:%.*]] = alloca i32, align 4 ; IS__CGSCC_OPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }, align 8 -; IS__CGSCC_OPM-NEXT: call void @add({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* nocapture nofree noundef nonnull writeonly sret align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] +; IS__CGSCC_OPM-NEXT: call void @add({ i32, i32 }* nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] ; IS__CGSCC_OPM-NEXT: ret void ; ; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn @@ -92,7 +92,7 @@ ; IS__CGSCC_NPM-SAME: () [[ATTR1:#.*]] { ; IS__CGSCC_NPM-NEXT: [[R:%.*]] = alloca i32, align 4 ; IS__CGSCC_NPM-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }, align 8 -; IS__CGSCC_NPM-NEXT: call void @add({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* noalias nocapture nofree noundef nonnull writeonly sret align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] +; IS__CGSCC_NPM-NEXT: call void @add({ i32, i32 }* noalias nocapture nofree noundef nonnull readonly align 8 dereferenceable(8) maxobjsize(8) [[PAIR]], i32* noalias nocapture nofree noundef nonnull sret writeonly align 4 dereferenceable(4) maxobjsize(4) [[R]]) [[ATTR2:#.*]] ; IS__CGSCC_NPM-NEXT: ret void ; %r = alloca i32 diff --git a/llvm/test/Transforms/InstCombine/pr46680.ll b/llvm/test/Transforms/InstCombine/pr46680.ll --- a/llvm/test/Transforms/InstCombine/pr46680.ll +++ b/llvm/test/Transforms/InstCombine/pr46680.ll @@ -24,17 +24,11 @@ ; CHECK-NEXT: br label [[BB22:%.*]] ; CHECK: bb13: ; CHECK-NEXT: [[I14:%.*]] = load i16, i16* [[ARG]], align 2 -; CHECK-NEXT: [[I15:%.*]] = trunc i16 [[I14]] to i8 -; CHECK-NEXT: store i8 [[I15]], i8* @c, align 1 +; CHECK-NEXT: [[I19:%.*]] = trunc i16 [[I14]] to i8 +; CHECK-NEXT: store i8 [[I19]], i8* @c, align 1 ; CHECK-NEXT: br label [[BB22]] ; CHECK: bb22: -; CHECK-NEXT: [[STOREMERGE2_IN:%.*]] = load i16, i16* [[ARG]], align 2 -; CHECK-NEXT: [[STOREMERGE2:%.*]] = trunc i16 [[STOREMERGE2_IN]] to i8 -; CHECK-NEXT: store i8 [[STOREMERGE2]], i8* @c, align 1 -; CHECK-NEXT: [[STOREMERGE1_IN:%.*]] = load i16, i16* [[ARG]], align 2 -; CHECK-NEXT: [[STOREMERGE1:%.*]] = trunc i16 [[STOREMERGE1_IN]] to i8 -; CHECK-NEXT: store i8 [[STOREMERGE1]], i8* @c, align 1 -; CHECK-NEXT: [[STOREMERGE_IN:%.*]] = load i16, i16* [[ARG]], align 2 +; CHECK-NEXT: [[STOREMERGE_IN:%.*]] = phi i16 [ [[I5]], [[BB4]] ], [ [[I14]], [[BB13]] ] ; CHECK-NEXT: [[STOREMERGE:%.*]] = trunc i16 [[STOREMERGE_IN]] to i8 ; CHECK-NEXT: store i8 [[STOREMERGE]], i8* @c, align 1 ; CHECK-NEXT: br label [[BB23:%.*]]