Skip to content

Commit fb1d497

Browse files
committed
[capture-promotion] Add support for GEPs from captures that are load_borrowed.
We supported this code pattern previously just for loads and never implemented the support for load_borrow. I just added analogous code for load_borrow. Without this, we hit a crash since: 1. We would not process the struct_element_addr for a valid value. 2. The load_borrow would not look through the struct_element_addr, so we would ask the cloner for the mapped value to the struct_element_addr... it was never visited, thus never mapped, thus KABOOM. rdar://93879907 (cherry picked from commit 3b39af3)
1 parent ba6cb0c commit fb1d497

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

lib/SILOptimizer/Mandatory/CapturePromotion.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,25 @@ void ClosureCloner::visitLoadBorrowInst(LoadBorrowInst *lbi) {
697697
return;
698698
}
699699

700+
auto *seai = dyn_cast<StructElementAddrInst>(lbi->getOperand());
701+
if (!seai) {
702+
SILCloner<ClosureCloner>::visitLoadBorrowInst(lbi);
703+
return;
704+
}
705+
706+
if (SILValue value = getProjectBoxMappedVal(seai->getOperand())) {
707+
// Loads of a struct_element_addr of an argument get replaced with a
708+
// struct_extract of the new passed in value. The value should be borrowed
709+
// already, so we can just extract the value.
710+
assert(
711+
!getBuilder().getFunction().hasOwnership() ||
712+
value.getOwnershipKind().isCompatibleWith(OwnershipKind::Guaranteed));
713+
value = getBuilder().emitStructExtract(lbi->getLoc(), value,
714+
seai->getField(), lbi->getType());
715+
recordFoldedValue(lbi, value);
716+
return;
717+
}
718+
700719
SILCloner<ClosureCloner>::visitLoadBorrowInst(lbi);
701720
return;
702721
}

test/SILOptimizer/capture_promotion_ownership.sil

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,11 +431,15 @@ bb0:
431431
// CHECK: [[BORROWED_BAZ:%.*]] = begin_borrow [[BAZ]] : $Baz
432432
// CHECK: [[X:%.*]] = struct_extract [[BORROWED_BAZ]] : $Baz, #Baz.x
433433
// CHECK: [[BAR:%.*]] = struct_extract [[BORROWED_BAZ]] : $Baz, #Baz.bar
434+
434435
// CHECK: [[BAR_COPY:%.*]] = copy_value [[BAR]]
436+
// CHECK: [[BAR_COPY_2:%.*]] = copy_value [[BAR_COPY]]
435437
// CHECK: [[BAR2:%.*]] = struct_extract [[BORROWED_BAZ]] : $Baz, #Baz.bar
436438
// CHECK: [[BAR2_COPY:%.*]] = copy_value [[BAR2]]
437439
// CHECK: [[BAR2_COPY_BORROW:%.*]] = begin_borrow [[BAR2_COPY]]
440+
// CHECK: [[LOAD_BORROW_EXT:%.*]] = struct_extract [[BORROWED_BAZ]]
438441
// CHECK: apply {{%.*}}([[BAR_COPY]], [[BAR2_COPY_BORROW]], [[X]])
442+
// CHECK: apply {{%.*}}([[BAR_COPY_2]], [[LOAD_BORROW_EXT]], [[X]])
439443
// CHECK: end_borrow [[BAR2_COPY_BORROW]]
440444
// CHECK: destroy_value [[BAR2_COPY]]
441445
// CHECK: end_borrow [[BORROWED_BAZ]]
@@ -458,12 +462,17 @@ bb0(%0 : @owned $<τ_0_0> { var τ_0_0 } <Baz>, %1 : @owned $<τ_0_0> { var τ_0
458462
%1a = project_box %1 : $<τ_0_0> { var τ_0_0 } <Baz>, 0
459463
%9 = struct_element_addr %1a : $*Baz, #Baz.x
460464
%10 = struct_element_addr %1a : $*Baz, #Baz.bar
465+
%10a = struct_element_addr %1a : $*Baz, #Baz.bar
461466
%11 = load [trivial] %9 : $*Int
462467
%12 = load [copy] %10 : $*Bar
468+
%12a = copy_value %12 : $Bar
463469
%13 = load [copy] %10 : $*Bar
464470
%14 = begin_borrow %13 : $Bar
465471
%15 = function_ref @destructured_baz_user : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> ()
472+
%16 = load_borrow %10a : $*Bar
466473
apply %15(%12, %14, %11) : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> ()
474+
apply %15(%12a, %16, %11) : $@convention(thin) (@owned Bar, @guaranteed Bar, Int) -> ()
475+
end_borrow %16 : $Bar
467476
end_borrow %14 : $Bar
468477
destroy_value %13 : $Bar
469478

0 commit comments

Comments
 (0)