Skip to content

Commit cea0f00

Browse files
committed
[InstructionDeleter] Delete dead load [take]s.
Previously, `isScopeAffectingInstructionDead` determined that an otherwise satisfactory `load` was not dead if it was a `load [take]`. The immediate effect was that dead `load [take]`s were not deleted. The downstream effect was that otherwise dead graphs of instructions would not be deleted. This was especially a problem for OSLogOptimization which deletes a great deal of code. Here, the InstructionDeleter is taught to compensate for the deletion of such `load [take]` by inserting `destroy_addr`s in their stead. rdar://117011668
1 parent 29acda5 commit cea0f00

File tree

4 files changed

+63
-11
lines changed

4 files changed

+63
-11
lines changed

lib/SILOptimizer/Utils/InstructionDeleter.cpp

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,9 @@ static bool isScopeAffectingInstructionDead(SILInstruction *inst,
9797
cast<LoadInst>(inst)->getOwnershipQualifier();
9898
// If the load creates a copy, it is dead, since we know that if at all it
9999
// is used, it is only in a destroy_value instruction.
100-
return (loadOwnershipQual == LoadOwnershipQualifier::Copy ||
100+
return (loadOwnershipQual == LoadOwnershipQualifier::Take ||
101+
loadOwnershipQual == LoadOwnershipQualifier::Copy ||
101102
loadOwnershipQual == LoadOwnershipQualifier::Trivial);
102-
// TODO: we can handle load [take] but we would have to know that the
103-
// operand has been consumed. Note that OperandOwnershipKind map does not
104-
// say this for load.
105103
}
106104
case SILInstructionKind::PartialApplyInst: {
107105
bool onlyTrivialArgs = true;
@@ -250,10 +248,19 @@ void InstructionDeleter::deleteWithUses(SILInstruction *inst, bool fixLifetimes,
250248
if (!operandValue)
251249
continue;
252250

253-
if (fixLifetimes && operand.isConsuming()) {
254-
SILBuilderWithScope builder(inst);
255-
auto *dvi = builder.createDestroyValue(inst->getLoc(), operandValue);
256-
getCallbacks().createdNewInst(dvi);
251+
if (fixLifetimes) {
252+
LoadInst *li = nullptr;
253+
if (operand.isConsuming()) {
254+
SILBuilderWithScope builder(inst);
255+
auto *dvi = builder.createDestroyValue(inst->getLoc(), operandValue);
256+
getCallbacks().createdNewInst(dvi);
257+
} else if ((li = dyn_cast<LoadInst>(inst)) &&
258+
li->getOwnershipQualifier() ==
259+
LoadOwnershipQualifier::Take) {
260+
SILBuilderWithScope builder(inst);
261+
auto *dai = builder.createDestroyAddr(inst->getLoc(), operandValue);
262+
getCallbacks().createdNewInst(dai);
263+
}
257264
}
258265
auto *operDef = operandValue->getDefiningInstruction();
259266
operand.drop();
@@ -419,4 +426,3 @@ void swift::recursivelyDeleteTriviallyDeadInstructions(
419426
nextInsts.clear();
420427
}
421428
}
422-

test/SILOptimizer/instruction_deleter.sil

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ struct MOS : ~Copyable {}
55
sil @getMOS : $() -> (@owned MOS)
66
sil @barrier : $() -> ()
77

8+
class C {}
9+
10+
sil @get : $<T> () -> (@out T)
11+
812
// CHECK-LABEL: begin running test {{.*}} on dontDeleteDeadMoveOnlyValue
913
// CHECK: Deleting-if-dead {{.*}} move_value
1014
// CHECK: deleteIfDead returned 0
@@ -28,3 +32,26 @@ sil [ossa] @dontDeleteDeadMoveOnlyValue : $() -> () {
2832
%retval = tuple ()
2933
return %retval : $()
3034
}
35+
36+
// CHECK-LABEL: begin running test {{.*}} on doDeleteLoadTake
37+
// CHECK: Deleting-if-dead {{%[^,]+}} = load [take]
38+
// CHECK: deleteIfDead returned 1
39+
// CHECK-LABEL: sil [ossa] @doDeleteLoadTake : {{.*}} {
40+
// CHECK: [[STACK:%[^,]+]] = alloc_stack $C
41+
// CHECK: [[GET:%[^,]+]] = function_ref @get
42+
// CHECK: apply [[GET]]<C>([[STACK]])
43+
// CHECK: destroy_addr [[STACK]]
44+
// CHECK: dealloc_stack [[STACK]]
45+
// CHECK-LABEL: } // end sil function 'doDeleteLoadTake'
46+
// CHECK-LABEL: end running test {{.*}} on doDeleteLoadTake
47+
sil [ossa] @doDeleteLoadTake : $() -> () {
48+
%stack = alloc_stack $C
49+
%get = function_ref @get : $@convention(thin) <T> () -> (@out T)
50+
apply %get<C>(%stack) : $@convention(thin) <T> () -> (@out T)
51+
specify_test "deleter-delete-if-dead @instruction"
52+
%c = load [take] %stack : $*C
53+
destroy_value %c : $C
54+
dealloc_stack %stack : $*C
55+
%retval = tuple ()
56+
return %retval : $()
57+
}

test/SILOptimizer/predictable_deadalloc_elim_ownership.sil

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,8 +156,7 @@ bb0(%0 : @owned $Builtin.NativeObject, %1 : $*Builtin.NativeObject):
156156
// CHECK: bb0([[ARG0:%.*]] : @owned $Builtin.NativeObject, [[ARG1:%.*]] : $*Builtin.NativeObject):
157157
// CHECK-NOT: alloc_stack
158158
// CHECK: destroy_value [[ARG0]]
159-
// CHECK: [[ARG1_LOADED:%.*]] = load [take] [[ARG1]]
160-
// CHECK: destroy_value [[ARG1_LOADED]]
159+
// CHECK: destroy_addr [[ARG1]]
161160
// CHECK: } // end sil function 'simple_init_take'
162161
sil [ossa] @simple_init_take : $@convention(thin) (@owned Builtin.NativeObject, @in Builtin.NativeObject) -> () {
163162
bb0(%0 : @owned $Builtin.NativeObject, %1 : $*Builtin.NativeObject):
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// RUN: %target-swift-frontend -disable-availability-checking -emit-sil -verify %s | %FileCheck %s
2+
3+
// REQUIRES: objc_interop
4+
5+
import Foundation
6+
import os.log
7+
8+
struct Log {
9+
static let attachmentLedgerTopic = Logger(
10+
subsystem: "com.xxx.yyy.zzz",
11+
category: "ccc")
12+
}
13+
14+
// CHECK-LABEL: sil @logWriter : {{.*}} {
15+
// CHECK-NOT: $s2os18OSLogInterpolationV13appendLiteralyySSF
16+
// CHECK-LABEL: } // end sil function 'logWriter'
17+
@_silgen_name("logWriter")
18+
public func logWriter(_ attachmentID: UUID) {
19+
Log.attachmentLedgerTopic.info("aaa: \(attachmentID)")
20+
}

0 commit comments

Comments
 (0)