10
10
//
11
11
// ===----------------------------------------------------------------------===//
12
12
13
+ #include " ASTVisitor.h"
13
14
#include " SILGen.h"
14
15
#include " SILGenFunction.h"
15
- #include " ASTVisitor .h"
16
+ #include " swift/AST/Types .h"
16
17
#include " swift/SIL/SILArgument.h"
18
+ #include " llvm/ADT/STLExtras.h"
17
19
18
20
using namespace swift ;
19
21
using namespace Lowering ;
@@ -33,7 +35,28 @@ void SILGenFunction::prepareEpilog(Optional<Type> directResultType,
33
35
for (auto directResult : fnConv.getDirectSILResults ()) {
34
36
SILType resultType = F.getLoweredType (F.mapTypeIntoContext (
35
37
fnConv.getSILType (directResult, getTypeExpansionContext ())));
36
- epilogBB->createPhiArgument (resultType, OwnershipKind::Owned);
38
+ // @out tuples do not get flattened in the function's return type, but
39
+ // the epilog block expects (recursively) flattened arguments. Flatten
40
+ // the type now.
41
+ SmallVector<SILType, 4 > worklist;
42
+ worklist.push_back (resultType);
43
+ while (!worklist.empty ()) {
44
+ auto ty = worklist.pop_back_val ();
45
+ if (auto tupleType = ty.getASTType ()->getAs <TupleType>()) {
46
+ assert (!fnConv.useLoweredAddresses () &&
47
+ " expanding tuple in non-opaque-values exit block?!" );
48
+ // Push tuple elements in reverse order (resulting in later tuple
49
+ // elements appearing earlier in worklist) so that as the worklist
50
+ // is drained by popping the back, arguments are created for the
51
+ // earlier types first.
52
+ for (auto index :
53
+ llvm::reverse (indices (tupleType->getElementTypes ()))) {
54
+ worklist.push_back (ty.getTupleElementType (index));
55
+ }
56
+ } else {
57
+ epilogBB->createPhiArgument (ty, OwnershipKind::Owned);
58
+ }
59
+ }
37
60
}
38
61
}
39
62
}
@@ -61,15 +84,84 @@ void SILGenFunction::prepareCoroutineUnwindEpilog(CleanupLocation cleanupLoc) {
61
84
CoroutineUnwindDest = JumpDest (unwindBB, getCleanupsDepth (), cleanupLoc);
62
85
}
63
86
87
+ // / View a given SILType as a type-tree under the operation of tupling and visit
88
+ // / its nodes (tuple elements) in post-order.
89
+ // /
90
+ // / For convenience, the index of the type in the flattened tuple is passed to
91
+ // / the visitor.
92
+ template <typename Visit>
93
+ void visitTupleTypeTreeInPostOrder (SILType root, Visit visit) {
94
+ struct Node {
95
+ SILType ty;
96
+ unsigned index;
97
+ };
98
+ SmallVector<std::pair<Node, unsigned >, 32 > stack;
99
+ auto tupleElementCount = [](SILType ty) -> unsigned {
100
+ if (auto tupleType = ty.getASTType ()->getAs <TupleType>())
101
+ return tupleType->getNumElements ();
102
+ return 0 ;
103
+ };
104
+ auto tupleElement = [](SILType ty, unsigned index) -> SILType {
105
+ return ty.getTupleElementType (index);
106
+ };
107
+ unsigned flattenedIndex = 0 ;
108
+ stack.push_back ({{root, flattenedIndex}, 0 });
109
+ while (!stack.empty ()) {
110
+ while (stack.back ().second != tupleElementCount (stack.back ().first .ty )) {
111
+ auto index = stack.back ().second ;
112
+ stack.back ().second ++;
113
+ stack.push_back (
114
+ {{tupleElement (stack.back ().first .ty , index), flattenedIndex}, 0 });
115
+ }
116
+ auto node = stack.pop_back_val ().first ;
117
+ visit (node.ty , node.index );
118
+ if (!node.ty .getASTType ()->template is <TupleType>())
119
+ flattenedIndex += 1 ;
120
+ }
121
+ }
122
+
64
123
// / Given a list of direct results, form the direct result value.
65
124
// /
66
125
// / Note that this intentionally loses any tuple sub-structure of the
67
- // / formal result type.
126
+ // / formal result type, except in the case of @out tuples where it must be
127
+ // / preserved.
68
128
static SILValue buildReturnValue (SILGenFunction &SGF, SILLocation loc,
69
129
ArrayRef<SILValue> directResults) {
70
130
if (directResults.size () == 1 )
71
131
return directResults[0 ];
72
132
133
+ auto fnConv = SGF.F .getConventions ();
134
+ if (!fnConv.useLoweredAddresses ()) {
135
+ // In opaque-values code, nested @out enums are not flattened. Reconstruct
136
+ // nested tuples.
137
+ auto resultType = SGF.F .getLoweredType (SGF.F .mapTypeIntoContext (
138
+ fnConv.getSILResultType (SGF.getTypeExpansionContext ())));
139
+ SmallVector<Optional<SILValue>, 4 > mutableDirectResult;
140
+ for (auto result : directResults) {
141
+ mutableDirectResult.push_back ({result});
142
+ }
143
+ visitTupleTypeTreeInPostOrder (resultType, [&](SILType ty, unsigned index) {
144
+ if (auto tupleTy = ty.getASTType ()->getAs <TupleType>()) {
145
+ SmallVector<SILValue, 4 > elements;
146
+ unsigned offset = 0 ;
147
+ auto elementCount = tupleTy->getNumElements ();
148
+ while (elements.size () < elementCount) {
149
+ if (mutableDirectResult[index + offset].hasValue ()) {
150
+ auto val = mutableDirectResult[index + offset].getValue ();
151
+ elements.push_back (val);
152
+ mutableDirectResult[index + offset].reset ();
153
+ }
154
+ ++offset;
155
+ }
156
+ assert (!mutableDirectResult[index].hasValue ());
157
+ auto tuple = SGF.B .createTuple (loc, ty, elements);
158
+ mutableDirectResult[index] = tuple;
159
+ }
160
+ });
161
+ assert (mutableDirectResult[0 ].hasValue ());
162
+ return mutableDirectResult[0 ].getValue ();
163
+ }
164
+
73
165
SmallVector<TupleTypeElt, 4 > eltTypes;
74
166
for (auto elt : directResults)
75
167
eltTypes.push_back (elt->getType ().getASTType ());
@@ -195,7 +287,9 @@ SILGenFunction::emitEpilogBB(SILLocation topLevel) {
195
287
// block.
196
288
SILValue returnValue;
197
289
if (!directResults.empty ()) {
198
- assert (directResults.size () == F.getConventions ().getNumDirectSILResults ());
290
+ assert (directResults.size () ==
291
+ F.getConventions ().getNumExpandedDirectSILResults (
292
+ getTypeExpansionContext ()));
199
293
returnValue = buildReturnValue (*this , topLevel, directResults);
200
294
}
201
295
0 commit comments