Skip to content

Commit b6cf3cd

Browse files
committed
Fix store_borrow generation and pattern matching in foreach loop unroll optimization
1 parent c3ef007 commit b6cf3cd

File tree

2 files changed

+25
-18
lines changed

2 files changed

+25
-18
lines changed

lib/SILOptimizer/LoopTransforms/ForEachLoopUnroll.cpp

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ static FixLifetimeInst *isFixLifetimeUseOfArray(SILInstruction *user,
249249
AllocStackInst *alloc = dyn_cast<AllocStackInst>(storeUser->getDest());
250250
if (!alloc)
251251
return nullptr;
252-
auto fixLifetimeUsers = alloc->getUsersOfType<FixLifetimeInst>();
252+
auto fixLifetimeUsers = storeUser->getUsersOfType<FixLifetimeInst>();
253253
if (fixLifetimeUsers.empty())
254254
return nullptr;
255255
auto firstUser = fixLifetimeUsers.begin();
@@ -278,7 +278,7 @@ static TryApplyInst *isForEachUseOfArray(SILInstruction *user, SILValue array) {
278278
AllocStackInst *alloc = dyn_cast<AllocStackInst>(storeUser->getDest());
279279
if (!alloc)
280280
return nullptr;
281-
auto applyUsers = alloc->getUsersOfType<TryApplyInst>();
281+
auto applyUsers = storeUser->getUsersOfType<TryApplyInst>();
282282
if (applyUsers.empty())
283283
return nullptr;
284284
auto firstUser = applyUsers.begin();
@@ -385,12 +385,11 @@ void ArrayInfo::getLastDestroys(
385385
/// not clean up any resulting dead instructions.
386386
static void removeForEachCall(TryApplyInst *forEachCall,
387387
InstructionDeleter &deleter) {
388-
AllocStackInst *allocStack =
389-
dyn_cast<AllocStackInst>(forEachCall->getArgument(1));
390-
assert(allocStack);
388+
auto *sbi = cast<StoreBorrowInst>(forEachCall->getArgument(1));
389+
auto *asi = cast<AllocStackInst>(sbi->getDest());
391390
// The allocStack will be used in the forEach call and also in a store
392391
// instruction and a dealloc_stack instruction. Force delete all of them.
393-
deleter.recursivelyForceDeleteUsersAndFixLifetimes(allocStack);
392+
deleter.recursivelyForceDeleteUsersAndFixLifetimes(asi);
394393
}
395394

396395
/// Unroll the \c forEachCall on an array, using the information in
@@ -502,12 +501,15 @@ static void unrollForEach(ArrayInfo &arrayInfo, TryApplyInst *forEachCall,
502501
// "error" branch of a try_apply. The error block created here will always
503502
// jump to the error target of the original forEach.
504503
auto errorTargetGenerator = [&](SILBasicBlock *insertionBlock,
505-
SILValue borrowedElem ) {
504+
SILValue borrowedElem, SILValue storeBorrow) {
506505
SILBasicBlock *newErrorBB = fun->createBasicBlockBefore(insertionBlock);
507506
SILValue argument = newErrorBB->createPhiArgument(
508507
errorArgument->getType(), errorArgument->getOwnershipKind());
509508
// Make the errorBB jump to the error target of the original forEach.
510509
SILBuilderWithScope builder(newErrorBB, forEachCall);
510+
if (storeBorrow) {
511+
builder.createEndBorrow(forEachLoc, storeBorrow);
512+
}
511513
if (borrowedElem) {
512514
builder.createEndBorrow(forEachLoc, borrowedElem);
513515
}
@@ -537,28 +539,33 @@ static void unrollForEach(ArrayInfo &arrayInfo, TryApplyInst *forEachCall,
537539
: forEachCall->getParentBlock();
538540
SILBuilderWithScope unrollBuilder(currentBB, forEachCall);
539541
SILValue borrowedElem;
542+
SILValue addr;
543+
540544
if (arrayElementType.isTrivial(*fun)) {
541545
unrollBuilder.createStore(forEachLoc, elementCopy, allocStack,
542546
StoreOwnershipQualifier::Trivial);
547+
addr = allocStack;
543548
} else {
544549
// Borrow the elementCopy and store it in the allocStack. Note that the
545550
// element's copy is guaranteed to be alive until the array is alive.
546551
// Therefore it is okay to use a borrow here.
547552
borrowedElem = unrollBuilder.createBeginBorrow(forEachLoc, elementCopy);
548-
unrollBuilder.createStoreBorrow(forEachLoc, borrowedElem, allocStack);
549-
550-
SILBuilderWithScope(&nextNormalBB->front(), forEachCall)
551-
.createEndBorrow(forEachLoc, borrowedElem);
553+
addr =
554+
unrollBuilder.createStoreBorrow(forEachLoc, borrowedElem, allocStack);
555+
SILBuilderWithScope builder(&nextNormalBB->front(), forEachCall);
556+
builder.createEndBorrow(forEachLoc, addr);
557+
builder.createEndBorrow(forEachLoc, borrowedElem);
552558
}
553559

554560
SILBasicBlock *errorTarget =
555-
errorTargetGenerator(nextNormalBB, borrowedElem);
561+
errorTargetGenerator(nextNormalBB, borrowedElem,
562+
isa<StoreBorrowInst>(addr) ? addr : SILValue());
556563
// Note that the substitution map must be empty as we are not supporting
557564
// elements of address-only type. All elements in the array are guaranteed
558565
// to be loadable. TODO: generalize this to address-only types.
559566
unrollBuilder.createTryApply(forEachLoc, forEachBodyClosure,
560-
SubstitutionMap(), allocStack,
561-
nextNormalBB, errorTarget);
567+
SubstitutionMap(), addr, nextNormalBB,
568+
errorTarget);
562569
nextNormalBB = currentBB;
563570
}
564571

test/SILOptimizer/for_each_loop_unroll_test.sil

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,17 +118,17 @@ bb2(%39 : @owned $Error):
118118
// CHECK-NOT: forEach
119119
// CHECK: [[STACK:%[0-9]+]] = alloc_stack $@callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Int>
120120
// CHECK: [[ELEM1BORROW:%[0-9]+]] = begin_borrow [[ELEM1]]
121-
// CHECK: store_borrow [[ELEM1BORROW]] to [[STACK]]
122-
// CHECK: try_apply [[BODYCLOSURE]]([[STACK]]) : $@noescape @callee_guaranteed (@in_guaranteed @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Int>) -> @error Error, normal [[NORMAL:bb[0-9]+]], error [[ERROR:bb[0-9]+]]
121+
// CHECK: [[SB1:%.*]] = store_borrow [[ELEM1BORROW]] to [[STACK]]
122+
// CHECK: try_apply [[BODYCLOSURE]]([[SB1]]) : $@noescape @callee_guaranteed (@in_guaranteed @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Int>) -> @error Error, normal [[NORMAL:bb[0-9]+]], error [[ERROR:bb[0-9]+]]
123123

124124
// CHECK: [[ERROR]]([[ERRPARAM:%[0-9]+]] : @owned $Error):
125125
// CHECK: br [[ERROR3:bb[0-9]+]]([[ERRPARAM]] : $Error)
126126

127127
// CHECK: [[NORMAL]](%{{.*}} : $()):
128128
// CHECK: end_borrow [[ELEM1BORROW]]
129129
// CHECK: [[ELEM2BORROW:%[0-9]+]] = begin_borrow [[ELEM2]]
130-
// CHECK: store_borrow [[ELEM2BORROW]] to [[STACK]]
131-
// CHECK: try_apply [[BODYCLOSURE]]([[STACK]]) : $@noescape @callee_guaranteed (@in_guaranteed @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Int>) -> @error Error, normal [[NORMAL2:bb[0-9]+]], error [[ERROR2:bb[0-9]+]]
130+
// CHECK: [[SB2:%.*]] = store_borrow [[ELEM2BORROW]] to [[STACK]]
131+
// CHECK: try_apply [[BODYCLOSURE]]([[SB2]]) : $@noescape @callee_guaranteed (@in_guaranteed @callee_guaranteed @substituted <τ_0_0> () -> @out τ_0_0 for <Int>) -> @error Error, normal [[NORMAL2:bb[0-9]+]], error [[ERROR2:bb[0-9]+]]
132132

133133
// CHECK: [[ERROR2]]([[ERRPARAM2:%[0-9]+]] : @owned $Error):
134134
// CHECK: br [[ERROR3:bb[0-9]+]]([[ERRPARAM2]] : $Error)

0 commit comments

Comments
 (0)