diff --git a/llvm/include/llvm/Analysis/AliasAnalysis.h b/llvm/include/llvm/Analysis/AliasAnalysis.h --- a/llvm/include/llvm/Analysis/AliasAnalysis.h +++ b/llvm/include/llvm/Analysis/AliasAnalysis.h @@ -402,7 +402,7 @@ /// approximation to a precise "captures before" analysis. class EarliestEscapeInfo final : public CaptureInfo { DominatorTree &DT; - const LoopInfo &LI; + const LoopInfo *LI; /// Map from identified local object to an instruction before which it does /// not escape, or nullptr if it never escapes. The "earliest" instruction @@ -415,7 +415,7 @@ DenseMap> Inst2Obj; public: - EarliestEscapeInfo(DominatorTree &DT, const LoopInfo &LI) : DT(DT), LI(LI) {} + EarliestEscapeInfo(DominatorTree &DT, const LoopInfo *LI) : DT(DT), LI(LI) {} bool isNotCapturedBeforeOrAt(const Value *Object, const Instruction *I) override; diff --git a/llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h b/llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h --- a/llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h +++ b/llvm/include/llvm/Transforms/Scalar/MemCpyOptimizer.h @@ -21,7 +21,7 @@ namespace llvm { -class AAResults; +class BatchAAResults; class AssumptionCache; class CallBase; class CallInst; @@ -40,7 +40,7 @@ class MemCpyOptPass : public PassInfoMixin { TargetLibraryInfo *TLI = nullptr; - AAResults *AA = nullptr; + BatchAAResults *AA = nullptr; AssumptionCache *AC = nullptr; DominatorTree *DT = nullptr; MemorySSA *MSSA = nullptr; @@ -52,7 +52,7 @@ PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); // Glue for the old PM. - bool runImpl(Function &F, TargetLibraryInfo *TLI, AAResults *AA, + bool runImpl(Function &F, TargetLibraryInfo *TLI, BatchAAResults *AA, AssumptionCache *AC, DominatorTree *DT, MemorySSA *MSSA); private: 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 @@ -256,7 +256,7 @@ return true; return I != Iter.first->second && - !isPotentiallyReachable(Iter.first->second, I, nullptr, &DT, &LI); + !isPotentiallyReachable(Iter.first->second, I, nullptr, &DT, LI); } void EarliestEscapeInfo::removeInstruction(Instruction *I) { diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp --- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -905,7 +905,7 @@ DSEState(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT, PostDominatorTree &PDT, const TargetLibraryInfo &TLI, const LoopInfo &LI) - : F(F), AA(AA), EI(DT, LI), BatchAA(AA, &EI), MSSA(MSSA), DT(DT), + : F(F), AA(AA), EI(DT, &LI), BatchAA(AA, &EI), MSSA(MSSA), DT(DT), PDT(PDT), TLI(TLI), DL(F.getParent()->getDataLayout()), LI(LI) { // Collect blocks with throwing instructions not modeled in MemorySSA and // alloc-like objects. diff --git a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp --- a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp +++ b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp @@ -330,7 +330,7 @@ // Check for mod or ref of Loc between Start and End, excluding both boundaries. // Start and End must be in the same block -static bool accessedBetween(AliasAnalysis &AA, MemoryLocation Loc, +static bool accessedBetween(BatchAAResults &AA, MemoryLocation Loc, const MemoryUseOrDef *Start, const MemoryUseOrDef *End) { assert(Start->getBlock() == End->getBlock() && "Only local supported"); @@ -967,10 +967,8 @@ // unexpected manner, for example via a global, which we deduce from // the use analysis, we also need to know that it does not sneakily // access dest. We rely on AA to figure this out for us. - ModRefInfo MR = AA->getModRefInfo(C, cpyDest, LocationSize::precise(srcSize)); - // If necessary, perform additional analysis. - if (isModOrRefSet(MR)) - MR = AA->callCapturesBefore(C, cpyDest, LocationSize::precise(srcSize), DT); + ModRefInfo MR = AA->getModRefInfo( + C, MemoryLocation(cpyDest, LocationSize::precise(srcSize))); if (isModOrRefSet(MR)) return false; @@ -1206,7 +1204,7 @@ /// Determine whether the instruction has undefined content for the given Size, /// either because it was freshly alloca'd or started its lifetime. -static bool hasUndefContents(MemorySSA *MSSA, AliasAnalysis *AA, Value *V, +static bool hasUndefContents(MemorySSA *MSSA, BatchAAResults *AA, Value *V, MemoryDef *Def, Value *Size) { if (MSSA->isLiveOnEntryDef(Def)) return isa(getUnderlyingObject(V)); @@ -1573,7 +1571,10 @@ auto *DT = &AM.getResult(F); auto *MSSA = &AM.getResult(F); - bool MadeChange = runImpl(F, &TLI, AA, AC, DT, &MSSA->getMSSA()); + EarliestEscapeInfo EI(*DT, nullptr); + BatchAAResults BatchAA(*AA, &EI); + + bool MadeChange = runImpl(F, &TLI, &BatchAA, AC, DT, &MSSA->getMSSA()); if (!MadeChange) return PreservedAnalyses::all(); @@ -1584,7 +1585,7 @@ } bool MemCpyOptPass::runImpl(Function &F, TargetLibraryInfo *TLI_, - AliasAnalysis *AA_, AssumptionCache *AC_, + BatchAAResults *AA_, AssumptionCache *AC_, DominatorTree *DT_, MemorySSA *MSSA_) { bool MadeChange = false; TLI = TLI_; @@ -1618,5 +1619,8 @@ auto *DT = &getAnalysis().getDomTree(); auto *MSSA = &getAnalysis().getMSSA(); - return Impl.runImpl(F, TLI, AA, AC, DT, MSSA); + EarliestEscapeInfo EI(*DT, nullptr); + BatchAAResults BatchAA(*AA, &EI); + + return Impl.runImpl(F, TLI, &BatchAA, AC, DT, MSSA); } diff --git a/llvm/test/Transforms/MemCpyOpt/callslot.ll b/llvm/test/Transforms/MemCpyOpt/callslot.ll --- a/llvm/test/Transforms/MemCpyOpt/callslot.ll +++ b/llvm/test/Transforms/MemCpyOpt/callslot.ll @@ -272,10 +272,10 @@ ; CHECK-NEXT: call void @accept_ptr(i8* [[DEST_I8]]) ; CHECK-NEXT: ret i32 10 ; CHECK: nocaptures: -; CHECK-NEXT: call void @accept_ptr(i8* [[SRC_I8]]) #[[ATTR3]] +; CHECK-NEXT: [[DEST1:%.*]] = bitcast [16 x i8]* [[DEST]] to i8* +; CHECK-NEXT: call void @accept_ptr(i8* [[DEST1]]) #[[ATTR3]] ; CHECK-NEXT: [[LV_1:%.*]] = load i32*, i32** [[PTR:%.*]], align 8 ; CHECK-NEXT: [[LV_2:%.*]] = load i32, i32* [[LV_1]], align 4 -; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[DEST_I8]], i8* [[SRC_I8]], i64 16, i1 false) ; CHECK-NEXT: ret i32 [[LV_2]] ; %dest = alloca [16 x i8] diff --git a/llvm/test/Transforms/MemCpyOpt/load-store-to-memcpy.ll b/llvm/test/Transforms/MemCpyOpt/load-store-to-memcpy.ll --- a/llvm/test/Transforms/MemCpyOpt/load-store-to-memcpy.ll +++ b/llvm/test/Transforms/MemCpyOpt/load-store-to-memcpy.ll @@ -73,12 +73,13 @@ ; CHECK-NEXT: [[B:%.*]] = alloca [[T]], align 8 ; CHECK-NEXT: [[A_I8:%.*]] = bitcast %T* [[A]] to i8* ; CHECK-NEXT: call void @use(i8* [[A_I8]]) -; CHECK-NEXT: [[VAL:%.*]] = load [[T]], %T* [[A]], align 8 ; CHECK-NEXT: [[LV_1:%.*]] = load i32*, i32** [[PTR:%.*]], align 8 +; CHECK-NEXT: [[TMP1:%.*]] = bitcast %T* [[B]] to i8* +; CHECK-NEXT: [[TMP2:%.*]] = bitcast %T* [[A]] to i8* +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[TMP1]], i8* align 8 [[TMP2]], i64 8, i1 false) ; CHECK-NEXT: store i32 0, i32* [[LV_1]], align 4 -; CHECK-NEXT: store [[T]] [[VAL]], %T* [[B]], align 16 -; CHECK-NEXT: [[TMP1:%.*]] = bitcast %T* [[A]] to i8* -; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[TMP1]], i8 0, i64 8, i1 false) +; CHECK-NEXT: [[TMP3:%.*]] = bitcast %T* [[A]] to i8* +; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[TMP3]], i8 0, i64 8, i1 false) ; CHECK-NEXT: [[B_I8:%.*]] = bitcast %T* [[B]] to i8* ; CHECK-NEXT: call void @use(i8* [[B_I8]]) ; CHECK-NEXT: call void @use(i8* [[A_I8]]) @@ -111,11 +112,12 @@ ; CHECK-NEXT: [[B:%.*]] = alloca [[T]], align 8 ; CHECK-NEXT: [[A_I8:%.*]] = bitcast %T* [[A]] to i8* ; CHECK-NEXT: call void @use(i8* [[A_I8]]) -; CHECK-NEXT: [[VAL:%.*]] = load [[T]], %T* [[A]], align 8 +; CHECK-NEXT: [[TMP1:%.*]] = bitcast %T* [[B]] to i8* +; CHECK-NEXT: [[TMP2:%.*]] = bitcast %T* [[A]] to i8* +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 16 [[TMP1]], i8* align 8 [[TMP2]], i64 8, i1 false) ; CHECK-NEXT: call void @clobber() -; CHECK-NEXT: store [[T]] [[VAL]], %T* [[B]], align 16 -; CHECK-NEXT: [[TMP1:%.*]] = bitcast %T* [[A]] to i8* -; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[TMP1]], i8 0, i64 8, i1 false) +; CHECK-NEXT: [[TMP3:%.*]] = bitcast %T* [[A]] to i8* +; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[TMP3]], i8 0, i64 8, i1 false) ; CHECK-NEXT: [[B_I8:%.*]] = bitcast %T* [[B]] to i8* ; CHECK-NEXT: call void @use(i8* [[B_I8]]) ; CHECK-NEXT: call void @use(i8* [[A_I8]])