Index: lib/Transforms/Scalar/DeadStoreElimination.cpp =================================================================== --- lib/Transforms/Scalar/DeadStoreElimination.cpp +++ lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -78,7 +78,7 @@ } bool runOnBasicBlock(BasicBlock &BB); - bool MemoryIsNotModifiedBetween(LoadInst *LI, StoreInst *SI); + bool MemoryIsNotModifiedBetween(Instruction *FirstI, Instruction *SecondI); bool HandleFree(CallInst *F); bool handleEndBlock(BasicBlock &BB); void RemoveAccessedObjects(const MemoryLocation &LoadedLoc, @@ -502,6 +502,22 @@ // If we're storing the same value back to a pointer that we just // loaded from, then the store can be removed. if (StoreInst *SI = dyn_cast(Inst)) { + + auto RemoveDeadInstAndUpdateBBI = [&](Instruction *DeadInst) { + // DeleteDeadInstruction can delete the current instruction. Save BBI + // in case we need it. + WeakVH NextInst(BBI); + + DeleteDeadInstruction(DeadInst, *MD, *TLI); + + if (!NextInst) // Next instruction deleted. + BBI = BB.begin(); + else if (BBI != BB.begin()) // Revisit this instruction if possible. + --BBI; + ++NumRedundantStores; + MadeChange = true; + }; + if (LoadInst *DepLoad = dyn_cast(SI->getValueOperand())) { if (SI->getPointerOperand() == DepLoad->getPointerOperand() && isRemovable(SI) && @@ -510,21 +526,28 @@ DEBUG(dbgs() << "DSE: Remove Store Of Load from same pointer:\n " << "LOAD: " << *DepLoad << "\n STORE: " << *SI << '\n'); - // DeleteDeadInstruction can delete the current instruction. Save BBI - // in case we need it. - WeakVH NextInst(BBI); - - DeleteDeadInstruction(SI, *MD, *TLI); - - if (!NextInst) // Next instruction deleted. - BBI = BB.begin(); - else if (BBI != BB.begin()) // Revisit this instruction if possible. - --BBI; - ++NumRedundantStores; - MadeChange = true; + RemoveDeadInstAndUpdateBBI(SI); continue; } } + + // Remove null stores into the calloc'ed objects + const DataLayout &DL = BB.getModule()->getDataLayout(); + Instruction *UnderlyingPointer = dyn_cast( + GetUnderlyingObject(SI->getPointerOperand(), DL)); + Constant *StoredConstant = dyn_cast(SI->getValueOperand()); + + if (UnderlyingPointer && isCallocLikeFn(UnderlyingPointer, TLI) && + StoredConstant && StoredConstant->isNullValue() && + isRemovable(SI) && + MemoryIsNotModifiedBetween(UnderlyingPointer, SI)) { + DEBUG(dbgs() + << "DSE: Remove null store to the calloc'ed object:\n DEAD: " + << *Inst << "\n OBJECT: " << *UnderlyingPointer << '\n'); + + RemoveDeadInstAndUpdateBBI(SI); + continue; + } } MemDepResult InstDep = MD->getDependency(Inst); @@ -633,52 +656,53 @@ return MadeChange; } -/// Returns true if the memory which is accessed by the store instruction is not -/// modified between the load and the store instruction. -/// Precondition: The store instruction must be dominated by the load +/// Returns true if the memory which is accessed by the second instruction is not +/// modified between the first and the second instruction. +/// Precondition: Second instruction must be dominated by the first /// instruction. -bool DSE::MemoryIsNotModifiedBetween(LoadInst *LI, StoreInst *SI) { +bool DSE::MemoryIsNotModifiedBetween(Instruction *FirstI, + Instruction *SecondI) { SmallVector WorkList; SmallPtrSet Visited; - BasicBlock::iterator LoadBBI(LI); - ++LoadBBI; - BasicBlock::iterator StoreBBI(SI); - BasicBlock *LoadBB = LI->getParent(); - BasicBlock *StoreBB = SI->getParent(); - MemoryLocation StoreLoc = MemoryLocation::get(SI); + BasicBlock::iterator FirstBBI(FirstI); + ++FirstBBI; + BasicBlock::iterator SecondBBI(SecondI); + BasicBlock *FirstBB = FirstI->getParent(); + BasicBlock *SecondBB = SecondI->getParent(); + MemoryLocation MemLoc = MemoryLocation::get(SecondI); // Start checking the store-block. - WorkList.push_back(StoreBB); + WorkList.push_back(SecondBB); bool isFirstBlock = true; // Check all blocks going backward until we reach the load-block. while (!WorkList.empty()) { BasicBlock *B = WorkList.pop_back_val(); - // Ignore instructions before LI if this is the LoadBB. - BasicBlock::iterator BI = (B == LoadBB ? LoadBBI : B->begin()); + // Ignore instructions before LI if this is the FirstBB. + BasicBlock::iterator BI = (B == FirstBB ? FirstBBI : B->begin()); BasicBlock::iterator EI; if (isFirstBlock) { - // Ignore instructions after SI if this is the first visit of StoreBB. - assert(B == StoreBB && "first block is not the store block"); - EI = StoreBBI; + // Ignore instructions after SI if this is the first visit of SecondBB. + assert(B == SecondBB && "first block is not the store block"); + EI = SecondBBI; isFirstBlock = false; } else { - // It's not StoreBB or (in case of a loop) the second visit of StoreBB. + // It's not SecondBB or (in case of a loop) the second visit of SecondBB. // In this case we also have to look at instructions after SI. EI = B->end(); } for (; BI != EI; ++BI) { Instruction *I = BI; - if (I->mayWriteToMemory() && I != SI) { - auto Res = AA->getModRefInfo(I, StoreLoc); + if (I->mayWriteToMemory() && I != SecondI) { + auto Res = AA->getModRefInfo(I, MemLoc); if (Res != MRI_NoModRef) return false; } } - if (B != LoadBB) { - assert(B != &LoadBB->getParent()->getEntryBlock() && + if (B != FirstBB) { + assert(B != &FirstBB->getParent()->getEntryBlock() && "Should not hit the entry block because SI must be dominated by LI"); for (auto PredI = pred_begin(B), PE = pred_end(B); PredI != PE; ++PredI) { if (!Visited.insert(*PredI).second) Index: test/Transforms/DeadStoreElimination/calloc-store.ll =================================================================== --- /dev/null +++ test/Transforms/DeadStoreElimination/calloc-store.ll @@ -0,0 +1,18 @@ +; RUN: opt < %s -basicaa -dse -S | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" + +; Function Attrs: nounwind +declare noalias i8* @calloc(i64, i64) + +; Function Attrs: nounwind uwtable +define noalias i32* @test_store() { +; CHECK-LABEL: test_store + %1 = tail call noalias i8* @calloc(i64 1, i64 4) + %2 = bitcast i8* %1 to i32* + ; This store is dead and should be removed + store i32 0, i32* %2, align 4 +; CHECK-NOT: store i32 0, i32* %2, align 4 + ret i32* %2 +} +