Skip to content

Commit c766956

Browse files
committed
[AddressLowering] Storage root inherits lexical.
When a `begin_borrow [lexical]` is lowered, the lifetime that it describes can't be shortened (or eliminated) when lowering. In some cases, though, there will not be an alloc_stack corresponding directly to the value being borrowed. In these cases, mark the whole aggregate lexical.
1 parent a995c56 commit c766956

File tree

3 files changed

+110
-7
lines changed

3 files changed

+110
-7
lines changed

lib/SILOptimizer/Mandatory/AddressLowering.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2772,13 +2772,15 @@ void UseRewriter::visitBeginBorrowInst(BeginBorrowInst *borrow) {
27722772

27732773
// Borrows are irrelevant unless they are marked lexical.
27742774
if (borrow->isLexical()) {
2775-
if (auto *allocStack = dyn_cast<AllocStackInst>(address)) {
2776-
allocStack->setIsLexical();
2777-
return;
2775+
if (auto base = getAccessBase(address)) {
2776+
if (auto *allocStack = dyn_cast<AllocStackInst>(base)) {
2777+
allocStack->setIsLexical();
2778+
return;
2779+
}
2780+
// Function arguments are inherently lexical.
2781+
if (isa<SILFunctionArgument>(base))
2782+
return;
27782783
}
2779-
// Function arguments are inherently lexical.
2780-
if (isa<SILFunctionArgument>(address))
2781-
return;
27822784

27832785
SWIFT_ASSERT_ONLY(address->dump());
27842786
llvm_unreachable("^^^ unknown lexical address producer");

test/SILOptimizer/address_lowering.sil

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ public protocol Comparable {
6262
static func < (lhs: Self, rhs: Self) -> Bool
6363
}
6464

65+
sil [ossa] @unknown : $@convention(thin) () -> ()
66+
sil [ossa] @getT : $@convention(thin) <T> () -> @out T
67+
sil [ossa] @getPair : $@convention(thin) <T> () -> @out Pair<T>
6568
sil [ossa] @takeGuaranteedObject : $@convention(thin) (@guaranteed AnyObject) -> ()
6669
sil [ossa] @takeIndirectClass : $@convention(thin) (@in_guaranteed C) -> ()
6770
sil [ossa] @takeTuple : $@convention(thin) <τ_0_0> (@in_guaranteed (τ_0_0, C)) -> ()
@@ -1225,6 +1228,51 @@ bb2(%9 : $Error):
12251228
throw %9 : $Error
12261229
}
12271230

1231+
// CHECK-LABEL: sil [ossa] @lexical_borrow_struct_extract {{.*}} {
1232+
// CHECK: [[PAIR_ADDR:%[^,]+]] = alloc_stack [lexical]
1233+
// CHECK: [[X_ADDR:%[^,]+]] = struct_element_addr [[PAIR_ADDR]]
1234+
// CHECK: apply {{%[^,]+}}<T>([[X_ADDR]])
1235+
// CHECK: destroy_addr [[PAIR_ADDR]]
1236+
// CHECK: dealloc_stack [[PAIR_ADDR]]
1237+
// CHECK-LABEL: } // end sil function 'lexical_borrow_struct_extract'
1238+
sil [ossa] @lexical_borrow_struct_extract : $@convention(thin) <T> () -> () {
1239+
%getPair = function_ref @getPair : $@convention(thin) <Tee> () -> @out Pair<Tee>
1240+
%instance = apply %getPair<T>() : $@convention(thin) <Tee> () -> @out Pair<Tee>
1241+
%scope = begin_borrow %instance : $Pair<T>
1242+
%x = struct_extract %scope : $Pair<T>, #Pair.x
1243+
%lifetime = begin_borrow [lexical] %x : $T
1244+
%takeInGuaranteed = function_ref @takeInGuaranteed : $@convention(thin) <Tee> (@in_guaranteed Tee) -> ()
1245+
apply %takeInGuaranteed<T>(%lifetime) : $@convention(thin) <Tee> (@in_guaranteed Tee) -> ()
1246+
%unknown = function_ref @unknown : $@convention(thin) () -> ()
1247+
apply %unknown() : $@convention(thin) () -> ()
1248+
end_borrow %lifetime : $T
1249+
end_borrow %scope : $Pair<T>
1250+
destroy_value %instance : $Pair<T>
1251+
%retval = tuple ()
1252+
return %retval : $()
1253+
}
1254+
1255+
// CHECK-LABEL: sil [ossa] @lexical_borrow_struct_extract_arg {{.*}} {
1256+
// CHECK: [[X_ADDR:%[^,]+]] = struct_element_addr [[PAIR_ADDR]]
1257+
// CHECK: apply {{%[^,]+}}<T>([[X_ADDR]])
1258+
// CHECK: destroy_addr [[PAIR_ADDR]]
1259+
// CHECK-LABEL: } // end sil function 'lexical_borrow_struct_extract_arg'
1260+
sil [ossa] @lexical_borrow_struct_extract_arg : $@convention(thin) <T> (@in Pair<T>) -> () {
1261+
entry(%instance : @owned $Pair<T>):
1262+
%scope = begin_borrow %instance : $Pair<T>
1263+
%x = struct_extract %scope : $Pair<T>, #Pair.x
1264+
%lifetime = begin_borrow [lexical] %x : $T
1265+
%takeInGuaranteed = function_ref @takeInGuaranteed : $@convention(thin) <Tee> (@in_guaranteed Tee) -> ()
1266+
apply %takeInGuaranteed<T>(%lifetime) : $@convention(thin) <Tee> (@in_guaranteed Tee) -> ()
1267+
%unknown = function_ref @unknown : $@convention(thin) () -> ()
1268+
apply %unknown() : $@convention(thin) () -> ()
1269+
end_borrow %lifetime : $T
1270+
end_borrow %scope : $Pair<T>
1271+
destroy_value %instance : $Pair<T>
1272+
%retval = tuple ()
1273+
return %retval : $()
1274+
}
1275+
12281276
sil hidden [ossa] @testBeginApplyDeadYield : $@convention(thin) <T> (@guaranteed TestGeneric<T>) -> () {
12291277
bb0(%0 : @guaranteed $TestGeneric<T>):
12301278
%2 = class_method %0 : $TestGeneric<T>, #TestGeneric.borrowedGeneric!read : <T> (TestGeneric<T>) -> () -> (), $@yield_once @convention(method) <τ_0_0> (@guaranteed TestGeneric<τ_0_0>) -> @yields @in_guaranteed τ_0_0
@@ -1493,4 +1541,3 @@ bb0(%0 : @guaranteed $T):
14931541
destroy_value %3 : $U
14941542
return %6 : $U
14951543
}
1496-

test/SILOptimizer/opaque_values_Onone.swift

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,57 @@
88
func generic_identity<T>(t: T) -> T {
99
return t
1010
}
11+
12+
13+
enum Maybe1<T : Equatable> {
14+
case nope
15+
case yep(T)
16+
// CHECK-LABEL: sil hidden @maybe1_compare {{.*}} {
17+
// CHECK: [[LHS_ADDR:%[^,]+]] = alloc_stack [lexical] $Maybe1
18+
// CHECK: [[RHS_ADDR:%[^,]+]] = alloc_stack [lexical] $Maybe1
19+
// CHECK: switch_enum_addr [[LHS_ADDR]] : $*Maybe1<T>, case #Maybe1.yep!enumelt: [[L_YEP:bb[0-9]+]], case #Maybe1.nope!enumelt: {{bb[0-9]+}}
20+
// CHECK: [[L_YEP]]:
21+
// CHECK: unchecked_take_enum_data_addr [[LHS_ADDR]] : $*Maybe1<T>, #Maybe1.yep!enumelt
22+
// CHECK: switch_enum_addr [[RHS_ADDR]] : $*Maybe1<T>, case #Maybe1.yep!enumelt: [[L_AND_R_YEP:bb[0-9]+]], default {{bb[0-9]+}}
23+
// CHECK: [[L_AND_R_YEP]]:
24+
// CHECK: unchecked_take_enum_data_addr [[RHS_ADDR]] : $*Maybe1<T>, #Maybe1.yep!enumelt
25+
// CHECK-LABEL: } // end sil function 'maybe1_compare'
26+
@_silgen_name("maybe1_compare")
27+
static func compare(_ lhs: Maybe1, _ rhs: Maybe1) -> Bool {
28+
switch (lhs, rhs) {
29+
case (.yep(let l), .yep(let r)):
30+
return l == r
31+
case (.nope, .nope):
32+
return true
33+
default:
34+
return false
35+
}
36+
}
37+
}
38+
39+
enum Maybe2<T : Equatable> {
40+
case nope
41+
case yep(T, T)
42+
43+
// CHECK-LABEL: sil hidden @maybe2_compare {{.*}} {
44+
// CHECK: [[LHS_ADDR:%[^,]+]] = alloc_stack [lexical] $Maybe2<T>
45+
// CHECK: [[RHS_ADDR:%[^,]+]] = alloc_stack [lexical] $Maybe2<T>
46+
// CHECK: switch_enum_addr [[LHS_ADDR]] : $*Maybe2<T>, case #Maybe2.yep!enumelt: [[L_YEP:bb[0-9]+]], case #Maybe2.nope!enumelt: {{bb[0-9]+}}
47+
// CHECK: [[L_YEP]]:
48+
// CHECK: unchecked_take_enum_data_addr [[LHS_ADDR]] : $*Maybe2<T>, #Maybe2.yep!enumelt
49+
// CHECK: switch_enum_addr [[RHS_ADDR]] : $*Maybe2<T>, case #Maybe2.yep!enumelt: [[R_YEP:bb[0-9]+]], default {{bb[0-9]+}}
50+
// CHECK: [[L_AND_R_YEP]]:
51+
// CHECK: unchecked_take_enum_data_addr [[RHS_ADDR]] : $*Maybe2<T>, #Maybe2.yep!enumelt
52+
// CHECK-LABEL: } // end sil function 'maybe2_compare'
53+
@_silgen_name("maybe2_compare")
54+
static func compare(_ lhs: Maybe2, _ rhs: Maybe2) -> Bool {
55+
switch (lhs, rhs) {
56+
case (.yep(let l, _), .yep(let r, _)):
57+
return l == r
58+
case (.nope, .nope):
59+
return true
60+
default:
61+
return false
62+
}
63+
}
64+
}

0 commit comments

Comments
 (0)