diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp --- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -816,6 +816,30 @@ }); } +// Collect stack objects that are dead at the end of the function. +static void +collectNonEscapedObjects(const Function &F, + SmallSetVector &NonEscapedObjects, + const TargetLibraryInfo *TLI) { + // Find all of the alloca'd pointers in the entry block. + const BasicBlock &Entry = F.front(); + for (const Instruction &I : Entry) { + if (isa(&I)) + NonEscapedObjects.insert(&I); + + // Okay, so these are dead heap objects, but if the pointer never escapes + // then it's leaked by this function anyways. + else if (isAllocLikeFn(&I, TLI) && !PointerMayBeCaptured(&I, true, true)) + NonEscapedObjects.insert(&I); + } + + // Treat byval or inalloca arguments the same, stores to them are dead at the + // end of the function. + for (const Argument &AI : F.args()) + if (AI.hasPassPointeeByValueAttr()) + NonEscapedObjects.insert(&AI); +} + /// Remove dead stores to stack-allocated locations in the function end block. /// Ex: /// %A = alloca i32 @@ -832,24 +856,7 @@ // Keep track of all of the stack objects that are dead at the end of the // function. SmallSetVector DeadStackObjects; - - // Find all of the alloca'd pointers in the entry block. - BasicBlock &Entry = BB.getParent()->front(); - for (Instruction &I : Entry) { - if (isa(&I)) - DeadStackObjects.insert(&I); - - // Okay, so these are dead heap objects, but if the pointer never escapes - // then it's leaked by this function anyways. - else if (isAllocLikeFn(&I, TLI) && !PointerMayBeCaptured(&I, true, true)) - DeadStackObjects.insert(&I); - } - - // Treat byval or inalloca arguments the same, stores to them are dead at the - // end of the function. - for (Argument &AI : BB.getParent()->args()) - if (AI.hasPassPointeeByValueAttr()) - DeadStackObjects.insert(&AI); + collectNonEscapedObjects(*BB.getParent(), DeadStackObjects, TLI); const DataLayout &DL = BB.getModule()->getDataLayout(); @@ -2122,6 +2129,35 @@ for (auto &KV : State.IOLs) MadeChange |= removePartiallyOverlappedStores(&AA, DL, KV.second); + // Keep track of all of the stack objects that are dead at the end of the + // function. + SmallSetVector DeadStackObjects; + collectNonEscapedObjects(F, DeadStackObjects, &TLI); + for (MemoryDef *Current : State.MemDefs) { + if (State.SkipStores.count(Current)) + continue; + Instruction *SI = Current->getMemoryInst(); + if (!Current->use_empty()) + continue; + + LLVM_DEBUG(dbgs() << "No MemoryUse uses " << *Current << " (" << *SI + << ")\n"); + + // See through pointer-to-pointer bitcasts + SmallVector Pointers; + GetUnderlyingObjects(getStoredPointerOperand(SI), Pointers, DL); + + // Stores to stack values are valid candidates for removal. + bool AllDead = all_of(Pointers, [&DeadStackObjects](const Value *Pointer) { + return DeadStackObjects.count(Pointer); + }); + if (AllDead) { + State.deleteDeadInstruction(SI); + MadeChange = true; + continue; + } + } + return MadeChange; } } // end anonymous namespace diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/mda-with-dbg-values.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/mda-with-dbg-values.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/mda-with-dbg-values.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/mda-with-dbg-values.ll @@ -69,8 +69,8 @@ !20 = !DILocation(line: 9, column: 5, scope: !14) !21 = !DILocation(line: 10, column: 1, scope: !14) -; Check that the store is removed and that the memcpy is still there +; Check that the store and memcpy are removed ; CHECK-LABEL: foo ; CHECK-NOT: store i8 -; CHECK: call void @llvm.memcpy +; CHECK-NOT: call void @llvm.memcpy ; CHECK: ret void diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-captures.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-captures.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-captures.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-captures.ll @@ -207,15 +207,13 @@ call void @capture(i8* %m) ret i8* %m } -; TODO: Remove store in exit. + ; Stores to stack objects can be eliminated if they are not captured inside the function. define void @test_alloca_nocapture_1() { ; CHECK-LABEL: @test_alloca_nocapture_1( -; CHECK-NEXT: [[M:%.*]] = alloca i8 ; CHECK-NEXT: call void @foo() ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: exit: -; CHECK-NEXT: store i8 1, i8* [[M]] ; CHECK-NEXT: ret void ; %m = alloca i8 @@ -228,7 +226,6 @@ ret void } -; TODO: Remove store in exit. ; Cannot remove first store i8 0, i8* %m, as the call to @capture captures the object. define void @test_alloca_capture_1() { ; CHECK-LABEL: @test_alloca_capture_1( @@ -237,7 +234,6 @@ ; CHECK-NEXT: call void @capture(i8* [[M]]) ; CHECK-NEXT: br label [[EXIT:%.*]] ; CHECK: exit: -; CHECK-NEXT: store i8 1, i8* [[M]] ; CHECK-NEXT: ret void ; %m = alloca i8 @@ -250,7 +246,6 @@ ret void } -; TODO: Remove store at exit. ; We can remove the last store to %m, even though it escapes because the alloca ; becomes invalid after the function returns. define void @test_alloca_capture_2(%S1* %E) { @@ -260,7 +255,6 @@ ; CHECK: exit: ; CHECK-NEXT: [[F_PTR:%.*]] = getelementptr [[S1:%.*]], %S1* [[E:%.*]], i32 0, i32 0 ; CHECK-NEXT: store i8* [[M]], i8** [[F_PTR]] -; CHECK-NEXT: store i8 1, i8* [[M]] ; CHECK-NEXT: ret void ; %m = alloca i8 diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-exceptions.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-exceptions.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-exceptions.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-exceptions.ll @@ -29,7 +29,6 @@ ; CHECK-NEXT: [[C1:%.*]] = cleanuppad within none [] ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: -; CHECK-NEXT: store i32 40, i32* [[SV]] ; CHECK-NEXT: ret void ; block1: diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-memintrinsics.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-memintrinsics.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-memintrinsics.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-memintrinsics.ll @@ -204,20 +204,12 @@ define void @alloca_3(i1 %c) { ; CHECK-LABEL: @alloca_3( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[P_ALLOCA:%.*]] = alloca [32 x i32] -; CHECK-NEXT: [[P:%.*]] = bitcast [32 x i32]* [[P_ALLOCA]] to i32* -; CHECK-NEXT: [[ARRAYIDX0:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 1 -; CHECK-NEXT: [[P3:%.*]] = bitcast i32* [[ARRAYIDX0]] to i8* -; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, i8* [[P3]], i64 4 -; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* align 4 [[TMP0]], i8 0, i64 24, i1 false) ; CHECK-NEXT: br i1 [[C:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: ; CHECK-NEXT: br label [[BB3:%.*]] ; CHECK: bb2: ; CHECK-NEXT: br label [[BB3]] ; CHECK: bb3: -; CHECK-NEXT: [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, i32* [[P]], i64 1 -; CHECK-NEXT: store i32 1, i32* [[ARRAYIDX1]], align 4 ; CHECK-NEXT: ret void ; entry: diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-multipath.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-multipath.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-multipath.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-multipath.ll @@ -589,14 +589,11 @@ ; CHECK-LABEL: @alloca_5( ; CHECK-NEXT: bb: ; CHECK-NEXT: [[TMP:%.*]] = alloca [[STRUCT_BLAM_4:%.*]], align 8 -; CHECK-NEXT: [[TMP36:%.*]] = getelementptr inbounds [[STRUCT_BLAM_4]], %struct.blam.4* [[TMP]], i64 0, i32 0, i32 1 -; CHECK-NEXT: [[TMP37:%.*]] = bitcast i64** [[TMP36]] to i8* ; CHECK-NEXT: [[TMP38:%.*]] = getelementptr inbounds [[STRUCT_BLAM_4]], %struct.blam.4* [[TMP]], i64 0, i32 0, i32 3 ; CHECK-NEXT: [[TMP39:%.*]] = bitcast i64* [[TMP38]] to i64* ; CHECK-NEXT: store i64 0, i64* [[TMP39]], align 4 ; CHECK-NEXT: br i1 [[C:%.*]], label [[BB46:%.*]], label [[BB47:%.*]] ; CHECK: bb46: -; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 8 dereferenceable(20) [[TMP37]], i8 0, i64 26, i1 false) ; CHECK-NEXT: ret void ; CHECK: bb47: ; CHECK-NEXT: [[TMP48:%.*]] = getelementptr inbounds [[STRUCT_BLAM_4]], %struct.blam.4* [[TMP]], i64 0, i32 0, i32 2 diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-simple.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-simple.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-simple.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/multiblock-simple.ll @@ -174,10 +174,8 @@ define void @test11() { ; CHECK-LABEL: @test11( -; CHECK-NEXT: [[P:%.*]] = alloca i32, align 4 ; CHECK-NEXT: br i1 true, label [[BB1:%.*]], label [[BB2:%.*]] ; CHECK: bb1: -; CHECK-NEXT: store i32 0, i32* [[P]], align 4 ; CHECK-NEXT: br label [[BB3:%.*]] ; CHECK: bb2: ; CHECK-NEXT: ret void diff --git a/llvm/test/Transforms/DeadStoreElimination/MSSA/simple.ll b/llvm/test/Transforms/DeadStoreElimination/MSSA/simple.ll --- a/llvm/test/Transforms/DeadStoreElimination/MSSA/simple.ll +++ b/llvm/test/Transforms/DeadStoreElimination/MSSA/simple.ll @@ -672,3 +672,14 @@ store volatile i32 3, i32* %P, align 4 ret void } + +define void @test48_volatile() { +; CHECK-LABEL: @test48_volatile( +; CHECK-NEXT: [[P:%.*]] = alloca i32 +; CHECK-NEXT: store volatile i32 2, i32* [[P]], align 4 +; CHECK-NEXT: ret void +; + %P = alloca i32 + store volatile i32 2, i32* %P, align 4 + ret void +}