diff --git a/lib/SILOptimizer/Analysis/MemoryBehavior.cpp b/lib/SILOptimizer/Analysis/MemoryBehavior.cpp index e3e2e5fd1d002..90823a0cdc870 100644 --- a/lib/SILOptimizer/Analysis/MemoryBehavior.cpp +++ b/lib/SILOptimizer/Analysis/MemoryBehavior.cpp @@ -250,21 +250,33 @@ MemBehavior MemoryBehaviorVisitor::visitLoadInst(LoadInst *LI) { } MemBehavior MemoryBehaviorVisitor::visitStoreInst(StoreInst *SI) { + MemBehavior srcBehabior = MemBehavior::None; + if (SI->getSrc()->getType().hasReferenceSemantics()) + srcBehabior = MemBehavior::MayRead; + + // TODO: Is there any other possible type that has reference/pointer semantics + // but isn't a reference or pointer? + if (SI->getSrc()->getType().getASTType() == + SI->getSrc()->getType().getASTContext().TheRawPointerType) + srcBehabior = MemBehavior::MayRead; + // No store besides the initialization of a "let"-variable // can have any effect on the value of this "let" variable. if (isLetValue() && (getAccessedAddress(SI->getDest()) != getValueAddress())) { - return MemBehavior::None; + return srcBehabior; } // If the store dest cannot alias the pointer in question, then the // specified value cannot be modified by the store. if (!mayAlias(SI->getDest())) - return MemBehavior::None; + return srcBehabior; // Otherwise, a store just writes. LLVM_DEBUG(llvm::dbgs() << " Could not prove store does not alias inst. " "Returning MayWrite.\n"); - return MemBehavior::MayWrite; + if (srcBehabior == MemBehavior::None) + return MemBehavior::MayWrite; + return MemBehavior::MayReadWrite; } MemBehavior MemoryBehaviorVisitor::visitBuiltinInst(BuiltinInst *BI) { diff --git a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp index ab7c7414b8607..5dc29aa009dce 100644 --- a/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp +++ b/lib/SILOptimizer/Transforms/DeadStoreElimination.cpp @@ -984,6 +984,11 @@ void DSEContext::processWrite(SILInstruction *I, SILValue Val, SILValue Mem, S->DeadStores.push_back(I); ++NumDeadStores; return; + } else { + // If the store isn't dead there's a possibility that the store reads memory + // because the source is some kind of pointer or reference. Make sure we + // process this. + processUnknownReadInstForDSE(I); } // Partial dead store - stores to some locations are dead, but not all. This diff --git a/test/SILOptimizer/dead_store_elim.sil b/test/SILOptimizer/dead_store_elim.sil index 0864c4a97c40a..e755691325fe2 100644 --- a/test/SILOptimizer/dead_store_elim.sil +++ b/test/SILOptimizer/dead_store_elim.sil @@ -231,21 +231,6 @@ bb0: return %4 : $() } -// CHECK-LABEL: sil @store_after_store -// CHECK: bb0 -// CHECK: {{ store}} -// CHECK-NOT: {{ store}} -// CHECK: return -sil @store_after_store : $@convention(thin) (@owned B) -> () { -bb0(%0 : $B): - %1 = alloc_box $<τ_0_0> { var τ_0_0 } - %1a = project_box %1 : $<τ_0_0> { var τ_0_0 } , 0 - store %0 to %1a : $*B - store %0 to %1a : $*B - %4 = tuple() - return %4 : $() -} - // CHECK-LABEL: sil @dead_store_elimination_over_noread_builtins // CHECK: bb0 // CHECK-NEXT: load @@ -1519,3 +1504,38 @@ bb0: dealloc_ref [stack] %1 : $foo return %3 : $Int } + +class F { } + +struct S { + var f : F +} + +struct U { + var s : S +} + +// Test that the second store is recorded as a read of the source. +// Otherwise the first store will be removed. +// CHECK-LABEL: @store_is_read_of_src +// CHECK: store {{%[0-9]+}} to {{%[0-9]+}} : $*S +// CHECK: store {{%[0-9]+}} to {{%[0-9]+}} : $*Builtin.RawPointer +// CHECK: store {{%[0-9]+}} to {{%[0-9]+}} : $*F +// CHECK-LABEL: end sil function 'store_is_read_of_src' +sil @store_is_read_of_src : $@convention(thin) (S, @inout F) -> () { +bb0(%0 : $S, %f : $*F): + %2 = alloc_stack $S, var, name "vs" + store %0 to %2 : $*S + %4 = address_to_pointer %2 : $*S to $Builtin.RawPointer + %9 = alloc_stack $U + %10 = unchecked_addr_cast %9 : $*U to $*Builtin.RawPointer + store %4 to %10 : $*Builtin.RawPointer + %12 = load %9 : $*U + %15 = struct_extract %12 : $U, #U.s + %16 = struct_extract %15 : $S, #S.f + dealloc_stack %9 : $*U + store %16 to %f : $*F + dealloc_stack %2 : $*S + %19 = tuple () + return %19 : $() +}