Index: lib/Transforms/Scalar/MemCpyOptimizer.cpp =================================================================== --- lib/Transforms/Scalar/MemCpyOptimizer.cpp +++ lib/Transforms/Scalar/MemCpyOptimizer.cpp @@ -698,6 +698,29 @@ return true; } } + + if (AllocaInst *AI = dyn_cast( + LI->getPointerOperand()->stripPointerCasts())) { + if (Argument *Arg = dyn_cast( + SI->getPointerOperand()->stripPointerCasts())) { + if (Arg->hasStructRetAttr() && Arg->hasNoAliasAttr() && + Arg->getType() == AI->getType()) { + AI->replaceAllUsesWith(Arg); + + MD->removeInstruction(SI); + SI->eraseFromParent(); + + MD->removeInstruction(LI); + LI->eraseFromParent(); + + MD->removeInstruction(AI); + AI->eraseFromParent(); + + ++NumMemCpyInstr; + return true; + } + } + } } } @@ -1177,6 +1200,8 @@ // lifetime copies undefined data, and we can therefore eliminate the // memcpy in favor of the data that was already at the destination. // d) memcpy from a just-memset'd source can be turned into memset. + // e) memcpy from an alloca to a noalias sret can be converted into direct + // access to the sret. if (DepInfo.isClobber()) { if (CallInst *C = dyn_cast(DepInfo.getInst())) { if (performCallSlotOptzn(M, M->getDest(), M->getSource(), @@ -1226,6 +1251,24 @@ return true; } + if (AllocaInst *AI = dyn_cast(M->getSource())) { + if (Argument *Arg = dyn_cast(M->getDest())) { + if (Arg->hasStructRetAttr() && Arg->hasNoAliasAttr() && + Arg->getType() == AI->getType()) { + AI->replaceAllUsesWith(Arg); + + MD->removeInstruction(M); + M->eraseFromParent(); + + MD->removeInstruction(AI); + AI->eraseFromParent(); + + ++NumMemCpyInstr; + return true; + } + } + } + return false; } Index: test/Transforms/MemCpyOpt/memcpy.ll =================================================================== --- test/Transforms/MemCpyOpt/memcpy.ll +++ test/Transforms/MemCpyOpt/memcpy.ll @@ -202,6 +202,53 @@ ret void } +define void @elide_memcpy_to_noalias_sret(%struct.big* noalias nocapture sret, + %struct.big* nocapture readonly, + %struct.big* nocapture readonly) { +; CHECK-LABEL: @elide_memcpy_to_noalias_sret +; CHECK-NOT: memcpy + %4 = alloca %struct.big, align 4 + %5 = bitcast %struct.big* %4 to i8* + call void @llvm.lifetime.start(i64 200, i8* %5) + br label %8 + +;