Skip to content

Commit 73765c8

Browse files
committed
[SIL] InitAccessors: Fix reference type handling by DI and RawSIL lowering
- Adds a missing check to `collectClassSelfUses` to find assign_or_init instructions; - RawSIL lowering should start emitting access around synthesized member references.
1 parent 112d0d4 commit 73765c8

File tree

3 files changed

+154
-11
lines changed

3 files changed

+154
-11
lines changed

lib/SILOptimizer/Mandatory/DIMemoryUseCollector.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -656,7 +656,7 @@ class ElementUseCollector {
656656
void collectUses(SILValue Pointer, unsigned BaseEltNo);
657657
bool addClosureElementUses(PartialApplyInst *pai, Operand *argUse);
658658
void collectAssignOrInitUses(PartialApplyInst *pai, Operand *argUse,
659-
unsigned BaseEltNo);
659+
unsigned BaseEltNo = 0);
660660

661661
void collectClassSelfUses(SILValue ClassPointer);
662662
void collectClassSelfUses(SILValue ClassPointer, SILType MemorySILType,
@@ -1632,6 +1632,11 @@ void ElementUseCollector::collectClassSelfUses(
16321632
if (onlyUsedByAssignByWrapper(PAI))
16331633
continue;
16341634

1635+
if (onlyUsedByAssignOrInit(PAI)) {
1636+
collectAssignOrInitUses(PAI, Op);
1637+
continue;
1638+
}
1639+
16351640
if (addClosureElementUses(PAI, Op))
16361641
continue;
16371642

lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -290,10 +290,21 @@ lowerAssignOrInitInstruction(SILBuilderWithScope &b,
290290
auto selfValue = setterPA->getOperand(1);
291291
auto isRefSelf = selfValue->getType().getASTType()->mayHaveSuperclass();
292292

293+
SILValue selfRef;
294+
if (isRefSelf) {
295+
selfRef = b.emitBeginBorrowOperation(loc, selfValue);
296+
} else {
297+
selfRef = b.createBeginAccess(loc, selfValue, SILAccessKind::Modify,
298+
SILAccessEnforcement::Dynamic,
299+
/*noNestedConflict=*/false,
300+
/*fromBuiltin=*/false);
301+
}
302+
293303
auto emitFieldReference = [&](VarDecl *field) -> SILValue {
294-
if (isRefSelf)
295-
return b.createRefElementAddr(loc, selfValue, field);
296-
return b.createStructElementAddr(loc, selfValue, field);
304+
if (isRefSelf) {
305+
return b.createRefElementAddr(loc, selfRef, field);
306+
}
307+
return b.createStructElementAddr(loc, selfRef, field);
297308
};
298309

299310
SmallVector<SILValue> arguments;
@@ -314,6 +325,12 @@ lowerAssignOrInitInstruction(SILBuilderWithScope &b,
314325

315326
b.createApply(loc, initFn, setterPA->getSubstitutionMap(), arguments);
316327

328+
if (isRefSelf) {
329+
b.emitEndBorrowOperation(loc, selfRef);
330+
} else {
331+
b.createEndAccess(loc, selfRef, /*aborted=*/false);
332+
}
333+
317334
// The unused partial_apply violates memory lifetime rules in case "self"
318335
// is an inout. Therefore we cannot keep it as a dead closure to be
319336
// cleaned up later. We have to delete it in this pass.

test/SIL/init_accessors.swift

Lines changed: 128 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,27 @@ struct TestInit {
66
var full: (Int, Int)
77

88
var point: (Int, Int) {
9+
// CHECK-LABEL: sil private @$s14init_accessors8TestInitV5pointSi_Sitvi : $@convention(thin) (Int, Int, @inout Int) -> (@out Int, @out (Int, Int))
10+
// CHECK: bb0([[Y_REF:%.*]] : $*Int, [[FULL_REF:%.*]] : $*(Int, Int), [[X_VAL:%.*]] : $Int, [[Y_VAL:%.*]] : $Int, [[X_REF:%.*]] : $*Int):
11+
//
12+
// CHECK: [[Y_ACCESS:%.*]] = begin_access [modify] [static] [[Y_REF]] : $*Int
13+
// CHECK-NEXT: store [[Y_VAL]] to [[Y_ACCESS]] : $*Int
14+
// CHECK-NEXT: end_access [[Y_ACCESS]] : $*Int
15+
//
16+
// CHECK-NEXT: [[X_ACCESS:%.*]] = begin_access [read] [static] [[X_REF]] : $*Int
17+
// CHECK-NEXT: [[X_VAL:%.*]] = load [[X_ACCESS]] : $*Int
18+
// CHECK-NEXT: end_access [[X_ACCESS]] : $*Int
19+
//
20+
// CHECK-NEXT: [[Y_ACCESS:%.*]] = begin_access [read] [static] [[Y_REF]] : $*Int
21+
// CHECK-NEXT: [[Y_VAL:%.*]] = load [[Y_ACCESS]] : $*Int
22+
// CHECK-NEXT: end_access [[Y_ACCESS]] : $*Int
23+
//
24+
// CHECK-NEXT: [[FULL_ACCESS:%.*]] = begin_access [modify] [static] [[FULL_REF]] : $*(Int, Int)
25+
// CHECK-NEXT: [[FULL_ELT_0:%.*]] = tuple_element_addr [[FULL_ACCESS]] : $*(Int, Int), 0
26+
// CHECK-NEXT: store [[X_VAL]] to [[FULL_ELT_0]] : $*Int
27+
// CHECK-NEXT: [[FULL_ELT_1:%.*]] = tuple_element_addr [[FULL_ACCESS]] : $*(Int, Int), 1
28+
// CHECK-NEXT: store [[Y_VAL]] to [[FULL_ELT_1]] : $*Int
29+
// CHECK-NEXT: end_access [[FULL_ACCESS]] : $*(Int, Int)
930
init(initialValue) initializes(y full) accesses(x) {
1031
self.y = initialValue.1
1132
self.full = (self.x, self.y)
@@ -16,13 +37,14 @@ struct TestInit {
1637
}
1738

1839
// CHECK-LABEL: sil hidden @$s14init_accessors8TestInitV1x1yACSi_SitcfC : $@convention(method) (Int, Int, @thin TestInit.Type) -> TestInit
19-
// CHECK: [[SELF_VALUE:%10]] = begin_access [modify] [static] {{.*}} : $*TestInit
20-
// CHECK-NEXT: // function_ref TestInit.point.init
40+
// CHECK: // function_ref TestInit.point.init
2141
// CHECK-NEXT: [[INIT_ACCESSOR:%.*]] = function_ref @$s14init_accessors8TestInitV5pointSi_Sitvi : $@convention(thin) (Int, Int, @inout Int) -> (@out Int, @out (Int, Int))
42+
// CHECK: [[SELF_VALUE:%.*]] = begin_access [modify] [dynamic] {{.*}} : $*TestInit
2243
// CHECK: [[Y_REF:%.*]] = struct_element_addr [[SELF_VALUE]] : $*TestInit, #TestInit.y
2344
// CHECK-NEXT: [[FULL_REF:%.*]] = struct_element_addr [[SELF_VALUE]] : $*TestInit, #TestInit.full
2445
// CHECK-NEXT: [[X_REF:%.*]] = struct_element_addr [[SELF_VALUE]] : $*TestInit, #TestInit.x
2546
// CHECK-NEXT: {{.*}} = apply [[INIT_ACCESSOR]]([[Y_REF]], [[FULL_REF]], %0, %1, [[X_REF]]) : $@convention(thin) (Int, Int, @inout Int) -> (@out Int, @out (Int, Int))
47+
// CHECK-NEXT: end_access [[SELF_VALUE]] : $*TestInit
2648
init(x: Int, y: Int) {
2749
self.x = x
2850
self.point = (x, y)
@@ -130,7 +152,7 @@ struct TestPartialInt {
130152
// CHECK-NEXT: [[TWO:%.*]] = struct $Int ([[BUILTIN_TWO]] : $Builtin.Int64)
131153
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s14init_accessors14TestPartialIntV6pointYSivs : $@convention(method) (Int, @inout TestPartialInt) -> ()
132154
// CHECK-NEXT: [[SETTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[SETTER_REF]]({{.*}}) : $@convention(method) (Int, @inout TestPartialInt) -> ()
133-
// CHECK-NEXT: {{.*}} = apply %32([[TWO]]) : $@callee_guaranteed (Int) -> ()
155+
// CHECK-NEXT: {{.*}} = apply [[SETTER_CLOSURE]]([[TWO]]) : $@callee_guaranteed (Int) -> ()
134156
init(x: Int, y: Int) {
135157
// Init
136158
self.pointX = x
@@ -169,16 +191,115 @@ struct TestNoInitAndInit {
169191
// CHECK-LABEL: sil hidden @$s14init_accessors013TestNoInitAndE0V1x1yACSi_SitcfC : $@convention(method) (Int, Int, @thin TestNoInitAndInit.Type) -> TestNoInitAndInit
170192
//
171193
// CHECK: [[INIT_REF:%.*]] = function_ref @$s14init_accessors013TestNoInitAndE0V6pointXSivi : $@convention(thin) (Int, @inout Int) -> ()
172-
// CHECK: [[X_REF:%.*]] = struct_element_addr {{.*}} : $*TestNoInitAndInit, #TestNoInitAndInit.x
173-
// CHECK-NEXT: %14 = apply [[INIT_REF]](%0, [[X_REF]]) : $@convention(thin) (Int, @inout Int) -> ()
194+
// CHECK: [[SELF_REF:%.*]] = begin_access [modify] [dynamic] {{.*}} : $*TestNoInitAndInit
195+
// CHECK-NEXT: [[X_REF:%.*]] = struct_element_addr [[SELF_REF]] : $*TestNoInitAndInit, #TestNoInitAndInit.x
196+
// CHECK-NEXT: {{.*}} = apply [[INIT_REF]](%0, [[X_REF]]) : $@convention(thin) (Int, @inout Int) -> ()
197+
// CHECK-NEXT: end_access [[SELF_REF]] : $*TestNoInitAndInit
174198
//
175199
// CHECK: [[INIT_REF:%.*]] = function_ref @$s14init_accessors013TestNoInitAndE0V6pointYSivi : $@convention(thin) (Int) -> @out Int
176-
// CHECK: [[Y_REF:%.*]] = struct_element_addr %16 : $*TestNoInitAndInit, #TestNoInitAndInit.y
177-
// CHECK-NEXT: %20 = apply [[INIT_REF]]([[Y_REF]], %1) : $@convention(thin) (Int) -> @out Int
200+
// CHECK: [[SELF_REF:%.*]] = begin_access [modify] [dynamic] {{.*}} : $*TestNoInitAndInit
201+
// CHECK-NEXT: [[Y_REF:%.*]] = struct_element_addr [[SELF_REF]] : $*TestNoInitAndInit, #TestNoInitAndInit.y
202+
// CHECK-NEXT: {{.*}} = apply [[INIT_REF]]([[Y_REF]], %1) : $@convention(thin) (Int) -> @out Int
203+
// CHECK-NEXT: end_access [[SELF_REF]] : $*TestNoInitAndInit
178204
init(x: Int, y: Int) {
179205
self.x = x
180206
self.pointX = x
181207
self.pointY = y
182208
print("Point(x: \(self.x), y: \(self.y)")
183209
}
184210
}
211+
212+
class TestClass {
213+
var x: Int
214+
var y: (Int, [String])
215+
216+
var data: (Int, (Int, [String])) {
217+
// CHECK-LABEL: sil private @$s14init_accessors9TestClassC4dataSi_Si_SaySSGttvi : $@convention(thin) (Int, Int, @owned Array<String>) -> (@out Int, @out (Int, Array<String>))
218+
// CHECK: bb0([[X_REF:%.*]] : $*Int, [[Y_REF:%.*]] : $*(Int, Array<String>), [[X_VAL:%.*]] : $Int, [[Y_VAL_0:%.*]] : $Int, [[Y_VAL_1:%.*]] : $Array<String>):
219+
// CHECK-NEXT: [[Y_VAL_TUPLE:%.*]] = tuple ([[Y_VAL_0]] : $Int, [[Y_VAL_1]] : $Array<String>)
220+
221+
// CHECK: [[X_ACCESS:%.*]] = begin_access [modify] [static] [[X_REF]] : $*Int
222+
// CHECK-NEXT: store [[X_VAL]] to [[X_ACCESS]] : $*Int
223+
// CHECK-NEXT: end_access [[X_ACCESS]] : $*Int
224+
//
225+
// CHECK: [[Y_VAL_0:%.*]] = tuple_extract [[Y_VAL_TUPLE]] : $(Int, Array<String>), 0
226+
// CHECK: [[Y_VAL_1:%.*]] = tuple_extract [[Y_VAL_TUPLE]] : $(Int, Array<String>), 1
227+
// CHECK: [[Y_ACCESS:%.*]] = begin_access [modify] [static] [[Y_REF]] : $*(Int, Array<String>)
228+
// CHECK-NEXT: [[Y_ELT_0:%.*]] = tuple_element_addr [[Y_ACCESS]] : $*(Int, Array<String>), 0
229+
// CHECK-NEXT: store [[Y_VAL_0]] to [[Y_ELT_0]] : $*Int
230+
// CHECK-NEXT: [[Y_ELT_1:%.*]] = tuple_element_addr [[Y_ACCESS]] : $*(Int, Array<String>), 1
231+
// CHECK-NEXT: store [[Y_VAL_1]] to [[Y_ELT_1]] : $*Array<String>
232+
// CHECK-NEXT: end_access [[Y_ACCESS]] : $*(Int, Array<String>)
233+
init(initialValue) initializes(x y) {
234+
x = initialValue.0
235+
y = initialValue.1
236+
}
237+
238+
get { (x, y) }
239+
set {
240+
x = newValue.0
241+
y = newValue.1
242+
}
243+
}
244+
245+
// CHECK-LABEL: sil hidden @$s14init_accessors9TestClassC1x1yACSi_Si_SaySSGttcfc : $@convention(method) (Int, Int, @owned Array<String>, @owned TestClass) -> @owned TestClass
246+
// CHECK: [[INIT_ACCESSOR:%.*]] = function_ref @$s14init_accessors9TestClassC4dataSi_Si_SaySSGttvi : $@convention(thin) (Int, Int, @owned Array<String>) -> (@out Int, @out (Int, Array<String>))
247+
// CHECK: strong_retain [[SELF_REF:%.*]] : $TestClass
248+
// CHECK: [[X_REF:%.*]] = ref_element_addr [[SELF_REF]] : $TestClass, #TestClass.x
249+
// CHECK-NEXT: [[Y_REF:%.*]] = ref_element_addr [[SELF_REF]] : $TestClass, #TestClass.y
250+
// CHECK-NEXT: [[Y_VAL_0:%.*]] = tuple_extract %12 : $(Int, Array<String>), 0
251+
// CHECK-NEXT: [[Y_VAL_1:%.*]] = tuple_extract %12 : $(Int, Array<String>), 1
252+
// CHECK-NEXT: {{.*}} = apply [[INIT_ACCESSOR]]([[X_REF]], [[Y_REF]], %0, [[Y_VAL_0]], [[Y_VAL_1]]) : $@convention(thin) (Int, Int, @owned Array<String>) -> (@out Int, @out (Int, Array<String>))
253+
// CHECK-NEXT: strong_release [[SELF_REF]] : $TestClass
254+
init(x: Int, y: (Int, [String])) {
255+
self.data = (x, y)
256+
}
257+
}
258+
259+
struct TestGeneric<T, U> {
260+
var a: T
261+
var b: T
262+
var c: U
263+
264+
// CHECK-LABEL: sil private @$s14init_accessors11TestGenericV4datax_xtvi : $@convention(thin) <T, U> (@in T, @in T, @inout U) -> (@out T, @out T)
265+
//
266+
// CHECK: bb0([[A_REF:%.*]] : $*T, [[B_REF:%.*]] : $*T, [[A_VALUE:%.*]] : $*T, [[B_VALUE:%.*]] : $*T, [[C_REF:%.*]] : $*U):
267+
//
268+
// CHECK: [[A_ACCESS:%.*]] = begin_access [modify] [static] [[A_REF]] : $*T
269+
// CHECK-NEXT: copy_addr [take] {{.*}} to [init] [[A_ACCESS]] : $*T
270+
// CHECK-NEXT: end_access [[A_ACCESS]] : $*T
271+
//
272+
// CHECK: [[B_ACCESS:%.*]] = begin_access [modify] [static] [[B_REF]] : $*T
273+
// CHECK-NEXT: copy_addr [take] {{.*}} to [init] [[B_ACCESS]] : $*T
274+
// CHECK-NEXT: end_access [[B_ACCESS]] : $*T
275+
//
276+
// CHECK: [[C_ACCESS:%.*]] = begin_access [read] [static] [[C_REF]] : $*U
277+
// CHECK-NEXT: [[C_AS_ANY:%.*]] = init_existential_addr {{.*}} : $*Any, $U
278+
// CHECK-NEXT: copy_addr [[C_ACCESS]] to [init] [[C_AS_ANY]] : $*U
279+
// CHECK-NEXT: end_access [[C_ACCESS]] : $*U
280+
var data: (T, T) {
281+
init(initialValue) initializes(a b) accesses(c) {
282+
a = initialValue.0
283+
b = initialValue.1
284+
print(c)
285+
}
286+
287+
get { (a, b) }
288+
set { }
289+
}
290+
291+
// CHECK-LABEL: sil hidden @$s14init_accessors11TestGenericV1a1b1cACyxq_Gx_xq_tcfC : $@convention(method) <T, U> (@in T, @in T, @in U, @thin TestGeneric<T, U>.Type) -> @out TestGeneric<T, U>
292+
//
293+
// CHECK: [[INIT_ACCESSOR:%.*]] = function_ref @$s14init_accessors11TestGenericV4datax_xtvi : $@convention(thin) <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_0, @inout τ_0_1) -> (@out τ_0_0, @out τ_0_0)
294+
// CHECK: {{.*}} = apply [[INIT_ACCESSOR]]<T, U>({{.*}}) : $@convention(thin) <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_0, @inout τ_0_1) -> (@out τ_0_0, @out τ_0_0)
295+
//
296+
// CHECK: [[SETTER:%.*]] = function_ref @$s14init_accessors11TestGenericV4datax_xtvs : $@convention(method) <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_0, @inout TestGeneric<τ_0_0, τ_0_1>) -> ()
297+
// CHECK-NEXT: [[SETTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[SETTER]]<T, U>([[SELF_VALUE:%.*]]) : $@convention(method) <τ_0_0, τ_0_1> (@in τ_0_0, @in τ_0_0, @inout TestGeneric<τ_0_0, τ_0_1>) -> ()
298+
// CHECK: %55 = apply [[SETTER_CLOSURE]]({{.*}}) : $@callee_guaranteed (@in T, @in T) -> ()
299+
// CHECK-NEXT: end_access [[SELF_VALUE]] : $*TestGeneric<T, U>
300+
init(a: T, b: T, c: U) {
301+
self.c = c
302+
self.data = (a, b)
303+
self.data = (b, a)
304+
}
305+
}

0 commit comments

Comments
 (0)