Skip to content

Commit 2e8b0e7

Browse files
committed
[RawSILLowering] InitAccessors: Implement lowering of assign_or_init as init accessor call
1 parent 68866d7 commit 2e8b0e7

File tree

2 files changed

+226
-13
lines changed

2 files changed

+226
-13
lines changed

lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#define DEBUG_TYPE "raw-sil-inst-lowering"
14+
#include "swift/AST/Decl.h"
1415
#include "swift/SIL/SILBuilder.h"
1516
#include "swift/SIL/SILFunction.h"
1617
#include "swift/SIL/SILInstruction.h"
@@ -168,6 +169,15 @@ static void getAssignByWrapperArgs(SmallVectorImpl<SILValue> &args,
168169
"initializer or setter has too many arguments");
169170
}
170171

172+
static void emitInitAccessorInitialValueArgument(
173+
SmallVectorImpl<SILValue> &args, SILValue src,
174+
const SILFunctionConventions &convention, SILBuilder &forProjections,
175+
SILBuilder &forCleanup) {
176+
unsigned argIdx = convention.getSILArgIndexOfFirstParam();
177+
getAssignByWrapperArgsRecursively(args, src, argIdx, convention,
178+
forProjections, forCleanup);
179+
}
180+
171181
static void
172182
lowerAssignByWrapperInstruction(SILBuilderWithScope &b,
173183
AssignByWrapperInst *inst,
@@ -273,10 +283,36 @@ lowerAssignOrInitInstruction(SILBuilderWithScope &b,
273283
SILValue initFn = inst->getInitializer();
274284
CanSILFunctionType fTy = initFn->getType().castTo<SILFunctionType>();
275285
SILFunctionConventions convention(fTy, inst->getModule());
276-
assert(!convention.hasIndirectSILResults());
277-
SmallVector<SILValue, 4> args;
278-
getAssignByWrapperArgs(args, src, convention, b, forCleanup);
279-
b.createApply(loc, initFn, SubstitutionMap(), args);
286+
287+
auto *setterPA = dyn_cast<PartialApplyInst>(inst->getSetter());
288+
assert(setterPA);
289+
290+
auto selfValue = setterPA->getOperand(1);
291+
auto isRefSelf = selfValue->getType().getASTType()->mayHaveSuperclass();
292+
293+
auto emitFieldReference = [&](VarDecl *field) -> SILValue {
294+
if (isRefSelf)
295+
return b.createRefElementAddr(loc, selfValue, field);
296+
return b.createStructElementAddr(loc, selfValue, field);
297+
};
298+
299+
SmallVector<SILValue> arguments;
300+
301+
// First, emit all of the properties listed in `initializes(...)`. They
302+
// are passed as indirect results.
303+
for (auto *property : inst->getInitializedProperties())
304+
arguments.push_back(emitFieldReference(property));
305+
306+
// Now emit `initialValue` which is the only argument specified
307+
// by the user.
308+
emitInitAccessorInitialValueArgument(arguments, src, convention, b,
309+
forCleanup);
310+
311+
// And finally, emit all of the `accesses(...)` properties.
312+
for (auto *property : inst->getAccessedProperties())
313+
arguments.push_back(emitFieldReference(property));
314+
315+
b.createApply(loc, initFn, setterPA->getSubstitutionMap(), arguments);
280316

281317
// The unused partial_apply violates memory lifetime rules in case "self"
282318
// is an inout. Therefore we cannot keep it as a dead closure to be
@@ -285,8 +321,7 @@ lowerAssignOrInitInstruction(SILBuilderWithScope &b,
285321

286322
// Also the argument of the closure (which usually is a "load") has to be
287323
// deleted to avoid memory lifetime violations.
288-
auto *setterPA = dyn_cast<PartialApplyInst>(inst->getSetter());
289-
if (setterPA && setterPA->getNumArguments() == 1)
324+
if (setterPA->getNumArguments() == 1)
290325
toDelete.insert(setterPA->getArgument(0));
291326
break;
292327
}
@@ -299,14 +334,8 @@ lowerAssignOrInitInstruction(SILBuilderWithScope &b,
299334
getAssignByWrapperArgs(args, src, convention, b, forCleanup);
300335
b.createApply(loc, setterFn, SubstitutionMap(), args);
301336

302-
// Again, we have to delete the unused dead closure.
337+
// Again, we have to delete the unused init accessor reference.
303338
toDelete.insert(inst->getInitializer());
304-
305-
// Also the argument of the closure (which usually is a "load") has to be
306-
// deleted to avoid memory lifetime violations.
307-
auto *initPA = dyn_cast<PartialApplyInst>(inst->getInitializer());
308-
if (initPA && initPA->getNumArguments() == 1)
309-
toDelete.insert(initPA->getArgument(0));
310339
break;
311340
}
312341
}

test/SIL/init_accessors.swift

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
// RUN: %target-swift-frontend -emit-sil -enable-experimental-feature InitAccessors %s | %FileCheck %s
2+
3+
struct TestInit {
4+
var x: Int
5+
var y: Int
6+
var full: (Int, Int)
7+
8+
var point: (Int, Int) {
9+
init(initialValue) initializes(y full) accesses(x) {
10+
self.y = initialValue.1
11+
self.full = (self.x, self.y)
12+
}
13+
14+
get { full }
15+
set { full = newValue }
16+
}
17+
18+
// 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
21+
// CHECK-NEXT: [[INIT_ACCESSOR:%.*]] = function_ref @$s14init_accessors8TestInitV5pointSi_Sitvi : $@convention(thin) (Int, Int, @inout Int) -> (@out Int, @out (Int, Int))
22+
// CHECK: [[Y_REF:%.*]] = struct_element_addr [[SELF_VALUE]] : $*TestInit, #TestInit.y
23+
// CHECK-NEXT: [[FULL_REF:%.*]] = struct_element_addr [[SELF_VALUE]] : $*TestInit, #TestInit.full
24+
// CHECK-NEXT: [[X_REF:%.*]] = struct_element_addr [[SELF_VALUE]] : $*TestInit, #TestInit.x
25+
// CHECK-NEXT: {{.*}} = apply [[INIT_ACCESSOR]]([[Y_REF]], [[FULL_REF]], %0, %1, [[X_REF]]) : $@convention(thin) (Int, Int, @inout Int) -> (@out Int, @out (Int, Int))
26+
init(x: Int, y: Int) {
27+
self.x = x
28+
self.point = (x, y)
29+
}
30+
}
31+
32+
struct TestSetter {
33+
var x: Int
34+
var y: Int
35+
36+
var point: (Int, Int) {
37+
init(initialValue) accesses(x y) {
38+
}
39+
40+
get { (x, y) }
41+
set { }
42+
}
43+
44+
// CHECK-LABEL: sil hidden @$s14init_accessors10TestSetterV1x1yACSi_SitcfC : $@convention(method) (Int, Int, @thin TestSetter.Type) -> TestSetter
45+
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s14init_accessors10TestSetterV5pointSi_Sitvs : $@convention(method) (Int, Int, @inout TestSetter) -> ()
46+
// CHECK-NEXT: [[SETTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[SETTER_REF]]([[SELF_VALUE:%.*]]) : $@convention(method) (Int, Int, @inout TestSetter) -> ()
47+
// CHECk-NEXT: %18 = apply [[SETTER_CLOSURE]](%0, %1) : $@callee_guaranteed (Int, Int) -> ()
48+
init(x: Int, y: Int) {
49+
self.x = x
50+
self.y = y
51+
self.point = (x, y)
52+
}
53+
}
54+
55+
struct TestInitThenSetter {
56+
var x: Int
57+
var y: Int
58+
59+
var point: (Int, Int) {
60+
init(initialValue) initializes(x y) {
61+
self.x = initialValue.0
62+
self.y = initialValue.1
63+
}
64+
65+
get { (x, y) }
66+
set { }
67+
}
68+
69+
// CHECK-LABEL: sil hidden @$s14init_accessors18TestInitThenSetterV1x1yACSi_SitcfC : $@convention(method) (Int, Int, @thin TestInitThenSetter.Type) -> TestInitThenSetter
70+
// CHECK: [[INIT_ACCESSOR:%.*]] = function_ref @$s14init_accessors18TestInitThenSetterV5pointSi_Sitvi : $@convention(thin) (Int, Int) -> (@out Int, @out Int)
71+
// CHECK: [[X_REF:%.*]] = struct_element_addr {{.*}} : $*TestInitThenSetter, #TestInitThenSetter.x
72+
// CHECK-NEXT: [[Y_REF:%.*]] = struct_element_addr {{.*}} : $*TestInitThenSetter, #TestInitThenSetter.y
73+
// CHECK-NEXT: {{.*}} = apply [[INIT_ACCESSOR]]([[X_REF]], [[Y_REF]], %0, %1) : $@convention(thin) (Int, Int) -> (@out Int, @out Int)
74+
//
75+
// CHECK: [[BUILTIN_ZERO:%.*]] = integer_literal $Builtin.Int64, 0
76+
// CHECK-NEXT: [[ZERO_X:%.*]] = struct $Int ([[BUILTIN_ZERO]] : $Builtin.Int64)
77+
// CHECK-NEXT: [[BUILTIN_ZERO:%.*]] = integer_literal $Builtin.Int64, 0
78+
// CHECK-NEXT: [[ZERO_Y:%.*]] = struct $Int ([[BUILTIN_ZERO]] : $Builtin.Int64)
79+
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s14init_accessors18TestInitThenSetterV5pointSi_Sitvs : $@convention(method) (Int, Int, @inout TestInitThenSetter) -> ()
80+
// CHECK-NEXT: [[SETTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[SETTER_REF]]([[SELF_VALUE:%.*]]) : $@convention(method) (Int, Int, @inout TestInitThenSetter) -> ()
81+
// CHECK-NEXT: {{.*}} = apply [[SETTER_CLOSURE]]([[ZERO_X]], [[ZERO_Y]]) : $@callee_guaranteed (Int, Int) -> ()
82+
init(x: Int, y: Int) {
83+
self.point = (x, y)
84+
85+
if x == 1 {
86+
self.point = (0, 0)
87+
}
88+
}
89+
}
90+
91+
struct TestPartialInt {
92+
var x: Int
93+
var y: Int
94+
95+
var pointX: Int {
96+
init(newValue) initializes(x) {
97+
self.x = newValue
98+
}
99+
100+
get { x }
101+
set { self.x = newValue }
102+
}
103+
104+
var pointY: Int {
105+
init(newValue) initializes(y) {
106+
self.y = newValue
107+
}
108+
109+
get { y }
110+
set { self.y = newValue }
111+
}
112+
113+
// CHECK-LABEL: sil hidden @$s14init_accessors14TestPartialIntV1x1yACSi_SitcfC : $@convention(method) (Int, Int, @thin TestPartialInt.Type) -> TestPartialInt
114+
//
115+
// CHECK: [[INIT_REF:%.*]] = function_ref @$s14init_accessors14TestPartialIntV6pointXSivi : $@convention(thin) (Int) -> @out Int
116+
// CHECK: [[X_REF:%.*]] = struct_element_addr {{.*}} : $*TestPartialInt, #TestPartialInt.x
117+
// CHECK-NEXT: {{.*}} = apply [[INIT_REF]]([[X_REF]], %0) : $@convention(thin) (Int) -> @out Int
118+
//
119+
// CHECK: [[INIT_REF:%.*]] = function_ref @$s14init_accessors14TestPartialIntV6pointYSivi : $@convention(thin) (Int) -> @out Int
120+
// CHECK: [[Y_REF:%.*]] = struct_element_addr {{.*}} : $*TestPartialInt, #TestPartialInt.y
121+
// CHECK-NEXT: {{.*}} = apply [[INIT_REF]]([[Y_REF]], %1) : $@convention(thin) (Int) -> @out Int
122+
//
123+
// CHECK: [[BUILTIN_ONE:%.*]] = integer_literal $Builtin.Int64, 1
124+
// CHECK-NEXT: [[ONE:%.*]] = struct $Int ([[BUILTIN_ONE]] : $Builtin.Int64)
125+
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s14init_accessors14TestPartialIntV6pointXSivs : $@convention(method) (Int, @inout TestPartialInt) -> ()
126+
// CHECK-NEXT: [[SETTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[SETTER_REF]]({{.*}}) : $@convention(method) (Int, @inout TestPartialInt) -> ()
127+
// CHECK-NEXT: {{.*}} = apply [[SETTER_CLOSURE]]([[ONE]]) : $@callee_guaranteed (Int) -> ()
128+
//
129+
// CHECK: [[BUILTIN_TWO:%.*]] = integer_literal $Builtin.Int64, 2
130+
// CHECK-NEXT: [[TWO:%.*]] = struct $Int ([[BUILTIN_TWO]] : $Builtin.Int64)
131+
// CHECK: [[SETTER_REF:%.*]] = function_ref @$s14init_accessors14TestPartialIntV6pointYSivs : $@convention(method) (Int, @inout TestPartialInt) -> ()
132+
// CHECK-NEXT: [[SETTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] [[SETTER_REF]]({{.*}}) : $@convention(method) (Int, @inout TestPartialInt) -> ()
133+
// CHECK-NEXT: {{.*}} = apply %32([[TWO]]) : $@callee_guaranteed (Int) -> ()
134+
init(x: Int, y: Int) {
135+
// Init
136+
self.pointX = x
137+
// Init
138+
self.pointY = y
139+
140+
// Setter
141+
self.pointX = 1
142+
// Setter
143+
self.pointY = 2
144+
145+
}
146+
}
147+
148+
struct TestNoInitAndInit {
149+
var x: Int
150+
var y: Int
151+
152+
var pointX: Int {
153+
init(initalValue) accesses(x) {
154+
}
155+
156+
get { x }
157+
set { }
158+
}
159+
160+
var pointY: Int {
161+
init(initialValue) initializes(y) {
162+
self.y = initialValue
163+
}
164+
165+
get { y }
166+
set { }
167+
}
168+
169+
// CHECK-LABEL: sil hidden @$s14init_accessors013TestNoInitAndE0V1x1yACSi_SitcfC : $@convention(method) (Int, Int, @thin TestNoInitAndInit.Type) -> TestNoInitAndInit
170+
//
171+
// 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) -> ()
174+
//
175+
// 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
178+
init(x: Int, y: Int) {
179+
self.x = x
180+
self.pointX = x
181+
self.pointY = y
182+
print("Point(x: \(self.x), y: \(self.y)")
183+
}
184+
}

0 commit comments

Comments
 (0)