Skip to content

Commit 3e8948e

Browse files
committed
[CopyPropagation] Hoist lexical end_borrows over some applies.
1 parent bfd78d6 commit 3e8948e

File tree

2 files changed

+81
-20
lines changed

2 files changed

+81
-20
lines changed

lib/SILOptimizer/Utils/ShrinkBorrowScope.cpp

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ class ShrinkBorrowScope {
5454
SmallPtrSet<SILBasicBlock *, 8> blocksWithReachedTops;
5555
SmallPtrSet<SILBasicBlock *, 8> blocksToEndAtTop;
5656

57+
llvm::SmallDenseMap<ApplySite, size_t> transitiveUsesPerApplySite;
58+
5759
// The list of blocks to look for new points at which to insert end_borrows
5860
// in. A block must not be processed if all of its successors have not yet
5961
// been. For that reason, it is necessary to allow the same block to be
@@ -81,6 +83,12 @@ class ShrinkBorrowScope {
8183
});
8284
}
8385

86+
bool isBarrierApply(SILInstruction *instruction) {
87+
// For now, treat every apply (that doesn't use the borrowed value) as a
88+
// barrier.
89+
return isa<ApplySite>(instruction);
90+
}
91+
8492
bool mayAccessPointer(SILInstruction *instruction) {
8593
if (!instruction->mayReadOrWriteMemory())
8694
return false;
@@ -100,9 +108,70 @@ class ShrinkBorrowScope {
100108
}
101109

102110
bool isDeinitBarrier(SILInstruction *instruction) {
103-
return users.contains(instruction) || instruction->maySynchronize() ||
104-
mayAccessPointer(instruction, value) ||
105-
mayLoadWeakOrUnowned(instruction, value);
111+
return isBarrierApply(instruction) || instruction->maySynchronize() ||
112+
mayAccessPointer(instruction) || mayLoadWeakOrUnowned(instruction);
113+
}
114+
115+
bool canReplaceValueWithBorrowedValue(SILValue value) {
116+
while (true) {
117+
auto *instruction = value.getDefiningInstruction();
118+
if (!instruction)
119+
return false;
120+
if (auto *cvi = dyn_cast<CopyValueInst>(instruction)) {
121+
value = cvi->getOperand();
122+
continue;
123+
} else if (auto *bbi = dyn_cast<BeginBorrowInst>(instruction)) {
124+
if (bbi == introducer) {
125+
return true;
126+
}
127+
}
128+
return false;
129+
}
130+
}
131+
132+
size_t usesInApply(ApplySite apply) {
133+
if (auto count = transitiveUsesPerApplySite.lookup(apply))
134+
return count;
135+
return 0;
136+
}
137+
138+
bool tryHoistOverInstruction(SILInstruction *instruction) {
139+
if (users.contains(instruction)) {
140+
if (auto apply = ApplySite::isa(instruction)) {
141+
SmallVector<int, 2> rewritableArgumentIndices;
142+
auto count = apply.getNumArguments();
143+
for (unsigned index = 0; index < count; ++index) {
144+
auto argument = apply.getArgument(index);
145+
if (canReplaceValueWithBorrowedValue(argument)) {
146+
rewritableArgumentIndices.push_back(index);
147+
}
148+
}
149+
if (rewritableArgumentIndices.size() != usesInApply(apply)) {
150+
return false;
151+
}
152+
// We can rewrite all the arguments which are transitive uses of the
153+
// borrow.
154+
for (auto index : rewritableArgumentIndices) {
155+
auto argument = apply.getArgument(index);
156+
auto borrowee = introducer->getOperand();
157+
if (auto *cvi = dyn_cast<CopyValueInst>(argument)) {
158+
cvi->setOperand(borrowee);
159+
} else {
160+
apply.setArgument(index, borrowee);
161+
}
162+
}
163+
return true;
164+
} else if (auto *bbi = dyn_cast<BeginBorrowInst>(instruction)) {
165+
if (bbi->isLexical() &&
166+
canReplaceValueWithBorrowedValue(bbi->getOperand())) {
167+
auto borrowee = introducer->getOperand();
168+
bbi->setOperand(borrowee);
169+
return true;
170+
}
171+
}
172+
return false;
173+
}
174+
return !isDeinitBarrier(instruction);
106175
}
107176
};
108177

@@ -136,6 +205,9 @@ bool ShrinkBorrowScope::populateUsers() {
136205
for (auto *usePoint : usePoints) {
137206
auto *user = usePoint->getUser();
138207
users.insert(user);
208+
if (auto apply = ApplySite::isa(user)) {
209+
++transitiveUsesPerApplySite[apply];
210+
}
139211
}
140212
return true;
141213
}
@@ -195,7 +267,7 @@ void ShrinkBorrowScope::findBarriers() {
195267
barrier = instruction;
196268
break;
197269
}
198-
if (isDeinitBarrier(instruction, borrowedValue.value)) {
270+
if (!tryHoistOverInstruction(instruction)) {
199271
barrier = instruction;
200272
break;
201273
}

test/SILOptimizer/shrink_borrow_scope.sil

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,8 @@ sil [ossa] @callee_optional_d_guaranteed: $@convention(thin) (@guaranteed Option
4242
// Hoist over br.
4343
// CHECK-LABEL: sil [ossa] @hoist_over_branch_1 : {{.*}} {
4444
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
45-
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
4645
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
47-
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[LIFETIME]])
48-
// CHECK: end_borrow [[LIFETIME]]
46+
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[INSTANCE]])
4947
// CHECK: br [[EXIT:bb[0-9]+]]
5048
// CHECK: [[EXIT]]:
5149
// CHECK: return [[INSTANCE]]
@@ -64,10 +62,8 @@ bl1:
6462
// Hoist over cond_br.
6563
// CHECK-LABEL: sil [ossa] @hoist_over_branch_2 : {{.*}} {
6664
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
67-
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
6865
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
69-
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[LIFETIME]])
70-
// CHECK: end_borrow [[LIFETIME]]
66+
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[INSTANCE]])
7167
// CHECK: cond_br undef, [[BL1:bb[0-9]+]], [[BL2:bb[0-9]+]]
7268
// CHECK: [[BL1]]:
7369
// CHECK: br [[EXIT:bb[0-9]+]]
@@ -95,10 +91,8 @@ exit:
9591
// Hoist over two brs.
9692
// CHECK-LABEL: sil [ossa] @hoist_over_branch_3 : {{.*}} {
9793
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
98-
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
9994
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
100-
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[LIFETIME]])
101-
// CHECK: end_borrow [[LIFETIME]]
95+
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[INSTANCE]])
10296
// CHECK: cond_br undef, [[BL1:bb[0-9]+]], [[BL2:bb[0-9]+]]
10397
// CHECK: [[BL1]]:
10498
// CHECK: br [[EXIT:bb[0-9]+]]
@@ -125,15 +119,12 @@ exit:
125119
// Don't hoist over 1 / 2 brs.
126120
// CHECK-LABEL: sil [ossa] @hoist_over_branch_4 : {{.*}} {
127121
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C):
128-
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
129122
// CHECK: cond_br undef, [[BL1:bb[0-9]+]], [[BL2:bb[0-9]+]]
130123
// CHECK: [[BL1]]:
131124
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
132-
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[LIFETIME]])
133-
// CHECK: end_borrow [[LIFETIME]]
125+
// CHECK: {{%[^,]+}} = apply [[CALLEE_GUARANTEED]]([[INSTANCE]])
134126
// CHECK: br [[EXIT:bb[0-9]+]]
135127
// CHECK: [[BL2]]:
136-
// CHECK: end_borrow [[LIFETIME]]
137128
// CHECK: br [[EXIT]]
138129
// CHECK: [[EXIT]]:
139130
// CHECK: return [[INSTANCE]]
@@ -156,10 +147,8 @@ exit:
156147
// Hoist over switch_enum destinations.
157148
// CHECK-LABEL: sil [ossa] @hoist_over_branch_5 : {{.*}} {
158149
// CHECK: {{bb[0-9]+}}([[INSTANCE:%[^,]+]] : @owned $C, [[CASE:%[^,]+]] : $OneOfThree):
159-
// CHECK: [[LIFETIME:%[^,]+]] = begin_borrow [[INSTANCE]]
160150
// CHECK: [[CALLEE_GUARANTEED:%[^,]+]] = function_ref @callee_guaranteed
161-
// CHECK: {{%[0-9]+}} = apply [[CALLEE_GUARANTEED]]([[LIFETIME]])
162-
// CHECK: end_borrow [[LIFETIME]]
151+
// CHECK: {{%[0-9]+}} = apply [[CALLEE_GUARANTEED]]([[INSTANCE]])
163152
// CHECK: switch_enum [[CASE]] : $OneOfThree, case #OneOfThree.one!enumelt: [[ONE_DEST:bb[0-9]+]], case #OneOfThree.two!enumelt: [[TWO_DEST:bb[0-9]+]], case #OneOfThree.three!enumelt: [[THREE_DEST:bb[0-9]+]]
164153
// CHECK: [[ONE_DEST]]:
165154
// CHECK: br [[EXIT:bb[0-9]+]]

0 commit comments

Comments
 (0)