Index: llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp =================================================================== --- llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp +++ llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp @@ -1461,9 +1461,24 @@ llvm::PointerMayBeCaptured(SrcAlloca, /* ReturnCaptures=*/true, /* StoreCaptures= */ true)) return false; + // TODO: refine the before memcpy condition for dest alloca + // Bailout if any Mod except lifetime intrinsics exists before memcpy on the + // dest. + auto DestLoc = MemoryLocation(DestAlloca, LocationSize::precise(Size)); + for (User *U : DestAlloca->users()) { + if (auto *I = dyn_cast(U)) { + if (!I->comesBefore(Store)) + continue; + if (auto *II = dyn_cast(I); + II && II->isLifetimeStartOrEnd()) + continue; + if (isModSet(AA->getModRefInfo(I, DestLoc))) + return false; + } + } - // 3. The src has no read and no write except lifetime intrinsics, from after - // the full copy to the end of the BB. + // 3. The src has no read and no write except lifetime intrinsics, from + // after the full copy to the end of the BB. for (auto It = ++Store->getIterator(), E = Store->getParent()->end(); It != E; ++It) { // See all users of the SrcAlloca, between full copy and end of the BB. @@ -1485,39 +1500,35 @@ DestAlloca->replaceAllUsesWith(SrcAlloca); // Erase redundant lifetimes - // FIXME: currently this doesn't work correctly for lifetime.end IntrinsicInst *LifetimeStart = nullptr, *LifetimeEnd = nullptr; - for (auto It = SrcAlloca->user_begin(), E = SrcAlloca->user_end(); It != E; - ++It) { - if (auto *II = dyn_cast(*It); - II && II->isLifetimeStartOrEnd()) { + SmallVector LifetimeToErase; + for (User *U : SrcAlloca->users()) { + if (auto *II = dyn_cast(U)) { if (II->getIntrinsicID() == Intrinsic::lifetime_start) { - if (!LifetimeStart) { + if (!LifetimeStart) LifetimeStart = II; - continue; - } - if (II->comesBefore(LifetimeStart)) { - eraseInstruction(LifetimeStart); + else if (II->comesBefore(LifetimeStart)) { + LifetimeToErase.push_back(LifetimeStart); LifetimeStart = II; - continue; - } + } else + LifetimeToErase.push_back(II); } else if (II->getIntrinsicID() == Intrinsic::lifetime_end) { - if (!LifetimeEnd) { + if (!LifetimeEnd) LifetimeEnd = II; - continue; - } - if (LifetimeEnd->comesBefore(II)) { - eraseInstruction(LifetimeEnd); + else if (LifetimeEnd->comesBefore(II)) { + LifetimeToErase.push_back(LifetimeEnd); LifetimeEnd = II; - continue; - } + } else + LifetimeToErase.push_back(II); } - // FIXME: this is necessary to remove redundant lifetime.end, but breaks - // for some reasons - // eraseInstruction(II); } } + // FIXME: still crash on erase + for (auto *II : make_early_inc_range(LifetimeToErase)) { + eraseInstruction(II); + } + // Drop metadata on the source alloca. SrcAlloca->dropUnknownNonDebugMetadata();