Skip to content

Commit 8ef1934

Browse files
committed
---
yaml --- r: 349337 b: refs/heads/master-next c: 7b3af6b h: refs/heads/master i: 349335: d8acde1
1 parent 18870d3 commit 8ef1934

File tree

5 files changed

+193
-38
lines changed

5 files changed

+193
-38
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
refs/heads/master: 3574c513bbc5578dd9346b4ea9ab5995c5927bb5
3-
refs/heads/master-next: 299ef466998dd978b8f48c15cc204da72436fee1
3+
refs/heads/master-next: 7b3af6b0d4900038562ee8701c8afc235e14fec4
44
refs/tags/osx-passed: b6b74147ef8a386f532cf9357a1bde006e552c54
55
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-a: 6bb18e013c2284f2b45f5f84f2df2887dc0f7dea
66
refs/tags/swift-2.2-SNAPSHOT-2015-12-01-b: 66d897bfcf64a82cb9a87f5e663d889189d06d07

branches/master-next/docs/SIL.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2342,8 +2342,8 @@ assign_by_wrapper
23422342
assign_by_wrapper %0 : $S to %1 : $*T, init %2 : $F, set %3 : $G
23432343
// $S can be a value or address type
23442344
// $T must be the type of a property wrapper.
2345-
// $F must be a function type, taking $S as a single argument and returning $T
2346-
// $G must be a function type, taking $S as a single argument and with not return value
2345+
// $F must be a function type, taking $S as a single argument (or multiple arguments in case of a tuple) and returning $T
2346+
// $G must be a function type, taking $S as a single argument (or multiple arguments in case of a tuple) and without a return value
23472347

23482348
Similar to the ``assign`` instruction, but the assignment is done via a
23492349
delegate.

branches/master-next/lib/SIL/SILVerifier.cpp

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1961,6 +1961,34 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
19611961
"Store operand type and dest type mismatch");
19621962
}
19631963

1964+
// Usually the assign_by_wrapper initializer or setter has a single argument
1965+
// (the value). But in case of a tuple, the initializer/setter expect the
1966+
// tuple elements as separate arguments.
1967+
void checkAssignByWrapperArgsRecursively(SILType ty,
1968+
SILFunctionConventions &conv, unsigned &argIdx) {
1969+
if (auto tupleTy = ty.getAs<TupleType>()) {
1970+
for (Type et : tupleTy->getElementTypes()) {
1971+
SILType elTy = SILType::getPrimitiveType(CanType(et), ty.getCategory());
1972+
checkAssignByWrapperArgsRecursively(elTy, conv, argIdx);
1973+
}
1974+
return;
1975+
}
1976+
require(argIdx < conv.getNumSILArguments(),
1977+
"initializer or setter has too few arguments");
1978+
SILType argTy = conv.getSILArgumentType(argIdx++);
1979+
if (ty.isAddress() && argTy.isObject())
1980+
ty = ty.getObjectType();
1981+
require(ty == argTy,
1982+
"wrong argument type of initializer or setter");
1983+
}
1984+
1985+
void checkAssignByWrapperArgs(SILType ty, SILFunctionConventions &conv) {
1986+
unsigned argIdx = conv.getSILArgIndexOfFirstParam();
1987+
checkAssignByWrapperArgsRecursively(ty, conv, argIdx);
1988+
require(argIdx == conv.getNumSILArguments(),
1989+
"initializer or setter has too many arguments");
1990+
}
1991+
19641992
void checkAssignByWrapperInst(AssignByWrapperInst *AI) {
19651993
SILValue Src = AI->getSrc(), Dest = AI->getDest();
19661994
require(AI->getModule().getStage() == SILStage::Raw,
@@ -1970,11 +1998,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
19701998
SILValue initFn = AI->getInitializer();
19711999
CanSILFunctionType initTy = initFn->getType().castTo<SILFunctionType>();
19722000
SILFunctionConventions initConv(initTy, AI->getModule());
1973-
unsigned firstArgIdx = initConv.getSILArgIndexOfFirstParam();
1974-
require(initConv.getNumSILArguments() == firstArgIdx + 1,
1975-
"init function has wrong number of arguments");
1976-
require(Src->getType() == initConv.getSILArgumentType(firstArgIdx),
1977-
"wrong argument type of init function");
2001+
checkAssignByWrapperArgs(Src->getType(), initConv);
19782002
switch (initConv.getNumIndirectSILResults()) {
19792003
case 0:
19802004
require(initConv.getNumDirectSILResults() == 1,
@@ -1998,10 +2022,7 @@ class SILVerifier : public SILVerifierBase<SILVerifier> {
19982022
SILFunctionConventions setterConv(setterTy, AI->getModule());
19992023
require(setterConv.getNumIndirectSILResults() == 0,
20002024
"set function has indirect results");
2001-
require(setterConv.getNumSILArguments() == 1,
2002-
"init function has wrong number of arguments");
2003-
require(Src->getType() == setterConv.getSILArgumentType(0),
2004-
"wrong argument type of init function");
2025+
checkAssignByWrapperArgs(Src->getType(), setterConv);
20052026
}
20062027

20072028
#define NEVER_LOADABLE_CHECKED_REF_STORAGE(Name, name, ...) \

branches/master-next/lib/SILOptimizer/Mandatory/RawSILInstLowering.cpp

Lines changed: 86 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,80 @@ static void lowerAssignInstruction(SILBuilderWithScope &b, AssignInst *inst) {
9191
inst->eraseFromParent();
9292
}
9393

94+
/// Construct the argument list for the assign_by_wrapper initializer or setter.
95+
///
96+
/// Usually this is only a single value and a single argument, but in case of
97+
/// a tuple, the initializer/setter expect the tuple elements as separate
98+
/// arguments. The purpose of this function is to recursively visit tuple
99+
/// elements and add them to the argument list \p arg.
100+
static void getAssignByWrapperArgsRecursively(SmallVectorImpl<SILValue> &args,
101+
SILValue src, unsigned &argIdx, const SILFunctionConventions &convention,
102+
SILBuilder &forProjections, SILBuilder &forCleanup) {
103+
104+
SILLocation loc = (*forProjections.getInsertionPoint()).getLoc();
105+
SILType srcTy = src->getType();
106+
if (auto tupleTy = srcTy.getAs<TupleType>()) {
107+
// In case the source is a tuple, we have to destructure the tuple and pass
108+
// the tuple elements separately.
109+
if (srcTy.isAddress()) {
110+
for (unsigned idx = 0, n = tupleTy->getNumElements(); idx < n; ++idx) {
111+
auto *TEA = forProjections.createTupleElementAddr(loc, src, idx);
112+
getAssignByWrapperArgsRecursively(args, TEA, argIdx, convention,
113+
forProjections, forCleanup);
114+
}
115+
} else {
116+
auto *DTI = forProjections.createDestructureTuple(loc, src);
117+
for (SILValue elmt : DTI->getAllResults()) {
118+
getAssignByWrapperArgsRecursively(args, elmt, argIdx, convention,
119+
forProjections, forCleanup);
120+
}
121+
}
122+
return;
123+
}
124+
assert(argIdx < convention.getNumSILArguments() &&
125+
"initializer or setter has too few arguments");
126+
127+
SILArgumentConvention argConv = convention.getSILArgumentConvention(argIdx);
128+
if (srcTy.isAddress() && !argConv.isIndirectConvention()) {
129+
// In case of a tuple where one element is loadable, but the other is
130+
// address only, we get the whole tuple as address.
131+
// For the loadable element, the argument is passed directly, but the
132+
// tuple element is in memory. For this case we have to insert a load.
133+
src = forProjections.createTrivialLoadOr(loc, src,
134+
LoadOwnershipQualifier::Take);
135+
}
136+
switch (argConv) {
137+
case SILArgumentConvention::Indirect_In_Guaranteed:
138+
forCleanup.createDestroyAddr(loc, src);
139+
break;
140+
case SILArgumentConvention::Direct_Guaranteed:
141+
forCleanup.createDestroyValue(loc, src);
142+
break;
143+
case SILArgumentConvention::Direct_Unowned:
144+
case SILArgumentConvention::Indirect_In:
145+
case SILArgumentConvention::Indirect_In_Constant:
146+
case SILArgumentConvention::Direct_Owned:
147+
break;
148+
case SILArgumentConvention::Indirect_Inout:
149+
case SILArgumentConvention::Indirect_InoutAliasable:
150+
case SILArgumentConvention::Indirect_Out:
151+
case SILArgumentConvention::Direct_Deallocating:
152+
llvm_unreachable("wrong convention for setter/initializer src argument");
153+
}
154+
args.push_back(src);
155+
++argIdx;
156+
}
157+
158+
static void getAssignByWrapperArgs(SmallVectorImpl<SILValue> &args,
159+
SILValue src, const SILFunctionConventions &convention,
160+
SILBuilder &forProjections, SILBuilder &forCleanup) {
161+
unsigned argIdx = convention.getSILArgIndexOfFirstParam();
162+
getAssignByWrapperArgsRecursively(args, src, argIdx, convention,
163+
forProjections, forCleanup);
164+
assert(argIdx == convention.getNumSILArguments() &&
165+
"initializer or setter has too many arguments");
166+
}
167+
94168
static void lowerAssignByWrapperInstruction(SILBuilderWithScope &b,
95169
AssignByWrapperInst *inst,
96170
SmallVectorImpl<BeginAccessInst *> &accessMarkers) {
@@ -103,21 +177,24 @@ static void lowerAssignByWrapperInstruction(SILBuilderWithScope &b,
103177
SILValue src = inst->getSrc();
104178
SILValue dest = inst->getDest();
105179
SILLocation loc = inst->getLoc();
106-
SILArgumentConvention srcConvention(SILArgumentConvention::Indirect_Inout);
180+
SILBuilderWithScope forCleanup(std::next(inst->getIterator()));
107181

108182
switch (inst->getOwnershipQualifier()) {
109183
case AssignOwnershipQualifier::Init: {
110184
SILValue initFn = inst->getInitializer();
111185
CanSILFunctionType fTy = initFn->getType().castTo<SILFunctionType>();
112186
SILFunctionConventions convention(fTy, inst->getModule());
187+
SmallVector<SILValue, 4> args;
113188
if (convention.hasIndirectSILResults()) {
114-
b.createApply(loc, initFn, SubstitutionMap(), { dest, src });
115-
srcConvention = convention.getSILArgumentConvention(1);
189+
args.push_back(dest);
190+
getAssignByWrapperArgs(args, src, convention, b, forCleanup);
191+
b.createApply(loc, initFn, SubstitutionMap(), args);
116192
} else {
193+
getAssignByWrapperArgs(args, src, convention, b, forCleanup);
117194
SILValue wrappedSrc = b.createApply(loc, initFn, SubstitutionMap(),
118-
{ src });
119-
b.createTrivialStoreOr(loc, wrappedSrc, dest, StoreOwnershipQualifier::Init);
120-
srcConvention = convention.getSILArgumentConvention(0);
195+
args);
196+
b.createTrivialStoreOr(loc, wrappedSrc, dest,
197+
StoreOwnershipQualifier::Init);
121198
}
122199
// TODO: remove the unused setter function, which usually is a dead
123200
// partial_apply.
@@ -129,8 +206,9 @@ static void lowerAssignByWrapperInstruction(SILBuilderWithScope &b,
129206
CanSILFunctionType fTy = setterFn->getType().castTo<SILFunctionType>();
130207
SILFunctionConventions convention(fTy, inst->getModule());
131208
assert(!convention.hasIndirectSILResults());
132-
srcConvention = convention.getSILArgumentConvention(0);
133-
b.createApply(loc, setterFn, SubstitutionMap(), { src });
209+
SmallVector<SILValue, 4> args;
210+
getAssignByWrapperArgs(args, src, convention, b, forCleanup);
211+
b.createApply(loc, setterFn, SubstitutionMap(), args);
134212

135213
// The destination address is not used. Remove it if it is a dead access
136214
// marker. This is important, because also the setter function contains
@@ -145,24 +223,6 @@ static void lowerAssignByWrapperInstruction(SILBuilderWithScope &b,
145223
case AssignOwnershipQualifier::Reinit:
146224
llvm_unreachable("wrong qualifier for assign_by_wrapper");
147225
}
148-
switch (srcConvention) {
149-
case SILArgumentConvention::Indirect_In_Guaranteed:
150-
b.createDestroyAddr(loc, src);
151-
break;
152-
case SILArgumentConvention::Direct_Guaranteed:
153-
b.createDestroyValue(loc, src);
154-
break;
155-
case SILArgumentConvention::Direct_Unowned:
156-
case SILArgumentConvention::Indirect_In:
157-
case SILArgumentConvention::Indirect_In_Constant:
158-
case SILArgumentConvention::Direct_Owned:
159-
break;
160-
case SILArgumentConvention::Indirect_Inout:
161-
case SILArgumentConvention::Indirect_InoutAliasable:
162-
case SILArgumentConvention::Indirect_Out:
163-
case SILArgumentConvention::Direct_Deallocating:
164-
llvm_unreachable("wrong convention for setter/initializer src argument");
165-
}
166226
inst->eraseFromParent();
167227
}
168228

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -module-name=a -o %t/a.out
3+
// RUN: %target-run %t/a.out | %FileCheck %s
4+
5+
// REQUIRES: executable_test
6+
7+
@propertyWrapper struct D<Value> {
8+
var wrappedValue: Value {
9+
didSet {
10+
print("set: \(wrappedValue)")
11+
}
12+
}
13+
14+
init(wrappedValue: Value) {
15+
self.wrappedValue = wrappedValue
16+
print("init: \(wrappedValue)")
17+
}
18+
19+
}
20+
21+
struct S<T> {
22+
@D var a: (Int,Int)
23+
@D var b: (T,T)
24+
@D var c: (Int,(Int, Bool))
25+
@D var d: (T,Int)
26+
@D var e: (Int,(T, Bool))
27+
28+
init(_ t: T) {
29+
// CHECK: init: (27, 28)
30+
a = (27, 28)
31+
// CHECK: init: (a.X, a.X)
32+
b = (t, t)
33+
// CHECK: init: (27, (28, true))
34+
c = (27, (28, true))
35+
// CHECK: init: (a.X, 27)
36+
d = (t, 27)
37+
// CHECK: init: (27, (a.X, true))
38+
e = (27, (t, true))
39+
// CHECK: set: (27, 28)
40+
a = (27, 28)
41+
// CHECK: set: (a.X, a.X)
42+
b = (t, t)
43+
// CHECK: set: (27, (28, true))
44+
c = (27, (28, true))
45+
// CHECK: set: (a.X, 27)
46+
d = (t, 27)
47+
// CHECK: set: (27, (a.X, true))
48+
e = (27, (t, true))
49+
}
50+
51+
}
52+
53+
class X {
54+
55+
56+
static var numInstances = 0
57+
58+
init() {
59+
X.numInstances += 1
60+
}
61+
62+
deinit {
63+
X.numInstances -= 1
64+
}
65+
}
66+
67+
func test() {
68+
_ = S(X())
69+
}
70+
71+
test()
72+
73+
// CHECK: num instances of X: 0
74+
print("num instances of X: \(X.numInstances)")

0 commit comments

Comments
 (0)