Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 13 additions & 10 deletions lib/SIL/IR/AbstractionPattern.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1373,12 +1373,12 @@ static void printGenerics(raw_ostream &out, const AbstractionPattern &pattern) {
// It'd be really nice if we could get these interleaved with the types.
if (auto subs = pattern.getGenericSubstitutions()) {
out << "@<";
bool first = false;
bool first = true;
for (auto sub : subs.getReplacementTypes()) {
if (!first) {
out << ",";
} else {
first = true;
first = false;
}
out << sub;
}
Expand Down Expand Up @@ -1961,8 +1961,11 @@ class SubstFunctionTypePatternVisitor
: CanType(CanMetatypeType::get(substInstance));
}

CanType handleGenericNominalType(CanType orig, CanType subst,
CanGenericSignature origSig) {
CanType handleGenericNominalType(AbstractionPattern origPattern, CanType subst) {
CanType orig = origPattern.getType();
CanGenericSignature origSig = origPattern.getGenericSignatureOrNull();
auto origPatternSubs = origPattern.getGenericSubstitutions();

// If there are no loose type parameters in the pattern here, we don't need
// to do a recursive visit at all.
if (!orig->hasTypeParameter()
Expand Down Expand Up @@ -2007,6 +2010,7 @@ class SubstFunctionTypePatternVisitor
if (differentOrigClass) {
orig = subst;
origSig = TC.getCurGenericSignature();
origPatternSubs = SubstitutionMap();
assert((!subst->hasTypeParameter() || origSig) &&
"lowering mismatched interface types in a context without "
"a generic signature");
Expand All @@ -2028,7 +2032,8 @@ class SubstFunctionTypePatternVisitor
->getCanonicalType();

replacementTypes[gp->getCanonicalType()->castTo<SubstitutableType>()]
= visit(substParamTy, AbstractionPattern(origSig, origParamTy));
= visit(substParamTy,
AbstractionPattern(origPatternSubs, origSig, origParamTy));
}

auto newSubMap = SubstitutionMap::get(nomGenericSig,
Expand All @@ -2048,8 +2053,7 @@ class SubstFunctionTypePatternVisitor
// If the type is generic (because it's a nested type in a generic context),
// process the generic type bindings.
if (!isa<ProtocolDecl>(nomDecl) && nomDecl->isGenericContext()) {
return handleGenericNominalType(pattern.getType(), nom,
pattern.getGenericSignatureOrNull());
return handleGenericNominalType(pattern, nom);
}

// Otherwise, there are no structural type parameters to visit.
Expand All @@ -2058,8 +2062,7 @@ class SubstFunctionTypePatternVisitor

CanType visitBoundGenericType(CanBoundGenericType bgt,
AbstractionPattern pattern) {
return handleGenericNominalType(pattern.getType(), bgt,
pattern.getGenericSignatureOrNull());
return handleGenericNominalType(pattern, bgt);
}

CanType visitPackType(CanPackType pack, AbstractionPattern pattern) {
Expand All @@ -2085,7 +2088,7 @@ class SubstFunctionTypePatternVisitor
// the pack substitution for that parameter recorded in the pattern.

// Remember that we're within an expansion.
// FIXME: when we introduce PackReferenceType we'll need to be clear
// FIXME: when we introduce PackElementType we'll need to be clear
// about which pack expansions to treat this way.
llvm::SaveAndRestore<bool> scope(WithinExpansion, true);

Expand Down
4 changes: 4 additions & 0 deletions lib/SIL/IR/SILFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,10 @@ void SILFunction::init(
IsExactSelfClass_t isExactSelfClass, IsDistributed_t isDistributed,
IsRuntimeAccessible_t isRuntimeAccessible) {
setName(Name);

assert(!LoweredType->hasTypeParameter() &&
"function type has open type parameters");

this->LoweredType = LoweredType;
this->GenericEnv = genericEnv;
this->SpecializationInfo = nullptr;
Expand Down
9 changes: 9 additions & 0 deletions lib/SILGen/Initialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -491,6 +491,15 @@ class BlackHoleInitialization : public Initialization {
return buf;
}

bool canPerformPackExpansionInitialization() const override {
return true;
}

void performPackExpansionInitialization(SILGenFunction &SGF,
SILLocation loc,
SILValue indexWithinComponent,
llvm::function_ref<void(Initialization *into)> fn) override;

void copyOrInitValueInto(SILGenFunction &SGF, SILLocation loc,
ManagedValue value, bool isInit) override;

Expand Down
135 changes: 88 additions & 47 deletions lib/SILGen/ResultPlan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ using namespace Lowering;
// Result Plans
//===----------------------------------------------------------------------===//

void ResultPlan::finishAndAddTo(SILGenFunction &SGF, SILLocation loc,
ArrayRef<ManagedValue> &directResults,
SILValue bridgedForeignError,
RValue &result) {
auto rvalue = finish(SGF, loc, directResults, bridgedForeignError);
assert(!rvalue.isInContext());
result.addElement(std::move(rvalue));
}

namespace {

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

public:
InitValueFromTemporaryResultPlan(
Initialization *init, ResultPlanPtr &&subPlan,
Initialization *init, CanType substType,
ResultPlanPtr &&subPlan,
std::unique_ptr<TemporaryInitialization> &&temporary)
: init(init), subPlan(std::move(subPlan)),
: init(init), substType(substType), subPlan(std::move(subPlan)),
temporary(std::move(temporary)) {}

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

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

return RValue::forInContext();
if (init) {
init->copyOrInitValueInto(SGF, loc, value, /*init*/ true);
init->finishInitialization(SGF);

return RValue::forInContext();
}

return RValue(SGF, loc, substType, value);
}

void
Expand Down Expand Up @@ -414,28 +430,30 @@ class PackExpansionResultPlan : public ResultPlan {
public:
PackExpansionResultPlan(ResultPlanBuilder &builder,
SILValue packAddr,
MutableArrayRef<InitializationPtr> inits,
Optional<MutableArrayRef<InitializationPtr>> inits,
AbstractionPattern origExpansionType,
CanTupleEltTypeArrayRef substEltTypes)
: PackAddr(packAddr) {
assert(!inits || inits->size() == substEltTypes.size());

auto packTy = packAddr->getType().castTo<SILPackType>();
auto formalPackType =
CanPackType::get(packTy->getASTContext(), substEltTypes);
auto origPatternType = origExpansionType.getPackExpansionPatternType();

ComponentPlans.reserve(inits.size());
for (auto i : indices(inits)) {
auto &init = inits[i];
ComponentPlans.reserve(substEltTypes.size());
for (auto i : indices(substEltTypes)) {
Initialization *init = inits ? (*inits)[i].get() : nullptr;
CanType substEltType = substEltTypes[i];

if (isa<PackExpansionType>(substEltType)) {
ComponentPlans.emplace_back(
builder.buildPackExpansionIntoPack(packAddr, formalPackType, i,
init.get(), origPatternType));
init, origPatternType));
} else {
ComponentPlans.emplace_back(
builder.buildScalarIntoPack(packAddr, formalPackType, i,
init.get(), origPatternType));
init, origPatternType));
}
}
}
Expand All @@ -451,6 +469,16 @@ class PackExpansionResultPlan : public ResultPlan {
return RValue::forInContext();
}

void finishAndAddTo(SILGenFunction &SGF, SILLocation loc,
ArrayRef<ManagedValue> &directResults,
SILValue bridgedForeignError,
RValue &result) override {
for (auto &componentPlan : ComponentPlans) {
componentPlan->finishAndAddTo(SGF, loc, directResults,
bridgedForeignError, result);
}
}

void gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
SmallVectorImpl<SILValue> &outList) const override {
outList.push_back(PackAddr);
Expand Down Expand Up @@ -557,19 +585,27 @@ class PackTransformResultPlan final : public ResultPlan {
/// components.
class TupleRValueResultPlan final : public ResultPlan {
CanTupleType substType;
SmallVector<ResultPlanPtr, 4> eltPlans;

SmallVector<ResultPlanPtr, 4> origEltPlans;

public:
TupleRValueResultPlan(ResultPlanBuilder &builder, AbstractionPattern origType,
CanTupleType substType)
: substType(substType) {
// Create plans for all the elements.
eltPlans.reserve(substType->getNumElements());
for (auto i : indices(substType->getElementTypes())) {
AbstractionPattern origEltType = origType.getTupleElementType(i);
CanType substEltType = substType.getElementType(i);
eltPlans.push_back(builder.build(nullptr, origEltType, substEltType));
}
origEltPlans.reserve(substType->getNumElements());
origType.forEachTupleElement(substType,
[&](TupleElementGenerator &origElt) {
AbstractionPattern origEltType = origElt.getOrigType();
auto substEltTypes = origElt.getSubstTypes();
if (!origElt.isOrigPackExpansion()) {
origEltPlans.push_back(
builder.build(nullptr, origEltType, substEltTypes[0]));
} else {
origEltPlans.push_back(
builder.buildForPackExpansion(None, origEltType, substEltTypes));
}
});
}

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

// Finish all the component tuples.
for (auto &plan : eltPlans) {
RValue eltRV =
plan->finish(SGF, loc, directResults, bridgedForeignError);
tupleRV.addElement(std::move(eltRV));
for (auto &plan : origEltPlans) {
plan->finishAndAddTo(SGF, loc, directResults, bridgedForeignError,
tupleRV);
}

return tupleRV;
Expand All @@ -590,8 +625,8 @@ class TupleRValueResultPlan final : public ResultPlan {
void
gatherIndirectResultAddrs(SILGenFunction &SGF, SILLocation loc,
SmallVectorImpl<SILValue> &outList) const override {
for (const auto &eltPlan : eltPlans) {
eltPlan->gatherIndirectResultAddrs(SGF, loc, outList);
for (const auto &plan : origEltPlans) {
plan->gatherIndirectResultAddrs(SGF, loc, outList);
}
}
};
Expand Down Expand Up @@ -1143,10 +1178,10 @@ ResultPlanPtr ResultPlanBuilder::buildForScalar(Initialization *init,
}

ResultPlanPtr ResultPlanBuilder::
buildForPackExpansion(MutableArrayRef<InitializationPtr> inits,
buildForPackExpansion(Optional<MutableArrayRef<InitializationPtr>> inits,
AbstractionPattern origExpansionType,
CanTupleEltTypeArrayRef substTypes) {
assert(inits.size() == substTypes.size());
assert(!inits || inits->size() == substTypes.size());

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

// TODO: try to just forward a single pack

Expand Down Expand Up @@ -1236,7 +1271,6 @@ ResultPlanBuilder::buildScalarIntoPack(SILValue packAddr,
Initialization *init,
AbstractionPattern origType) {
assert(!origType.isPackExpansion());
assert(init);
auto substType = formalPackType.getElementType(componentIndex);
assert(!isa<PackExpansionType>(substType));

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

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

// Immediately gather the indirect result.
Expand All @@ -1265,38 +1300,44 @@ ResultPlanBuilder::buildScalarIntoPack(SILValue packAddr,
ResultPlanPtr ResultPlanBuilder::buildForTuple(Initialization *init,
AbstractionPattern origType,
CanTupleType substType) {
// If we don't have an initialization for the tuple, just build the
// individual components.
if (!init) {
return ResultPlanPtr(new TupleRValueResultPlan(*this, origType, substType));
}

// Okay, we have an initialization for the tuple that we need to emit into.

// If we can just split the initialization, do so.
if (init->canSplitIntoTupleElements()) {
// If we have an initialization, and we can split it, do so.
if (init && init->canSplitIntoTupleElements()) {
return ResultPlanPtr(
new TupleInitializationResultPlan(*this, init, origType, substType));
}

// Otherwise, we're going to have to call copyOrInitValueInto, which only
// takes a single value.

// If the tuple is address-only, we'll get much better code if we
// emit into a single buffer.
// Otherwise, if the tuple contains a pack expansion, we'll need to
// initialize a single buffer one way or another: either we're giving
// this to RValue (which wants a single value for tuples with pack
// expansions) or we'll have to call copyOrInitValueInto on init
// (which expects a single value). Create a temporary, build into
// that, and then call the initialization.
//
// We also use this path when we have an init and the type is
// address-only, because we'll need to call copyOrInitValueInto and
// we'll get better code by building that up indirectly. But we don't
// do that if we're not using lowered addresses because we prefer to
// build tuples with scalar operations.
auto &substTL = SGF.getTypeLowering(substType);
assert(substTL.isAddressOnly() || !substType.containsPackExpansionType());
if (substTL.isAddressOnly() &&
(substType.containsPackExpansionType() ||
SGF.F.getConventions().useLoweredAddresses())) {
(init != nullptr && SGF.F.getConventions().useLoweredAddresses()))) {
// Create a temporary.
auto temporary = SGF.emitTemporary(loc, substTL);

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

// Make a plan to initialize into that.
// Make a plan to produce the final result from that.
return ResultPlanPtr(new InitValueFromTemporaryResultPlan(
init, std::move(subplan), std::move(temporary)));
init, substType, std::move(subplan), std::move(temporary)));
}

// If we don't have an initialization, just build the individual
// components.
if (!init) {
return ResultPlanPtr(new TupleRValueResultPlan(*this, origType, substType));
}

// Build a sub-plan that doesn't know about the initialization.
Expand Down
10 changes: 8 additions & 2 deletions lib/SILGen/ResultPlan.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ class ResultPlan {
virtual RValue finish(SILGenFunction &SGF, SILLocation loc,
ArrayRef<ManagedValue> &directResults,
SILValue bridgedForeignError) = 0;

virtual void finishAndAddTo(SILGenFunction &SGF, SILLocation loc,
ArrayRef<ManagedValue> &directResults,
SILValue bridgedForeignError,
RValue &result);

virtual ~ResultPlan() = default;

/// Defers the emission of the given breadcrumb until \p finish is invoked.
Expand Down Expand Up @@ -92,8 +98,8 @@ struct ResultPlanBuilder {
ResultPlanPtr buildForTuple(Initialization *emitInto,
AbstractionPattern origType,
CanTupleType substType);
ResultPlanPtr buildForPackExpansion(MutableArrayRef<InitializationPtr> inits,
AbstractionPattern origPatternType,
ResultPlanPtr buildForPackExpansion(Optional<MutableArrayRef<InitializationPtr>> inits,
AbstractionPattern origExpansionType,
CanTupleEltTypeArrayRef substTypes);
ResultPlanPtr buildPackExpansionIntoPack(SILValue packAddr,
CanPackType formalPackType,
Expand Down
Loading