diff options
author | Chris Lattner <sabre@nondot.org> | 2009-09-01 17:56:32 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2009-09-01 17:56:32 +0000 |
commit | f41eaacee4a4a2d4339dd553626d98c73650c8c7 (patch) | |
tree | f8d379b48bf4fb692542a3f52545e959820d5538 /lib/Transforms/Scalar/MemCpyOptimizer.cpp | |
parent | c517cb006553320875544f39655c3299124be3ea (diff) |
enhance memcpy opt to turn memmoves into memcpy when the src/dest
don't alias. Remove an old and poorly reduced testcase that fails
with this transform for reasons unrelated to the original test.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@80693 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms/Scalar/MemCpyOptimizer.cpp')
-rw-r--r-- | lib/Transforms/Scalar/MemCpyOptimizer.cpp | 47 |
1 files changed, 41 insertions, 6 deletions
diff --git a/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/lib/Transforms/Scalar/MemCpyOptimizer.cpp index cd89235e47..a158f0a8f5 100644 --- a/lib/Transforms/Scalar/MemCpyOptimizer.cpp +++ b/lib/Transforms/Scalar/MemCpyOptimizer.cpp @@ -317,6 +317,7 @@ namespace { // Helper fuctions bool processStore(StoreInst *SI, BasicBlock::iterator &BBI); bool processMemCpy(MemCpyInst *M); + bool processMemMove(MemMoveInst *M); bool performCallSlotOptzn(MemCpyInst *cpy, CallInst *C); bool iterateOnFunction(Function &F); }; @@ -431,9 +432,8 @@ bool MemCpyOpt::processStore(StoreInst *SI, BasicBlock::iterator &BBI) { BasicBlock::iterator InsertPt = BI; if (MemSetF == 0) { - const Type *Tys[] = {Type::getInt64Ty(SI->getContext())}; - MemSetF = Intrinsic::getDeclaration(M, Intrinsic::memset, - Tys, 1); + const Type *Ty = Type::getInt64Ty(SI->getContext()); + MemSetF = Intrinsic::getDeclaration(M, Intrinsic::memset, &Ty, 1); } // Get the starting pointer of the block. @@ -679,11 +679,10 @@ bool MemCpyOpt::processMemCpy(MemCpyInst *M) { return false; // If all checks passed, then we can transform these memcpy's - const Type *Tys[1]; - Tys[0] = M->getLength()->getType(); + const Type *Ty = M->getLength()->getType(); Function *MemCpyFun = Intrinsic::getDeclaration( M->getParent()->getParent()->getParent(), - M->getIntrinsicID(), Tys, 1); + M->getIntrinsicID(), &Ty, 1); Value *Args[4] = { M->getRawDest(), MDep->getRawSource(), M->getLength(), M->getAlignmentCst() @@ -708,6 +707,36 @@ bool MemCpyOpt::processMemCpy(MemCpyInst *M) { return false; } +/// processMemMove - Transforms memmove calls to memcpy calls when the src/dst +/// are guaranteed not to alias. +bool MemCpyOpt::processMemMove(MemMoveInst *M) { + AliasAnalysis &AA = getAnalysis<AliasAnalysis>(); + + // If the memmove is a constant size, use it for the alias query, this allows + // us to optimize things like: memmove(P, P+64, 64); + uint64_t MemMoveSize = ~0ULL; + if (ConstantInt *Len = dyn_cast<ConstantInt>(M->getLength())) + MemMoveSize = Len->getZExtValue(); + + // See if the pointers alias. + if (AA.alias(M->getRawDest(), MemMoveSize, M->getRawSource(), MemMoveSize) != + AliasAnalysis::NoAlias) + return false; + + DEBUG(errs() << "MemCpyOpt: Optimizing memmove -> memcpy: " << *M << "\n"); + + // If not, then we know we can transform this. + Module *Mod = M->getParent()->getParent()->getParent(); + const Type *Ty = M->getLength()->getType(); + M->setOperand(0, Intrinsic::getDeclaration(Mod, Intrinsic::memcpy, &Ty, 1)); + + // MemDep may have over conservative information about this instruction, just + // conservatively flush it from the cache. + getAnalysis<MemoryDependenceAnalysis>().removeInstruction(M); + return true; +} + + // MemCpyOpt::iterateOnFunction - Executes one iteration of GVN. bool MemCpyOpt::iterateOnFunction(Function &F) { bool MadeChange = false; @@ -723,6 +752,12 @@ bool MemCpyOpt::iterateOnFunction(Function &F) { MadeChange |= processStore(SI, BI); else if (MemCpyInst *M = dyn_cast<MemCpyInst>(I)) MadeChange |= processMemCpy(M); + else if (MemMoveInst *M = dyn_cast<MemMoveInst>(I)) { + if (processMemMove(M)) { + --BI; // Reprocess the new memcpy. + MadeChange = true; + } + } } } |