Skip to content

Commit 099cae5

Browse files
committed
[semantic-arc-opts] Handle arg extract + copy + borrow + use.
Specifically, now the optimizer can take the following code: sil @foo: $@convention(thin) (@guaranteed NativeObjectPair) -> () { bb0(%0 : @guaranteed $NativeObjectPair): %1 = struct_extract %0 : $NativeObjectPair, #NativeObjectPair.obj1 %2 = copy_value %1 : $Builtin.NativeObject %3 = begin_borrow %2 : $Builtin.NativeObject %foo = function_ref ... apply %foo(%3) : $@convention(thin) (@guaranteed Builtin.NativeObject) -> () end_borrow %3 : $Builtin.NativeObject destroy_value %2 : $Builtin.NativeObject ... } and eliminate all ownership instructions. I.e.: sil @foo: $@convention(thin) (@guaranteed NativeObjectPair) -> () { bb0(%0 : @guaranteed $NativeObjectPair): %1 = struct_extract %0 : $NativeObjectPair, #NativeObjectPair.obj1 %foo = function_ref .... apply %foo(%1) ... } Before this the optimizer could only eliminate 200 insts in the stdlib. With this change, we now can eliminate ~7000.
1 parent 5a73063 commit 099cae5

File tree

4 files changed

+54
-14
lines changed

4 files changed

+54
-14
lines changed

include/swift/SIL/OwnershipUtils.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,12 @@ bool isGuaranteedForwardingValueKind(SILNodeKind kind);
114114

115115
bool isGuaranteedForwardingValue(SILValue value);
116116

117+
bool isOwnershipForwardingInst(SILInstruction *i);
118+
117119
bool isGuaranteedForwardingInst(SILInstruction *i);
118120

119-
bool isOwnershipForwardingInst(SILInstruction *i);
121+
bool getUnderlyingBorrowIntroducers(SILValue inputValue,
122+
SmallVectorImpl<SILValue> &out);
120123

121124
} // namespace swift
122125

lib/SIL/OwnershipUtils.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "swift/SIL/OwnershipUtils.h"
14+
#include "swift/SIL/SILArgument.h"
1415
#include "swift/SIL/SILInstruction.h"
1516

1617
using namespace swift;
@@ -75,3 +76,38 @@ bool swift::isGuaranteedForwardingInst(SILInstruction *i) {
7576
bool swift::isOwnershipForwardingInst(SILInstruction *i) {
7677
return isOwnershipForwardingValueKind(SILNodeKind(i->getKind()));
7778
}
79+
80+
bool swift::getUnderlyingBorrowIntroducers(SILValue inputValue,
81+
SmallVectorImpl<SILValue> &out) {
82+
SmallVector<SILValue, 32> worklist;
83+
worklist.emplace_back(inputValue);
84+
85+
while (!worklist.empty()) {
86+
SILValue v = worklist.pop_back_val();
87+
88+
// First check if v is an introducer. If so, stash it and continue.
89+
if (isa<SILFunctionArgument>(v) || isa<LoadBorrowInst>(v) ||
90+
isa<BeginBorrowInst>(v)) {
91+
out.push_back(v);
92+
continue;
93+
}
94+
95+
// Otherwise if v is an ownership forwarding value, add its defining
96+
// instruction
97+
if (isGuaranteedForwardingValue(v)) {
98+
auto *i = v->getDefiningInstruction();
99+
assert(i);
100+
transform(i->getAllOperands(), std::back_inserter(worklist),
101+
[](const Operand &op) -> SILValue { return op.get(); });
102+
continue;
103+
}
104+
105+
// If v produces any ownership, then we can ignore it. Otherwise, we need to
106+
// return false since this is an introducer we do not understand.
107+
if (v.getOwnershipKind() != ValueOwnershipKind::Any &&
108+
v.getOwnershipKind() != ValueOwnershipKind::Trivial)
109+
return false;
110+
}
111+
112+
return true;
113+
}

lib/SILOptimizer/Mandatory/SemanticARCOpts.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#define DEBUG_TYPE "sil-semantic-arc-opts"
14+
#include "swift/Basic/STLExtras.h"
1415
#include "swift/SIL/BasicBlockUtils.h"
1516
#include "swift/SIL/OwnershipUtils.h"
1617
#include "swift/SIL/SILArgument.h"
1718
#include "swift/SIL/SILInstruction.h"
1819
#include "swift/SIL/SILVisitor.h"
19-
#include "swift/Basic/STLExtras.h"
2020
#include "swift/SILOptimizer/Analysis/PostOrderAnalysis.h"
2121
#include "swift/SILOptimizer/PassManager/Passes.h"
2222
#include "swift/SILOptimizer/PassManager/Transforms.h"
@@ -71,19 +71,20 @@ bool SemanticARCOptVisitor::visitBeginBorrowInst(BeginBorrowInst *bbi) {
7171
return true;
7272
}
7373

74-
/// TODO: Add support for begin_borrow, load_borrow.
75-
static bool canHandleOperand(SILValue operand) {
76-
if (auto *arg = dyn_cast<SILFunctionArgument>(operand)) {
77-
return arg->getOwnershipKind() == ValueOwnershipKind::Guaranteed;
78-
}
74+
static bool canHandleOperand(SILValue operand, SmallVectorImpl<SILValue> &out) {
75+
if (!getUnderlyingBorrowIntroducers(operand, out))
76+
return false;
7977

80-
return false;
78+
/// TODO: Add support for begin_borrow, load_borrow.
79+
return all_of(out, [](SILValue v) { return isa<SILFunctionArgument>(v); });
8180
}
8281

8382
static bool performGuaranteedCopyValueOptimization(CopyValueInst *cvi) {
83+
SmallVector<SILValue, 16> borrowIntroducers;
84+
8485
// Whitelist the operands that we know how to support and make sure
8586
// our operand is actually guaranteed.
86-
if (!canHandleOperand(cvi->getOperand()))
87+
if (!canHandleOperand(cvi->getOperand(), borrowIntroducers))
8788
return false;
8889

8990
// Then go over all of our uses. Find our destroying instructions
@@ -132,8 +133,8 @@ static bool performGuaranteedCopyValueOptimization(CopyValueInst *cvi) {
132133
//
133134
// TODO: When we support begin_borrow/load_borrow a linear linfetime
134135
// check will be needed here.
135-
assert(isa<SILFunctionArgument>(cvi->getOperand()) &&
136-
"This code must be updated for begin_borrow/load_borrow?!");
136+
assert(all_of(borrowIntroducers,
137+
[](SILValue v) { return isa<SILFunctionArgument>(v); }));
137138

138139
// Otherwise, we know that our copy_value/destroy_values are all
139140
// completely within the guaranteed value scope.

test/SILOptimizer/semantic-arc-opts.sil

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,16 +100,16 @@ bb0(%0 : @guaranteed $Builtin.NativeObject):
100100
return %9999 : $()
101101
}
102102

103-
// CHECK-LABEL: sil @struct_extract_guaranteed_use : $@convention(thin) (@guaranteed NativeObjectPair) -> () {
103+
// CHECK-LABEL: sil @copy_struct_extract_guaranteed_use : $@convention(thin) (@guaranteed NativeObjectPair) -> () {
104104
// CHECK: bb0([[ARG:%.*]] : @guaranteed $NativeObjectPair):
105105
// CHECK-NOT: copy_value
106106
// CHECK-NOT: begin_borrow
107107
// CHECK: [[FIELD:%.*]] = struct_extract [[ARG]]
108108
// CHECK: apply {{%.*}}([[FIELD]]) :
109109
// CHECK-NEXT: tuple
110110
// CHECK-NEXT: return
111-
// CHECK: } // end sil function 'struct_extract_guaranteed_use'
112-
sil @struct_extract_guaranteed_use : $@convention(thin) (@guaranteed NativeObjectPair) -> () {
111+
// CHECK: } // end sil function 'copy_struct_extract_guaranteed_use'
112+
sil @copy_struct_extract_guaranteed_use : $@convention(thin) (@guaranteed NativeObjectPair) -> () {
113113
bb0(%0 : @guaranteed $NativeObjectPair):
114114
%1 = copy_value %0 : $NativeObjectPair
115115
%2 = begin_borrow %1 : $NativeObjectPair

0 commit comments

Comments
 (0)