Skip to content

Commit 7442099

Browse files
committed
Teach ResultPlan to handle packs correctly when we're not emitting
into an Initialization. rdar://107161241
1 parent de283f8 commit 7442099

File tree

3 files changed

+128
-49
lines changed

3 files changed

+128
-49
lines changed

lib/SILGen/ResultPlan.cpp

Lines changed: 88 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ using namespace Lowering;
2727
// Result Plans
2828
//===----------------------------------------------------------------------===//
2929

30+
void ResultPlan::finishAndAddTo(SILGenFunction &SGF, SILLocation loc,
31+
ArrayRef<ManagedValue> &directResults,
32+
SILValue bridgedForeignError,
33+
RValue &result) {
34+
auto rvalue = finish(SGF, loc, directResults, bridgedForeignError);
35+
assert(!rvalue.isInContext());
36+
result.addElement(std::move(rvalue));
37+
}
38+
3039
namespace {
3140

3241
/// A result plan for evaluating an indirect result into the address
@@ -343,14 +352,16 @@ class ScalarResultPlan final : public ResultPlan {
343352
/// using a temporary buffer initialized by a sub-plan.
344353
class InitValueFromTemporaryResultPlan final : public ResultPlan {
345354
Initialization *init;
355+
CanType substType;
346356
ResultPlanPtr subPlan;
347357
std::unique_ptr<TemporaryInitialization> temporary;
348358

349359
public:
350360
InitValueFromTemporaryResultPlan(
351-
Initialization *init, ResultPlanPtr &&subPlan,
361+
Initialization *init, CanType substType,
362+
ResultPlanPtr &&subPlan,
352363
std::unique_ptr<TemporaryInitialization> &&temporary)
353-
: init(init), subPlan(std::move(subPlan)),
364+
: init(init), substType(substType), subPlan(std::move(subPlan)),
354365
temporary(std::move(temporary)) {}
355366

356367
RValue finish(SILGenFunction &SGF, SILLocation loc,
@@ -362,10 +373,15 @@ class InitValueFromTemporaryResultPlan final : public ResultPlan {
362373
(void)subResult;
363374

364375
ManagedValue value = temporary->getManagedAddress();
365-
init->copyOrInitValueInto(SGF, loc, value, /*init*/ true);
366-
init->finishInitialization(SGF);
367376

368-
return RValue::forInContext();
377+
if (init) {
378+
init->copyOrInitValueInto(SGF, loc, value, /*init*/ true);
379+
init->finishInitialization(SGF);
380+
381+
return RValue::forInContext();
382+
}
383+
384+
return RValue(SGF, loc, substType, value);
369385
}
370386

371387
void
@@ -414,28 +430,30 @@ class PackExpansionResultPlan : public ResultPlan {
414430
public:
415431
PackExpansionResultPlan(ResultPlanBuilder &builder,
416432
SILValue packAddr,
417-
MutableArrayRef<InitializationPtr> inits,
433+
Optional<MutableArrayRef<InitializationPtr>> inits,
418434
AbstractionPattern origExpansionType,
419435
CanTupleEltTypeArrayRef substEltTypes)
420436
: PackAddr(packAddr) {
437+
assert(!inits || inits->size() == substEltTypes.size());
438+
421439
auto packTy = packAddr->getType().castTo<SILPackType>();
422440
auto formalPackType =
423441
CanPackType::get(packTy->getASTContext(), substEltTypes);
424442
auto origPatternType = origExpansionType.getPackExpansionPatternType();
425443

426-
ComponentPlans.reserve(inits.size());
427-
for (auto i : indices(inits)) {
428-
auto &init = inits[i];
444+
ComponentPlans.reserve(substEltTypes.size());
445+
for (auto i : indices(substEltTypes)) {
446+
Initialization *init = inits ? (*inits)[i].get() : nullptr;
429447
CanType substEltType = substEltTypes[i];
430448

431449
if (isa<PackExpansionType>(substEltType)) {
432450
ComponentPlans.emplace_back(
433451
builder.buildPackExpansionIntoPack(packAddr, formalPackType, i,
434-
init.get(), origPatternType));
452+
init, origPatternType));
435453
} else {
436454
ComponentPlans.emplace_back(
437455
builder.buildScalarIntoPack(packAddr, formalPackType, i,
438-
init.get(), origPatternType));
456+
init, origPatternType));
439457
}
440458
}
441459
}
@@ -451,6 +469,16 @@ class PackExpansionResultPlan : public ResultPlan {
451469
return RValue::forInContext();
452470
}
453471

472+
void finishAndAddTo(SILGenFunction &SGF, SILLocation loc,
473+
ArrayRef<ManagedValue> &directResults,
474+
SILValue bridgedForeignError,
475+
RValue &result) override {
476+
for (auto &componentPlan : ComponentPlans) {
477+
componentPlan->finishAndAddTo(SGF, loc, directResults,
478+
bridgedForeignError, result);
479+
}
480+
}
481+
454482
void gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
455483
SmallVectorImpl<SILValue> &outList) const override {
456484
outList.push_back(PackAddr);
@@ -557,19 +585,27 @@ class PackTransformResultPlan final : public ResultPlan {
557585
/// components.
558586
class TupleRValueResultPlan final : public ResultPlan {
559587
CanTupleType substType;
560-
SmallVector<ResultPlanPtr, 4> eltPlans;
588+
589+
SmallVector<ResultPlanPtr, 4> origEltPlans;
561590

562591
public:
563592
TupleRValueResultPlan(ResultPlanBuilder &builder, AbstractionPattern origType,
564593
CanTupleType substType)
565594
: substType(substType) {
566595
// Create plans for all the elements.
567-
eltPlans.reserve(substType->getNumElements());
568-
for (auto i : indices(substType->getElementTypes())) {
569-
AbstractionPattern origEltType = origType.getTupleElementType(i);
570-
CanType substEltType = substType.getElementType(i);
571-
eltPlans.push_back(builder.build(nullptr, origEltType, substEltType));
572-
}
596+
origEltPlans.reserve(substType->getNumElements());
597+
origType.forEachTupleElement(substType,
598+
[&](TupleElementGenerator &origElt) {
599+
AbstractionPattern origEltType = origElt.getOrigType();
600+
auto substEltTypes = origElt.getSubstTypes();
601+
if (!origElt.isOrigPackExpansion()) {
602+
origEltPlans.push_back(
603+
builder.build(nullptr, origEltType, substEltTypes[0]));
604+
} else {
605+
origEltPlans.push_back(
606+
builder.buildForPackExpansion(None, origEltType, substEltTypes));
607+
}
608+
});
573609
}
574610

575611
RValue finish(SILGenFunction &SGF, SILLocation loc,
@@ -578,10 +614,9 @@ class TupleRValueResultPlan final : public ResultPlan {
578614
RValue tupleRV(substType);
579615

580616
// Finish all the component tuples.
581-
for (auto &plan : eltPlans) {
582-
RValue eltRV =
583-
plan->finish(SGF, loc, directResults, bridgedForeignError);
584-
tupleRV.addElement(std::move(eltRV));
617+
for (auto &plan : origEltPlans) {
618+
plan->finishAndAddTo(SGF, loc, directResults, bridgedForeignError,
619+
tupleRV);
585620
}
586621

587622
return tupleRV;
@@ -590,8 +625,8 @@ class TupleRValueResultPlan final : public ResultPlan {
590625
void
591626
gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
592627
SmallVectorImpl<SILValue> &outList) const override {
593-
for (const auto &eltPlan : eltPlans) {
594-
eltPlan->gatherIndirectResultAddrs(SGF, loc, outList);
628+
for (const auto &plan : origEltPlans) {
629+
plan->gatherIndirectResultAddrs(SGF, loc, outList);
595630
}
596631
}
597632
};
@@ -1143,10 +1178,10 @@ ResultPlanPtr ResultPlanBuilder::buildForScalar(Initialization *init,
11431178
}
11441179

11451180
ResultPlanPtr ResultPlanBuilder::
1146-
buildForPackExpansion(MutableArrayRef<InitializationPtr> inits,
1181+
buildForPackExpansion(Optional<MutableArrayRef<InitializationPtr>> inits,
11471182
AbstractionPattern origExpansionType,
11481183
CanTupleEltTypeArrayRef substTypes) {
1149-
assert(inits.size() == substTypes.size());
1184+
assert(!inits || inits->size() == substTypes.size());
11501185

11511186
// Pack expansions in the original result type always turn into
11521187
// a single @pack_out result.
@@ -1155,7 +1190,7 @@ ResultPlanPtr ResultPlanBuilder::
11551190
auto packTy =
11561191
result.getSILStorageType(SGF.SGM.M, calleeTypeInfo.substFnType,
11571192
SGF.getTypeExpansionContext());
1158-
assert(packTy.castTo<SILPackType>()->getNumElements() == inits.size());
1193+
assert(packTy.castTo<SILPackType>()->getNumElements() == substTypes.size());
11591194

11601195
// TODO: try to just forward a single pack
11611196

@@ -1236,7 +1271,6 @@ ResultPlanBuilder::buildScalarIntoPack(SILValue packAddr,
12361271
Initialization *init,
12371272
AbstractionPattern origType) {
12381273
assert(!origType.isPackExpansion());
1239-
assert(init);
12401274
auto substType = formalPackType.getElementType(componentIndex);
12411275
assert(!isa<PackExpansionType>(substType));
12421276

@@ -1245,7 +1279,8 @@ ResultPlanBuilder::buildScalarIntoPack(SILValue packAddr,
12451279
->getElementType(componentIndex);
12461280
SILResultInfo resultInfo(loweredEltType, ResultConvention::Indirect);
12471281

1248-
// Use the normal scalar emission path.
1282+
// Use the normal scalar emission path to gather an indirect result
1283+
// of that type.
12491284
auto plan = buildForScalar(init, origType, substType, resultInfo);
12501285

12511286
// Immediately gather the indirect result.
@@ -1265,38 +1300,44 @@ ResultPlanBuilder::buildScalarIntoPack(SILValue packAddr,
12651300
ResultPlanPtr ResultPlanBuilder::buildForTuple(Initialization *init,
12661301
AbstractionPattern origType,
12671302
CanTupleType substType) {
1268-
// If we don't have an initialization for the tuple, just build the
1269-
// individual components.
1270-
if (!init) {
1271-
return ResultPlanPtr(new TupleRValueResultPlan(*this, origType, substType));
1272-
}
1273-
1274-
// Okay, we have an initialization for the tuple that we need to emit into.
1275-
1276-
// If we can just split the initialization, do so.
1277-
if (init->canSplitIntoTupleElements()) {
1303+
// If we have an initialization, and we can split it, do so.
1304+
if (init && init->canSplitIntoTupleElements()) {
12781305
return ResultPlanPtr(
12791306
new TupleInitializationResultPlan(*this, init, origType, substType));
12801307
}
12811308

1282-
// Otherwise, we're going to have to call copyOrInitValueInto, which only
1283-
// takes a single value.
1284-
1285-
// If the tuple is address-only, we'll get much better code if we
1286-
// emit into a single buffer.
1309+
// Otherwise, if the tuple contains a pack expansion, we'll need to
1310+
// initialize a single buffer one way or another: either we're giving
1311+
// this to RValue (which wants a single value for tuples with pack
1312+
// expansions) or we'll have to call copyOrInitValueInto on init
1313+
// (which expects a single value). Create a temporary, build into
1314+
// that, and then call the initialization.
1315+
//
1316+
// We also use this path when we have an init and the type is
1317+
// address-only, because we'll need to call copyOrInitValueInto and
1318+
// we'll get better code by building that up indirectly. But we don't
1319+
// do that if we're not using lowered addresses because we prefer to
1320+
// build tuples with scalar operations.
12871321
auto &substTL = SGF.getTypeLowering(substType);
1322+
assert(substTL.isAddressOnly() || !substType.containsPackExpansionType());
12881323
if (substTL.isAddressOnly() &&
12891324
(substType.containsPackExpansionType() ||
1290-
SGF.F.getConventions().useLoweredAddresses())) {
1325+
(init != nullptr && SGF.F.getConventions().useLoweredAddresses()))) {
12911326
// Create a temporary.
12921327
auto temporary = SGF.emitTemporary(loc, substTL);
12931328

12941329
// Build a sub-plan to emit into the temporary.
12951330
auto subplan = buildForTuple(temporary.get(), origType, substType);
12961331

1297-
// Make a plan to initialize into that.
1332+
// Make a plan to produce the final result from that.
12981333
return ResultPlanPtr(new InitValueFromTemporaryResultPlan(
1299-
init, std::move(subplan), std::move(temporary)));
1334+
init, substType, std::move(subplan), std::move(temporary)));
1335+
}
1336+
1337+
// If we don't have an initialization, just build the individual
1338+
// components.
1339+
if (!init) {
1340+
return ResultPlanPtr(new TupleRValueResultPlan(*this, origType, substType));
13001341
}
13011342

13021343
// Build a sub-plan that doesn't know about the initialization.

lib/SILGen/ResultPlan.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ class ResultPlan {
4242
virtual RValue finish(SILGenFunction &SGF, SILLocation loc,
4343
ArrayRef<ManagedValue> &directResults,
4444
SILValue bridgedForeignError) = 0;
45+
46+
virtual void finishAndAddTo(SILGenFunction &SGF, SILLocation loc,
47+
ArrayRef<ManagedValue> &directResults,
48+
SILValue bridgedForeignError,
49+
RValue &result);
50+
4551
virtual ~ResultPlan() = default;
4652

4753
/// Defers the emission of the given breadcrumb until \p finish is invoked.
@@ -92,8 +98,8 @@ struct ResultPlanBuilder {
9298
ResultPlanPtr buildForTuple(Initialization *emitInto,
9399
AbstractionPattern origType,
94100
CanTupleType substType);
95-
ResultPlanPtr buildForPackExpansion(MutableArrayRef<InitializationPtr> inits,
96-
AbstractionPattern origPatternType,
101+
ResultPlanPtr buildForPackExpansion(Optional<MutableArrayRef<InitializationPtr>> inits,
102+
AbstractionPattern origExpansionType,
97103
CanTupleEltTypeArrayRef substTypes);
98104
ResultPlanPtr buildPackExpansionIntoPack(SILValue packAddr,
99105
CanPackType formalPackType,

test/SILGen/variadic-generic-tuples.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,3 +291,35 @@ struct EmptyContainer<each T> {}
291291
func f<each T>(_: repeat each T) {
292292
let _ = (repeat EmptyContainer<each T>())
293293
}
294+
295+
// rdar://107161241: handle receiving tuples that originally contained
296+
// packs that are not emitted into an initialization
297+
struct FancyTuple<each T> {
298+
var x: (repeat each T)
299+
300+
func makeTuple() -> (repeat each T) {
301+
return (repeat each x.element)
302+
}
303+
}
304+
305+
// CHECK: sil{{.*}} @$s4main23testFancyTuple_concreteyyF :
306+
// Create a pack to receive the results from makeTuple.
307+
// CHECK: [[PACK:%.*]] = alloc_pack $Pack{Int, String, Bool}
308+
// CHECK-NEXT: [[INT_ADDR:%.*]] = alloc_stack $Int
309+
// CHECK-NEXT: [[INT_INDEX:%.*]] = scalar_pack_index 0 of $Pack{Int, String, Bool}
310+
// CHECK-NEXT: pack_element_set [[INT_ADDR]] : $*Int into [[INT_INDEX]] of [[PACK]] : $*Pack{Int, String, Bool}
311+
// CHECK-NEXT: [[STRING_ADDR:%.*]] = alloc_stack $String
312+
// CHECK-NEXT: [[STRING_INDEX:%.*]] = scalar_pack_index 1 of $Pack{Int, String, Bool}
313+
// CHECK-NEXT: pack_element_set [[STRING_ADDR]] : $*String into [[STRING_INDEX]] of [[PACK]] : $*Pack{Int, String, Bool}
314+
// CHECK-NEXT: [[BOOL_ADDR:%.*]] = alloc_stack $Bool
315+
// CHECK-NEXT: [[BOOL_INDEX:%.*]] = scalar_pack_index 2 of $Pack{Int, String, Bool}
316+
// CHECK-NEXT: pack_element_set [[BOOL_ADDR]] : $*Bool into [[BOOL_INDEX]] of [[PACK]] : $*Pack{Int, String, Bool}
317+
// CHECK: [[FN:%.*]] = function_ref @$s4main10FancyTupleV04makeC0xxQp_tyF
318+
// CHECK-NEXT: apply [[FN]]<Pack{Int, String, Bool}>([[PACK]], {{.*}})
319+
func testFancyTuple_concrete() {
320+
FancyTuple<Int, String, Bool>(x: (1, "hi", false)).makeTuple()
321+
}
322+
323+
func testFancyTuple_pack<each T>(values: repeat each T) {
324+
FancyTuple<Int, String, repeat each T, Bool>(x: (1, "hi", repeat each values, false)).makeTuple()
325+
}

0 commit comments

Comments
 (0)