Skip to content

Commit f85430f

Browse files
authored
Merge pull request #63255 from gottesmm/pr-f6f932ba70eaa205c45042884148ff1033d9a416
[move-only] Make sure that we insert compensating destroys for phi values
2 parents b5ca122 + 97f742d commit f85430f

File tree

3 files changed

+96
-7
lines changed

3 files changed

+96
-7
lines changed

lib/SILOptimizer/Mandatory/MoveOnlyObjectChecker.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,13 +177,12 @@ struct BorrowToDestructureTransform {
177177
DiagnosticEmitter &diagnosticEmitter;
178178
FieldSensitiveSSAPrunedLiveRange liveness;
179179
SmallVector<Operand *, 8> destructureNeedingUses;
180-
SmallVector<Operand *, 8> livenessNeedingUses;
181-
SmallVector<SILInstruction *, 8> endScopeInsts;
182180
PostOrderAnalysis *poa;
183181
PostOrderFunctionInfo *pofi = nullptr;
184182
Optional<AvailableValueStore> blockToAvailableValues;
185183
SILValue initialValue;
186184
SmallVector<SILInstruction *, 8> createdDestructures;
185+
SmallVector<SILPhiArgument *, 8> createdPhiArguments;
187186

188187
using InterestingUser = FieldSensitivePrunedLiveness::InterestingUser;
189188
SmallFrozenMultiMap<SILBasicBlock *, std::pair<Operand *, InterestingUser>, 8>

lib/SILOptimizer/Mandatory/MoveOnlyUtils.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@ bool BorrowToDestructureTransform::gatherUses(
135135
blocksToUses.insert(
136136
nextUse->getParentBlock(),
137137
{nextUse, {*leafRange, false /*is lifetime ending*/}});
138-
livenessNeedingUses.push_back(nextUse);
139138
liveness.updateForUse(nextUse->getUser(), *leafRange,
140139
false /*is lifetime ending*/);
141140
continue;
@@ -146,7 +145,6 @@ bool BorrowToDestructureTransform::gatherUses(
146145
// Ignore destroy_value, we are going to eliminate them.
147146
if (isa<DestroyValueInst>(nextUse->getUser())) {
148147
LLVM_DEBUG(llvm::dbgs() << " Found destroy value!\n");
149-
endScopeInsts.push_back(nextUse->getUser());
150148
continue;
151149
}
152150

@@ -186,7 +184,6 @@ bool BorrowToDestructureTransform::gatherUses(
186184
continue;
187185
case OperandOwnership::EndBorrow:
188186
LLVM_DEBUG(llvm::dbgs() << " Found end borrow!\n");
189-
endScopeInsts.push_back(nextUse->getUser());
190187
continue;
191188
case OperandOwnership::Reborrow:
192189
llvm_unreachable("Unsupported for now?!");
@@ -879,8 +876,12 @@ BorrowToDestructureTransform::computeAvailableValues(SILBasicBlock *block) {
879876
}
880877

881878
// Ok, we need to actually construct a phi.
882-
SILType offsetType = smallestTypeAvailable[i]->second;
883-
newValues[i] = block->createPhiArgument(offsetType, OwnershipKind::Owned);
879+
{
880+
SILType offsetType = smallestTypeAvailable[i]->second;
881+
auto *phi = block->createPhiArgument(offsetType, OwnershipKind::Owned);
882+
newValues[i] = phi;
883+
createdPhiArguments.push_back(phi);
884+
}
884885

885886
for (auto *predBlock : predsSkippingBackEdges) {
886887
auto &predAvailableValues = computeAvailableValues(predBlock);
@@ -1299,6 +1300,23 @@ void BorrowToDestructureTransform::cleanup(
12991300
}
13001301
}
13011302

1303+
// Then do this for our inserted phis.
1304+
while (!createdPhiArguments.empty()) {
1305+
auto *arg = createdPhiArguments.pop_back_val();
1306+
1307+
// If we have a trivial argument, we do not ened to add any compensating
1308+
// destroys.
1309+
if (arg->getType().isTrivial(*fn))
1310+
continue;
1311+
1312+
SWIFT_DEFER {
1313+
liveness.clear();
1314+
discoveredBlocks.clear();
1315+
boundary.clear();
1316+
};
1317+
addCompensatingDestroys(liveness, boundary, arg);
1318+
}
1319+
13021320
// And finally do the same thing for our initial copy_value.
13031321
addCompensatingDestroys(liveness, boundary, initialValue);
13041322
}

test/SILOptimizer/moveonly_borrow_to_destructure_transform.sil

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,29 @@ struct AggStruct {
2525
var pair: KlassPair
2626
}
2727

28+
@_moveOnly
29+
struct KlassPair2 {
30+
var lhs: MoveOnlyKlass
31+
var rhs: MoveOnlyKlass
32+
}
33+
34+
@_moveOnly
35+
struct AggStruct2 {
36+
var lhs: MoveOnlyKlass
37+
var pair: KlassPair2
38+
var rhs: MoveOnlyKlass
39+
}
40+
2841
@_moveOnly
2942
struct SingleIntContainingStruct {
3043
var value: Builtin.Int32
3144
}
3245

3346
sil @misc_use : $@convention(thin) () -> ()
47+
sil @aggstruct_consume : $@convention(thin) (@owned AggStruct) -> ()
48+
sil @moveonlyklass_consume : $@convention(thin) (@owned MoveOnlyKlass) -> ()
49+
sil @moveonlyklass_use : $@convention(thin) (@guaranteed MoveOnlyKlass) -> ()
50+
sil @klass_use : $@convention(thin) (@guaranteed Klass) -> ()
3451

3552
///////////
3653
// Tests //
@@ -137,6 +154,61 @@ bb0(%0 : @guaranteed $SingleIntContainingStruct):
137154
return %5 : $Builtin.Int32
138155
}
139156

157+
// CHECK-LABEL: sil [ossa] @phis_are_cleaned_up : $@convention(thin) (@owned AggStruct2) -> () {
158+
// CHECK: bb3([[FIRST_PHI:%.*]] : @owned $MoveOnlyKlass, [[SECOND_PHI:%.*]] : @owned $MoveOnlyKlass, [[THIRD_PHI:%.*]] : @owned $MoveOnlyKlass):
159+
// CHECK: destroy_value [[SECOND_PHI]]
160+
// CHECK: destroy_value [[THIRD_PHI]]
161+
// CHECK: apply {{%.*}}([[FIRST_PHI]])
162+
// CHECK: destroy_value [[FIRST_PHI]]
163+
// CHECK: } // end sil function 'phis_are_cleaned_up'
164+
sil [ossa] @phis_are_cleaned_up : $@convention(thin) (@owned AggStruct2) -> () {
165+
bb0(%0 : @owned $AggStruct2):
166+
%1 = move_value [lexical] %0 : $AggStruct2
167+
%2 = mark_must_check [no_implicit_copy] %1 : $AggStruct2
168+
debug_value %2 : $AggStruct2, let, name "x2", argno 1
169+
cond_br undef, bb1, bb2
170+
171+
bb1:
172+
%8 = begin_borrow %2 : $AggStruct2
173+
%9 = struct_extract %8 : $AggStruct2, #AggStruct2.pair
174+
%10 = copy_value %9 : $KlassPair2
175+
%11 = begin_borrow %10 : $KlassPair2
176+
%12 = struct_extract %11 : $KlassPair2, #KlassPair2.rhs
177+
%13 = copy_value %12 : $MoveOnlyKlass
178+
end_borrow %11 : $KlassPair2
179+
destroy_value %10 : $KlassPair2
180+
%16 = function_ref @moveonlyklass_consume : $@convention(thin) (@owned MoveOnlyKlass) -> ()
181+
%17 = apply %16(%13) : $@convention(thin) (@owned MoveOnlyKlass) -> ()
182+
end_borrow %8 : $AggStruct2
183+
br bb3
184+
185+
bb2:
186+
%20 = begin_borrow %2 : $AggStruct2
187+
%21 = struct_extract %20 : $AggStruct2, #AggStruct2.pair
188+
%22 = copy_value %21 : $KlassPair2
189+
%23 = begin_borrow %22 : $KlassPair2
190+
%24 = struct_extract %23 : $KlassPair2, #KlassPair2.rhs
191+
%25 = copy_value %24 : $MoveOnlyKlass
192+
end_borrow %23 : $KlassPair2
193+
destroy_value %22 : $KlassPair2
194+
%28 = function_ref @moveonlyklass_consume : $@convention(thin) (@owned MoveOnlyKlass) -> ()
195+
%29 = apply %28(%25) : $@convention(thin) (@owned MoveOnlyKlass) -> ()
196+
end_borrow %20 : $AggStruct2
197+
br bb3
198+
199+
bb3:
200+
%32 = begin_borrow %2 : $AggStruct2
201+
%33 = struct_extract %32 : $AggStruct2, #AggStruct2.lhs
202+
%34 = copy_value %33 : $MoveOnlyKlass
203+
%35 = function_ref @moveonlyklass_use : $@convention(thin) (@guaranteed MoveOnlyKlass) -> ()
204+
%36 = apply %35(%34) : $@convention(thin) (@guaranteed MoveOnlyKlass) -> ()
205+
destroy_value %34 : $MoveOnlyKlass
206+
end_borrow %32 : $AggStruct2
207+
destroy_value %2 : $AggStruct2
208+
%39 = tuple ()
209+
return %39 : $()
210+
}
211+
140212
///////////////////////////////
141213
// Single Field Struct Tests //
142214
///////////////////////////////

0 commit comments

Comments
 (0)