[MemCpyOpt] memset->memcpy forwarding with undef tail

Currently memcpyopt optimizes cases like

    memset(a, byte, N);
    memcpy(b, a, M);

to

    memset(a, byte, N);
    memset(b, byte, M);

if M <= N. Often this allows further simplifications down the line,
which drop the first memset entirely.

This patch extends this optimization for the case where M > N, but we
know that the bytes a[N..M] are undef due to alloca/lifetime.start.

This situation arises relatively often for Rust code, because Rust does
not initialize trailing structure padding and loves to insert redundant
memcpys. This also fixes https://bugs.llvm.org/show_bug.cgi?id=39844.

For the implementation, I'm reusing a bit of code for a similar existing
optimization (direct memcpy of undef). I've also added memset support to
MemDepAnalysis GetLocation -- Instead, getPointerDependencyFrom could be
used, but it seems to make more sense to add this to GetLocation and thus
make the computation cachable.

Differential Revision: https://reviews.llvm.org/D55120

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@348645 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Nikita Popov
2018-12-07 21:16:58 +00:00
parent f6f2b8d5fd
commit e9812ab427
3 changed files with 40 additions and 20 deletions
@@ -154,6 +154,12 @@ static ModRefInfo GetLocation(const Instruction *Inst, MemoryLocation &Loc,
return ModRefInfo::Mod;
}
if (const MemSetInst *MI = dyn_cast<MemSetInst>(Inst)) {
Loc = MemoryLocation::getForDest(MI);
// Conversatively assume ModRef for volatile memset.
return MI->isVolatile() ? ModRefInfo::ModRef : ModRefInfo::Mod;
}
if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(Inst)) {
switch (II->getIntrinsicID()) {
case Intrinsic::lifetime_start: