Skip to content

[LVA] Record store as read of source for reference types. #31131

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions lib/SILOptimizer/Analysis/MemoryBehavior.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
5 changes: 5 additions & 0 deletions lib/SILOptimizer/Transforms/DeadStoreElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
50 changes: 35 additions & 15 deletions test/SILOptimizer/dead_store_elim.sil
Original file line number Diff line number Diff line change
Expand Up @@ -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 } <B>
%1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <B>, 0
store %0 to %1a : $*B
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We lose this optimization when the source is a reference type. I think that's a rare case but, I would like to add this back as a special-case optimization in another patch.

store %0 to %1a : $*B
%4 = tuple()
return %4 : $()
}

// CHECK-LABEL: sil @dead_store_elimination_over_noread_builtins
// CHECK: bb0
// CHECK-NEXT: load
Expand Down Expand Up @@ -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 : $()
}