Skip to content

Commit 61e8585

Browse files
authored
Merge pull request #67040 from rjmccall/variadic-tuple-result-reabstraction-thunks
Handle variadic tuples in reabstraction thunk emission
2 parents 227c6a8 + c0777e6 commit 61e8585

23 files changed

+2271
-372
lines changed

SwiftCompilerSources/Sources/SIL/Argument.swift

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,17 @@ public enum ArgumentConvention {
141141
/// indirectly is recorded in the pack type.
142142
case packGuaranteed
143143

144+
/// This argument is a pack of indirect return value addresses. The
145+
/// addresses are stored in the pack by the caller and read out by the
146+
/// callee; within the callee, they are individually treated like
147+
/// indirectOut arguments.
148+
case packOut
149+
144150
public var isIndirect: Bool {
145151
switch self {
146152
case .indirectIn, .indirectInGuaranteed,
147153
.indirectInout, .indirectInoutAliasable, .indirectOut,
148-
.packInout, .packOwned, .packGuaranteed:
154+
.packOut, .packInout, .packOwned, .packGuaranteed:
149155
return true
150156
case .directOwned, .directUnowned, .directGuaranteed:
151157
return false
@@ -159,7 +165,19 @@ public enum ArgumentConvention {
159165
return true
160166
case .directOwned, .directUnowned, .directGuaranteed,
161167
.indirectInout, .indirectInoutAliasable, .indirectOut,
162-
.packInout:
168+
.packOut, .packInout:
169+
return false
170+
}
171+
}
172+
173+
public var isIndirectOut: Bool {
174+
switch self {
175+
case .indirectOut, .packOut:
176+
return true
177+
case .indirectInGuaranteed, .directGuaranteed, .packGuaranteed,
178+
.indirectIn, .directOwned, .directUnowned,
179+
.indirectInout, .indirectInoutAliasable,
180+
.packInout, .packOwned:
163181
return false
164182
}
165183
}
@@ -170,7 +188,7 @@ public enum ArgumentConvention {
170188
return true
171189
case .indirectIn, .directOwned, .directUnowned,
172190
.indirectInout, .indirectInoutAliasable, .indirectOut,
173-
.packInout, .packOwned:
191+
.packOut, .packInout, .packOwned:
174192
return false
175193
}
176194
}
@@ -181,6 +199,7 @@ public enum ArgumentConvention {
181199
.indirectOut,
182200
.indirectInGuaranteed,
183201
.indirectInout,
202+
.packOut,
184203
.packInout,
185204
.packOwned,
186205
.packGuaranteed:
@@ -207,6 +226,7 @@ public enum ArgumentConvention {
207226
.directUnowned,
208227
.directGuaranteed,
209228
.directOwned,
229+
.packOut,
210230
.packOwned,
211231
.packGuaranteed:
212232
return false
@@ -233,6 +253,7 @@ extension BridgedArgumentConvention {
233253
case .Direct_Owned: return .directOwned
234254
case .Direct_Unowned: return .directUnowned
235255
case .Direct_Guaranteed: return .directGuaranteed
256+
case .Pack_Out: return .packOut
236257
case .Pack_Inout: return .packInout
237258
case .Pack_Owned: return .packOwned
238259
case .Pack_Guaranteed: return .packGuaranteed

SwiftCompilerSources/Sources/SIL/Effects.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ extension Function {
143143
if convention.isIndirectIn {
144144
// Even a `[readnone]` function can read from an indirect argument.
145145
result.memory.read = true
146-
} else if convention == .indirectOut {
146+
} else if convention.isIndirectOut {
147147
// Even `[readnone]` and `[readonly]` functions write to indirect results.
148148
result.memory.write = true
149149
}
@@ -546,7 +546,7 @@ public struct SideEffects : CustomStringConvertible, NoReflectionChildren {
546546
case .indirectInGuaranteed, .packGuaranteed:
547547
result.memory.write = false
548548
result.ownership.destroy = false
549-
case .indirectOut, .packInout:
549+
case .indirectOut, .packOut, .packInout:
550550
result.memory.read = false
551551
result.ownership.copy = false
552552
result.ownership.destroy = false

SwiftCompilerSources/Sources/SIL/Function.swift

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,6 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash
8585
public var resultType: Type { bridged.getSILResultType().type }
8686

8787
public func getArgumentConvention(for argumentIndex: Int) -> ArgumentConvention {
88-
if argumentIndex < numIndirectResultArguments {
89-
return .indirectOut
90-
}
9188
return bridged.getSILArgumentConvention(argumentIndex).convention
9289
}
9390

include/swift/Basic/Generators.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,10 @@ class ArrayRefGenerator {
146146
}
147147
};
148148

149+
namespace generator_details {
150+
template <class T> struct is_simple_generator_ref;
151+
}
152+
149153
/// An abstracting reference to an existing generator.
150154
///
151155
/// The implementation of this type holds the reference to the existing
@@ -182,7 +186,8 @@ class SimpleGeneratorRef {
182186
constexpr SimpleGeneratorRef() : vtable(nullptr), pointer(nullptr) {}
183187

184188
template <class G>
185-
constexpr SimpleGeneratorRef(G &generator)
189+
constexpr SimpleGeneratorRef(G &generator,
190+
typename std::enable_if<!generator_details::is_simple_generator_ref<G>::value, bool>::type = false)
186191
: vtable(&VTableImpl<G>::vtable), pointer(&generator) {}
187192

188193
/// Test whether this generator ref was initialized with a
@@ -212,6 +217,19 @@ class SimpleGeneratorRef {
212217
}
213218
};
214219

220+
namespace generator_details {
221+
222+
template <class T>
223+
struct is_simple_generator_ref<SimpleGeneratorRef<T>> {
224+
static constexpr bool value = true;
225+
};
226+
template <class T>
227+
struct is_simple_generator_ref {
228+
static constexpr bool value = false;
229+
};
230+
231+
}
232+
215233
} // end namespace swift
216234

217235
#endif

include/swift/SIL/AbstractionPattern.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,6 +1354,10 @@ class AbstractionPattern {
13541354
llvm::Optional<AbstractionPattern>
13551355
getVanishingTupleElementPatternType() const;
13561356

1357+
/// Does this tuple type vanish, i.e. is it flattened to a singleton
1358+
/// non-expansion element under substitution?
1359+
bool doesTupleVanish() const;
1360+
13571361
static AbstractionPattern
13581362
projectTupleElementType(const AbstractionPattern *base, size_t index) {
13591363
return base->getTupleElementType(index);

include/swift/SIL/AbstractionPatternGenerators.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,11 @@ class TupleElementGenerator {
224224
return origEltIndex == numOrigElts;
225225
}
226226

227+
/// Does the entire original tuple vanish?
228+
bool doesOrigTupleVanish() const {
229+
return origTupleVanishes;
230+
}
231+
227232
/// Advance to the next orig element.
228233
void advance() {
229234
assert(!isFinished());

include/swift/SIL/SILArgument.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,6 @@ class SILPhiArgument;
2828
class SILUndef;
2929
class TermInst;
3030

31-
// Map an argument index onto a SILArgumentConvention.
32-
inline SILArgumentConvention
33-
SILFunctionConventions::getSILArgumentConvention(unsigned index) const {
34-
assert(index <= getNumSILArguments());
35-
if (index < getNumIndirectSILResults()) {
36-
assert(silConv.loweredAddresses);
37-
return SILArgumentConvention::Indirect_Out;
38-
} else {
39-
auto param = funcTy->getParameters()[index - getNumIndirectSILResults()];
40-
return SILArgumentConvention(param.getConvention());
41-
}
42-
}
43-
4431
struct SILArgumentKind {
4532
enum innerty : std::underlying_type<ValueKind>::type {
4633
#define ARGUMENT(ID, PARENT) ID = unsigned(SILNodeKind::ID),

include/swift/SIL/SILArgumentConvention.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,28 @@ struct SILArgumentConvention {
164164
}
165165
llvm_unreachable("covered switch isn't covered?!");
166166
}
167+
168+
/// Returns true if \p Value is an indirect-out parameter.
169+
bool isIndirectOutParameter() {
170+
switch (Value) {
171+
case SILArgumentConvention::Indirect_Out:
172+
case SILArgumentConvention::Pack_Out:
173+
return true;
174+
175+
case SILArgumentConvention::Indirect_In:
176+
case SILArgumentConvention::Indirect_In_Guaranteed:
177+
case SILArgumentConvention::Indirect_Inout:
178+
case SILArgumentConvention::Indirect_InoutAliasable:
179+
case SILArgumentConvention::Direct_Unowned:
180+
case SILArgumentConvention::Direct_Guaranteed:
181+
case SILArgumentConvention::Direct_Owned:
182+
case SILArgumentConvention::Pack_Inout:
183+
case SILArgumentConvention::Pack_Owned:
184+
case SILArgumentConvention::Pack_Guaranteed:
185+
return false;
186+
}
187+
llvm_unreachable("covered switch isn't covered?!");
188+
}
167189
};
168190

169191
} // namespace swift

include/swift/SIL/SILBridging.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ struct BridgedFunction {
219219

220220
BridgedArgumentConvention getSILArgumentConvention(SwiftInt idx) const {
221221
swift::SILFunctionConventions conv(getFunction()->getConventionsInContext());
222-
return castToArgumentConvention(swift::SILArgumentConvention(conv.getParamInfoForSILArg(idx).getConvention()));
222+
return castToArgumentConvention(conv.getSILArgumentConvention(idx));
223223
}
224224

225225
swift::SILType getSILResultType() const {

include/swift/SIL/SILFunctionConventions.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,6 @@ class SILFunctionConventions {
409409
/// Return the SIL argument convention of apply/entry argument at
410410
/// the given argument index.
411411
SILArgumentConvention getSILArgumentConvention(unsigned index) const;
412-
// See SILArgument.h.
413412

414413
/// Return the SIL type of the apply/entry argument at the given index.
415414
SILType getSILArgumentType(unsigned index,

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ bool AbstractionPattern::matchesTuple(CanType substType) const {
312312
return false;
313313
LLVM_FALLTHROUGH;
314314
case Kind::Tuple: {
315-
if (getVanishingTupleElementPatternType()) {
315+
if (doesTupleVanish()) {
316316
// TODO: recurse into elements.
317317
return true;
318318
}
@@ -478,6 +478,11 @@ bool AbstractionPattern::doesTupleContainPackExpansionType() const {
478478
llvm_unreachable("bad kind");
479479
}
480480

481+
bool AbstractionPattern::doesTupleVanish() const {
482+
assert(isTuple());
483+
return getVanishingTupleElementPatternType().has_value();
484+
}
485+
481486
llvm::Optional<AbstractionPattern>
482487
AbstractionPattern::getVanishingTupleElementPatternType() const {
483488
if (!isTuple())
@@ -553,8 +558,7 @@ TupleElementGenerator::TupleElementGenerator(
553558
assert(origTupleType.isTuple());
554559
assert(origTupleType.matchesTuple(substType));
555560

556-
origTupleVanishes =
557-
origTupleType.getVanishingTupleElementPatternType().has_value();
561+
origTupleVanishes = origTupleType.doesTupleVanish();
558562
origTupleTypeIsOpaque = origTupleType.isOpaqueTuple();
559563
numOrigElts = origTupleType.getNumTupleElements();
560564

lib/SIL/IR/SILArgument.cpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,42 @@ SILParameterInfo SILFunctionArgument::getKnownParameterInfo() const {
7575
return getFunction()->getConventions().getParamInfoForSILArg(getIndex());
7676
}
7777

78+
SILArgumentConvention
79+
SILFunctionConventions::getSILArgumentConvention(unsigned index) const {
80+
assert(index < getNumSILArguments());
81+
82+
// If the argument is a parameter, index into the parameters.
83+
if (index >= getNumIndirectSILResults()) {
84+
auto param = funcTy->getParameters()[index - getNumIndirectSILResults()];
85+
return SILArgumentConvention(param.getConvention());
86+
}
87+
88+
// If it's an indirect result, it could be either Pack_Out or
89+
// Indirect_Out.
90+
91+
// Handle the common case of a function with no pack results.
92+
if (funcTy->getNumPackResults() == 0) {
93+
assert(silConv.loweredAddresses);
94+
return SILArgumentConvention::Indirect_Out;
95+
}
96+
97+
// Otherwise, we need to index into the indirect results to figure out
98+
// whether the result is a pack or not, and unfortunately that is not a
99+
// linear algorithm.
100+
for (auto result : getIndirectSILResults()) {
101+
if (index == 0) {
102+
if (result.getConvention() == ResultConvention::Indirect) {
103+
assert(silConv.loweredAddresses);
104+
return SILArgumentConvention::Indirect_Out;
105+
} else {
106+
assert(result.getConvention() == ResultConvention::Pack);
107+
return SILArgumentConvention::Pack_Out;
108+
}
109+
}
110+
index--;
111+
}
112+
llvm_unreachable("mismatch with getNumIndirectSILResults()?");
113+
}
78114

79115
//===----------------------------------------------------------------------===//
80116
// SILBlockArgument

lib/SILGen/Cleanup.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,3 +499,35 @@ CleanupCloner::cloneForRemainingPackComponents(SILValue packAddr,
499499
firstComponentIndex);
500500
return ManagedValue(packAddr, cleanup);
501501
}
502+
503+
ManagedValue
504+
CleanupCloner::cloneForRemainingTupleComponents(SILValue tupleAddr,
505+
CanPackType inducedPackType,
506+
unsigned firstComponentIndex) const {
507+
if (isLValue) {
508+
return ManagedValue::forLValue(tupleAddr);
509+
}
510+
511+
if (!hasCleanup) {
512+
return ManagedValue::forUnmanaged(tupleAddr);
513+
}
514+
515+
assert(!writebackBuffer.has_value());
516+
bool isTrivial = true;
517+
auto tupleTy = tupleAddr->getType().castTo<TupleType>();
518+
for (auto eltTy : tupleTy.getElementTypes().slice(firstComponentIndex)) {
519+
if (!SILType::getPrimitiveObjectType(eltTy).isTrivial(SGF.F)) {
520+
isTrivial = false;
521+
break;
522+
}
523+
}
524+
525+
if (isTrivial)
526+
return ManagedValue::forUnmanaged(tupleAddr);
527+
528+
auto cleanup =
529+
SGF.enterDestroyRemainingTupleElementsCleanup(tupleAddr,
530+
inducedPackType,
531+
firstComponentIndex);
532+
return ManagedValue(tupleAddr, cleanup);
533+
}

lib/SILGen/Cleanup.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,9 @@ class CleanupCloner {
349349
ManagedValue cloneForRemainingPackComponents(SILValue packAddr,
350350
CanPackType formalPackType,
351351
unsigned firstComponentIndex) const;
352+
ManagedValue cloneForRemainingTupleComponents(SILValue tupleAddr,
353+
CanPackType inducedPackType,
354+
unsigned firstComponentIndex) const;
352355

353356
static void
354357
getClonersForRValue(SILGenFunction &SGF, const RValue &rvalue,

lib/SILGen/ResultPlan.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1324,7 +1324,7 @@ ResultPlanPtr ResultPlanBuilder::buildForTuple(Initialization *init,
13241324
// emit directly into the initialization. If the orig tuple vanishes,
13251325
// that counts as the initialization being splittable.
13261326
if (init) {
1327-
bool vanishes = origType.getVanishingTupleElementPatternType().has_value();
1327+
bool vanishes = origType.doesTupleVanish();
13281328
if (vanishes || init->canSplitIntoTupleElements()) {
13291329
return ResultPlanPtr(
13301330
new TupleInitializationResultPlan(*this, init, origType, substType,

lib/SILGen/SILGenApply.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3417,8 +3417,7 @@ class ArgEmitter {
34173417
// If the original parameter type is a vanishing tuple, we want to emit
34183418
// this as if the argument source was wrapped in an extra level of
34193419
// tuple literal.
3420-
bool origTupleVanishes =
3421-
origParamType.getVanishingTupleElementPatternType().has_value();
3420+
bool origTupleVanishes = origParamType.doesTupleVanish();
34223421

34233422
auto substType = arg.getSubstRValueType();
34243423

lib/SILGen/SILGenFunction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -990,7 +990,7 @@ SILGenFunction::emitClosureValue(SILLocation loc, SILDeclRef constant,
990990

991991
// Get the lowered AST types:
992992
// - the original type
993-
auto origFormalType = AbstractionPattern(constantInfo.LoweredType);
993+
auto origFormalType = AbstractionPattern(subs, constantInfo.LoweredType);
994994

995995
// - the substituted type
996996
auto substFormalType = expectedType;

0 commit comments

Comments
 (0)