//===--- SILGenPack.cpp - Helper routines for lowering variadic packs -----===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "Initialization.h" #include "Scope.h" #include "SILGenFunction.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/GenericEnvironment.h" #include "swift/Basic/Assertions.h" using namespace swift; using namespace Lowering; namespace { /// Cleanup to deallocate a now-uninitialized pack. class DeallocPackCleanup : public Cleanup { SILValue Addr; public: DeallocPackCleanup(SILValue addr) : Addr(addr) {} void emit(SILGenFunction &SGF, CleanupLocation l, ForUnwind_t forUnwind) override { SGF.B.createDeallocPack(l, Addr); } void dump(SILGenFunction &) const override { #ifndef NDEBUG llvm::errs() << "DeallocPackCleanup\n" << "State: " << getState() << "\n" << "Addr: " << Addr << "\n"; #endif } }; /// Cleanup to destroy all the values in a pack. class DestroyPackCleanup : public Cleanup { SILValue Addr; CanPackType FormalPackType; unsigned BeginIndex, EndIndex; public: DestroyPackCleanup(SILValue addr, CanPackType formalPackType, unsigned beginIndex, unsigned endIndex) : Addr(addr), FormalPackType(formalPackType), BeginIndex(beginIndex), EndIndex(endIndex) {} void emit(SILGenFunction &SGF, CleanupLocation l, ForUnwind_t forUnwind) override { SGF.emitDestroyPack(l, Addr, FormalPackType, BeginIndex, EndIndex); } void dump(SILGenFunction &) const override { #ifndef NDEBUG llvm::errs() << "DestroyPackCleanup\n" << "State:" << getState() << "\n" << "Addr:" << Addr << "\n" << "FormalPackType:" << FormalPackType << "\n" << "BeginIndex:" << BeginIndex << "\n" << "EndIndex:" << EndIndex << "\n"; #endif } }; /// Cleanup to destroy the preceding values in a pack-expansion /// component of a pack. class PartialDestroyPackCleanup : public Cleanup { SILValue Addr; unsigned PackComponentIndex; /// NOTE: It is expected that LimitWithinComponent maybe an empty SILValue. SILValue LimitWithinComponent; CanPackType FormalPackType; public: PartialDestroyPackCleanup(SILValue addr, CanPackType formalPackType, unsigned packComponentIndex, SILValue limitWithinComponent) : Addr(addr), PackComponentIndex(packComponentIndex), LimitWithinComponent(limitWithinComponent), FormalPackType(formalPackType) {} void emit(SILGenFunction &SGF, CleanupLocation l, ForUnwind_t forUnwind) override { SGF.emitPartialDestroyPack(l, Addr, FormalPackType, PackComponentIndex, LimitWithinComponent); } void dump(SILGenFunction &) const override { #ifndef NDEBUG llvm::errs() << "PartialDestroyPackCleanup\n" << "State: " << getState() << "\n" << "Addr: " << Addr << "FormalPackType: " << FormalPackType << "\n" << "ComponentIndex: " << PackComponentIndex << "\n" << "LimitWithinComponent: "; if (LimitWithinComponent) llvm::errs() << LimitWithinComponent; else llvm::errs() << "None\n"; #endif } }; /// Cleanup to destroy the remaining values in a pack-expansion /// component of a pack. class PartialDestroyRemainingPackCleanup : public Cleanup { SILValue Addr; unsigned ComponentIndex; SILValue CurrentIndexWithinComponent; CanPackType FormalPackType; public: PartialDestroyRemainingPackCleanup(SILValue packAddr, CanPackType formalPackType, unsigned componentIndex, SILValue currentIndexWithinComponent) : Addr(packAddr), ComponentIndex(componentIndex), CurrentIndexWithinComponent(currentIndexWithinComponent), FormalPackType(formalPackType) {} void emit(SILGenFunction &SGF, CleanupLocation l, ForUnwind_t forUnwind) override { SGF.emitPartialDestroyRemainingPack(l, Addr, FormalPackType, ComponentIndex, CurrentIndexWithinComponent); } void dump(SILGenFunction &) const override { #ifndef NDEBUG llvm::errs() << "PartialDestroyRemainingPackCleanup\n" << "State: " << getState() << "\n" << "Addr: " << Addr << "FormalPackType: " << FormalPackType << "\n" << "ComponentIndex: " << ComponentIndex << "\n" << "CurrentIndexWithinComponent: " << CurrentIndexWithinComponent << "\n"; #endif } }; /// Cleanup to destroy the preceding values in a pack-expansion /// component of a tuple. class PartialDestroyTupleCleanup : public Cleanup { SILValue Addr; unsigned ComponentIndex; SILValue LimitWithinComponent; CanPackType InducedPackType; public: PartialDestroyTupleCleanup(SILValue tupleAddr, CanPackType inducedPackType, unsigned componentIndex, SILValue limitWithinComponent) : Addr(tupleAddr), ComponentIndex(componentIndex), LimitWithinComponent(limitWithinComponent), InducedPackType(inducedPackType) {} void emit(SILGenFunction &SGF, CleanupLocation l, ForUnwind_t forUnwind) override { SGF.emitPartialDestroyTuple(l, Addr, InducedPackType, ComponentIndex, LimitWithinComponent); } void dump(SILGenFunction &) const override { #ifndef NDEBUG llvm::errs() << "PartialDestroyTupleCleanup\n" << "State: " << getState() << "\n" << "Addr: " << Addr << "InducedPackType: " << InducedPackType << "\n" << "ComponentIndex: " << ComponentIndex << '\n' << "LimitWithinComponent: " << LimitWithinComponent << '\n'; #endif } }; /// Cleanup to destroy the remaining values in a pack-expansion /// component of a tuple. class PartialDestroyRemainingTupleCleanup : public Cleanup { SILValue Addr; unsigned ComponentIndex; SILValue CurrentIndexWithinComponent; CanPackType InducedPackType; public: PartialDestroyRemainingTupleCleanup(SILValue tupleAddr, CanPackType inducedPackType, unsigned componentIndex, SILValue currentIndexWithinComponent) : Addr(tupleAddr), ComponentIndex(componentIndex), CurrentIndexWithinComponent(currentIndexWithinComponent), InducedPackType(inducedPackType) {} void emit(SILGenFunction &SGF, CleanupLocation l, ForUnwind_t forUnwind) override { SGF.emitPartialDestroyRemainingTuple(l, Addr, InducedPackType, ComponentIndex, CurrentIndexWithinComponent); } void dump(SILGenFunction &) const override { #ifndef NDEBUG llvm::errs() << "PartialDestroyRemainingTupleCleanup\n" << "State: " << getState() << "\n" << "Addr: " << Addr << "InducedPackType: " << InducedPackType << "\n" << "ComponentIndex: " << ComponentIndex << "\n" << "CurrentIndexWithinComponent: " << CurrentIndexWithinComponent; #endif } }; /// Cleanup to destroy the remaining elements in a tuple following a /// particular value. class DestroyRemainingTupleElementsCleanup : public Cleanup { SILValue Addr; unsigned ComponentIndex; CanPackType InducedPackType; public: DestroyRemainingTupleElementsCleanup(SILValue tupleAddr, CanPackType inducedPackType, unsigned componentIndex) : Addr(tupleAddr), ComponentIndex(componentIndex), InducedPackType(inducedPackType) {} void emit(SILGenFunction &SGF, CleanupLocation l, ForUnwind_t forUnwind) override { SGF.emitDestroyRemainingTupleElements(l, Addr, InducedPackType, ComponentIndex); } void dump(SILGenFunction &) const override { #ifndef NDEBUG llvm::errs() << "DestroyRemainingTupleElementsCleanup\n" << "State: " << getState() << "\n" << "Addr: " << Addr << "InducedPackType: " << InducedPackType << "\n" << "ComponentIndex: " << ComponentIndex << "\n"; #endif } }; /// An ASTWalker to emit tuple values in `MaterializePackExpr` nodes. /// /// Materialized packs are emitted inside a pack expansion context before /// entering the dynamic pack loop so that the values are only evaluated /// once, rather than at each pack element iteration. struct MaterializePackEmitter : public ASTWalker { SILGenFunction &SGF; MaterializePackEmitter(SILGenFunction &SGF) : SGF(SGF) {} ASTWalker::PreWalkResult walkToExprPre(Expr *expr) override { using Action = ASTWalker::Action; // Don't walk into nested pack expansions. if (isa(expr)) return Action::SkipNode(expr); if (auto *packExpr = dyn_cast(expr)) { auto *fromExpr = packExpr->getFromExpr(); assert(fromExpr->getType()->is()); auto &lowering = SGF.getTypeLowering(fromExpr->getType()); auto loweredTy = lowering.getLoweredType(); auto tupleAddr = SGF.emitTemporaryAllocation(fromExpr, loweredTy); auto init = SGF.useBufferAsTemporary(tupleAddr, lowering); SGF.emitExprInto(fromExpr, init.get()); // Write the tuple value to a side table in the active pack expansion // to be projected later within the dynamic pack loop. auto *activeExpansion = SGF.getInnermostPackExpansion(); activeExpansion->MaterializedPacks[packExpr] = tupleAddr; } return Action::Continue(expr); } }; } // end anonymous namespace void SILGenFunction::prepareToEmitPackExpansionExpr(PackExpansionExpr *E) { MaterializePackEmitter tempPackEmission(*this); E->getPatternExpr()->walk(tempPackEmission); } CleanupHandle SILGenFunction::enterDeallocPackCleanup(SILValue temp) { assert(temp->getType().isAddress() && "dealloc must have an address type"); assert(temp->getType().is()); Cleanups.pushCleanup(temp); return Cleanups.getTopCleanup(); } CleanupHandle SILGenFunction::enterDestroyPackCleanup(SILValue addr, CanPackType formalPackType) { Cleanups.pushCleanup(addr, formalPackType, 0, formalPackType->getNumElements()); return Cleanups.getTopCleanup(); } CleanupHandle SILGenFunction::enterDestroyPrecedingPackComponentsCleanup(SILValue addr, CanPackType formalPackType, unsigned componentIndex) { Cleanups.pushCleanup(addr, formalPackType, 0, componentIndex); return Cleanups.getTopCleanup(); } CleanupHandle SILGenFunction::enterDestroyRemainingPackComponentsCleanup(SILValue addr, CanPackType formalPackType, unsigned componentIndex) { Cleanups.pushCleanup(addr, formalPackType, componentIndex, formalPackType->getNumElements()); return Cleanups.getTopCleanup(); } CleanupHandle SILGenFunction::enterPartialDestroyPackCleanup(SILValue addr, CanPackType formalPackType, unsigned packComponentIndex, SILValue limitWithinComponent) { Cleanups.pushCleanup(addr, formalPackType, packComponentIndex, limitWithinComponent); return Cleanups.getTopCleanup(); } CleanupHandle SILGenFunction::enterPartialDestroyRemainingPackCleanup(SILValue addr, CanPackType formalPackType, unsigned componentIndex, SILValue indexWithinComponent) { Cleanups.pushCleanup(addr, formalPackType, componentIndex, indexWithinComponent); return Cleanups.getTopCleanup(); } CleanupHandle SILGenFunction::enterPartialDestroyTupleCleanup(SILValue addr, CanPackType inducedPackType, unsigned componentIndex, SILValue limitWithinComponent) { Cleanups.pushCleanup(addr, inducedPackType, componentIndex, limitWithinComponent); return Cleanups.getTopCleanup(); } CleanupHandle SILGenFunction::enterPartialDestroyRemainingTupleCleanup(SILValue addr, CanPackType inducedPackType, unsigned componentIndex, SILValue indexWithinComponent) { Cleanups.pushCleanup(addr, inducedPackType, componentIndex, indexWithinComponent); return Cleanups.getTopCleanup(); } CleanupHandle SILGenFunction::enterDestroyRemainingTupleElementsCleanup(SILValue addr, CanPackType formalPackType, unsigned componentIndex) { Cleanups.pushCleanup(addr, formalPackType, componentIndex); return Cleanups.getTopCleanup(); } void SILGenFunction::emitDestroyPack(SILLocation loc, SILValue packAddr, CanPackType formalPackType, unsigned beginIndex, unsigned endIndex) { auto packTy = packAddr->getType().castTo(); assert(beginIndex <= endIndex); assert(endIndex <= packTy->getNumElements()); // Destroy each of the elements of the pack. for (auto componentIndex : range(beginIndex, endIndex)) { auto eltTy = packTy->getSILElementType(componentIndex); // We can skip this if the whole thing is trivial. auto &eltTL = getTypeLowering(eltTy); if (eltTL.isTrivial()) continue; // If it's an expansion component, emit a "partial"-destroy loop. if (auto expansion = eltTy.getAs()) { emitPartialDestroyPack(loc, packAddr, formalPackType, componentIndex, /*limit*/ nullptr); // If it's a scalar component, project and destroy it. } else { auto packIndex = B.createScalarPackIndex(loc, componentIndex, formalPackType); auto eltAddr = B.createPackElementGet(loc, packIndex, packAddr, eltTy); B.createDestroyAddr(loc, eltAddr); } } } ManagedValue SILGenFunction::emitManagedPackWithCleanup(SILValue addr, CanPackType formalPackType) { // If the pack type is trivial, we're done. if (getTypeLowering(addr->getType()).isTrivial()) return ManagedValue::forTrivialAddressRValue(addr); // If we weren't given a formal pack type, construct one induced from // the lowered pack type. auto packType = addr->getType().castTo(); if (!formalPackType) formalPackType = packType->getApproximateFormalPackType(); // Enter a cleanup for the pack. auto cleanup = enterDestroyPackCleanup(addr, formalPackType); return ManagedValue::forOwnedAddressRValue(addr, cleanup); } static bool isPatternInvariantToExpansion(CanType patternType, CanPackArchetypeType countArchetype) { return !patternType.findIf([&](CanType type) { if (auto archetype = dyn_cast(type)) { return archetype == countArchetype || archetype->getReducedShape() == countArchetype->getReducedShape(); } return false; }); } std::pair SILGenFunction::createOpenedElementValueEnvironment(SILType expansionTy) { SILType eltTy; auto env = createOpenedElementValueEnvironment({expansionTy}, {&eltTy}); return std::make_pair(env, eltTy); } GenericEnvironment * SILGenFunction::createOpenedElementValueEnvironment( ArrayRef expansionTys, ArrayRef eltTys) { return createOpenedElementValueEnvironment(expansionTys, eltTys, {}, {}); } GenericEnvironment * SILGenFunction::createOpenedElementValueEnvironment( ArrayRef expansionTys, ArrayRef eltTys, ArrayRef formalExpansionTypes, ArrayRef formalEltTypes) { // The element-types output arrays should be the same size as their // corresponding expansion-types input arrays. assert(expansionTys.size() == eltTys.size()); assert(formalExpansionTypes.size() == formalEltTypes.size()); assert(!expansionTys.empty() || !formalExpansionTypes.empty()); auto countArchetype = cast( (expansionTys.empty() ? cast(formalExpansionTypes[0]) : expansionTys[0].castTo()).getCountType()); GenericEnvironment *env = nullptr; auto processExpansion = [&](CanPackExpansionType expansion) -> CanType { assert(countArchetype->getReducedShape() == cast(expansion.getCountType())->getReducedShape() && "expansions are over packs with different shapes"); // The element type is the pattern type, if that's invariant to // expansion, or else the expansion mapping of that in the // opened-element environment. auto patternType = expansion.getPatternType(); if (isPatternInvariantToExpansion(patternType, countArchetype)) return patternType; // Lazily create the opened-element environment if we find a // pattern type that's not invariant to expansion. if (!env) { auto context = OpenedElementContext:: createForContextualExpansion(SGM.getASTContext(), expansion); env = context.environment; } return env->mapContextualPackTypeIntoElementContext(patternType); }; for (auto i : indices(expansionTys)) { auto exp = expansionTys[i].castTo(); auto loweredEltTy = processExpansion(exp); *eltTys[i] = SILType::getPrimitiveAddressType(loweredEltTy); } for (auto i : indices(formalExpansionTypes)) { auto exp = cast(formalExpansionTypes[i]); auto eltType = processExpansion(exp); *formalEltTypes[i] = eltType; } return env; } void SILGenFunction::emitPartialDestroyPack(SILLocation loc, SILValue packAddr, CanPackType formalPackType, unsigned componentIndex, SILValue limitWithinComponent) { auto packTy = packAddr->getType().castTo(); auto result = createOpenedElementValueEnvironment( packTy->getSILElementType(componentIndex)); auto elementEnv = result.first; auto elementTy = result.second; emitDynamicPackLoop(loc, formalPackType, componentIndex, /*startAfter*/ SILValue(), limitWithinComponent, elementEnv, /*reverse*/ true, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { auto eltAddr = B.createPackElementGet(loc, packIndex, packAddr, elementTy); B.createDestroyAddr(loc, eltAddr); }); } void SILGenFunction::emitPartialDestroyRemainingPack(SILLocation loc, SILValue packAddr, CanPackType formalPackType, unsigned componentIndex, SILValue currentIndexWithinComponent) { auto result = createOpenedElementValueEnvironment( packAddr->getType().getPackElementType(componentIndex)); auto elementEnv = result.first; auto elementTy = result.second; emitDynamicPackLoop(loc, formalPackType, componentIndex, /*startAfter*/ currentIndexWithinComponent, /*limit*/ SILValue(), elementEnv, /*reverse*/ false, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { auto eltAddr = B.createPackElementGet(loc, packIndex, packAddr, elementTy); B.createDestroyAddr(loc, eltAddr); }); } void SILGenFunction::emitPartialDestroyTuple(SILLocation loc, SILValue tupleAddr, CanPackType inducedPackType, unsigned componentIndex, SILValue limitWithinComponent) { auto result = createOpenedElementValueEnvironment( tupleAddr->getType().getTupleElementType(componentIndex)); auto elementEnv = result.first; auto elementTy = result.second; emitDynamicPackLoop(loc, inducedPackType, componentIndex, /*startAfter*/ SILValue(), limitWithinComponent, elementEnv, /*reverse*/ true, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { auto eltAddr = B.createTuplePackElementAddr(loc, packIndex, tupleAddr, elementTy); B.createDestroyAddr(loc, eltAddr); }); } void SILGenFunction::emitPartialDestroyRemainingTuple(SILLocation loc, SILValue tupleAddr, CanPackType inducedPackType, unsigned componentIndex, SILValue currentIndexWithinComponent) { auto result = createOpenedElementValueEnvironment( tupleAddr->getType().getTupleElementType(componentIndex)); auto elementEnv = result.first; auto elementTy = result.second; emitDynamicPackLoop(loc, inducedPackType, componentIndex, /*startAfter*/ currentIndexWithinComponent, /*limit*/ SILValue(), elementEnv, /*reverse*/ false, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { auto eltAddr = B.createTuplePackElementAddr(loc, packIndex, tupleAddr, elementTy); B.createDestroyAddr(loc, eltAddr); }); } void SILGenFunction::emitDestroyRemainingTupleElements( SILLocation loc, SILValue tupleAddr, CanPackType inducedPackType, unsigned firstComponentIndex) { auto tupleTy = tupleAddr->getType().castTo(); bool containsExpansions = tupleTy->containsPackExpansionType(); assert(!containsExpansions || inducedPackType); // Destroy each of the elements of the pack. for (auto componentIndex : range(firstComponentIndex, tupleTy->getNumElements())) { auto eltTy = tupleAddr->getType().getTupleElementType(componentIndex); // We can skip this if the whole thing is trivial. auto &eltTL = getTypeLowering(eltTy); if (eltTL.isTrivial()) continue; // If it's an expansion component, emit a "partial"-destroy loop. if (auto expansion = eltTy.getAs()) { emitPartialDestroyRemainingTuple(loc, tupleAddr, inducedPackType, componentIndex, /*limit*/ nullptr); // If it's a scalar component, project and destroy it. } else { SILValue eltAddr; if (containsExpansions) { auto packIndex = B.createScalarPackIndex(loc, componentIndex, inducedPackType); eltAddr = B.createTuplePackElementAddr(loc, packIndex, tupleAddr, eltTy); } else { eltAddr = B.createTupleElementAddr(loc, tupleAddr, componentIndex, eltTy); } B.createDestroyAddr(loc, eltAddr); } } } void SILGenFunction::copyPackElementsToTuple(SILLocation loc, SILValue tupleAddr, SILValue pack, CanPackType formalPackType) { auto pair = createOpenedElementValueEnvironment( tupleAddr->getType().getTupleElementType(/*componentIndex=*/0)); auto elementEnv = pair.first; auto elementTy = pair.second; emitDynamicPackLoop( loc, formalPackType, /*componentIndex=*/0, elementEnv, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { auto packEltAddr = B.createPackElementGet( loc, packIndex, pack, elementTy); auto tupleEltAddr = B.createTuplePackElementAddr( loc, packIndex, tupleAddr, elementTy); B.createCopyAddr(loc, packEltAddr, tupleEltAddr, IsNotTake, IsInitialization); }); } void SILGenFunction::projectTupleElementsToPack(SILLocation loc, SILValue tupleAddr, SILValue pack, CanPackType formalPackType) { auto pair = createOpenedElementValueEnvironment( tupleAddr->getType().getTupleElementType(/*componentIndex=*/0)); auto elementEnv = pair.first; auto elementTy = pair.second; emitDynamicPackLoop( loc, formalPackType, /*componentIndex=*/0, elementEnv, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue packIndex) { auto tupleEltAddr = B.createTuplePackElementAddr( loc, packIndex, tupleAddr, elementTy); B.createPackElementSet(loc, tupleEltAddr, packIndex, pack); }); } void SILGenFunction::emitDynamicPackLoop( SILLocation loc, CanPackType formalPackType, unsigned componentIndex, GenericEnvironment *openedElementEnv, llvm::function_ref emitBody, SILBasicBlock *loopLatch) { return emitDynamicPackLoop(loc, formalPackType, componentIndex, /*startAfter*/ SILValue(), /*limit*/ SILValue(), openedElementEnv, /*reverse*/ false, emitBody, loopLatch); } void SILGenFunction::emitDynamicPackLoop( SILLocation loc, CanPackType formalPackType, unsigned componentIndex, SILValue startingAfterIndexInComponent, SILValue limitWithinComponent, GenericEnvironment *openedElementEnv, bool reverse, llvm::function_ref emitBody, SILBasicBlock *loopLatch) { assert(isa(formalPackType.getElementType(componentIndex))); assert((!startingAfterIndexInComponent || !reverse) && "cannot reverse with a starting index"); ASTContext &ctx = SGM.getASTContext(); // Save and restore the innermost pack expansion. ActivePackExpansion activeExpansionRecord = { openedElementEnv }; llvm::SaveAndRestore packExpansionScope(InnermostPackExpansion, &activeExpansionRecord); if (auto *expansion = loc.getAsASTNode()) prepareToEmitPackExpansionExpr(expansion); auto wordTy = SILType::getBuiltinWordType(ctx); auto boolTy = SILType::getBuiltinIntegerType(1, ctx); SILValue zero; if (!startingAfterIndexInComponent) { zero = B.createIntegerLiteral(loc, wordTy, 0); } auto one = B.createIntegerLiteral(loc, wordTy, 1); // The formal type of the component of the pack that we're iterating over. // If this isn't the entire pack, we'll dynamically index into just the // expansion component and then compose that into an index into the larger // pack. CanPackType formalDynamicPackType = formalPackType; bool needsSlicing = formalPackType->getNumElements() != 1; if (needsSlicing) { formalDynamicPackType = CanPackType::get(ctx, formalPackType.getElementType(componentIndex)); } // If the caller didn't give us a limit, use the full length of the // pack expansion. if (!limitWithinComponent) { limitWithinComponent = B.createPackLength(loc, formalDynamicPackType); } // The initial index value: the limit if iterating in reverse, // otherwise the start-after index + 1 if we have one, otherwise 0. SILValue startingIndex; if (reverse) { startingIndex = limitWithinComponent; } else if (startingAfterIndexInComponent) { startingIndex = B.createBuiltinBinaryFunction(loc, "add", wordTy, wordTy, { startingAfterIndexInComponent, one }); } else { startingIndex = zero; } // Branch to the loop condition block, passing the initial index value. auto condBB = createBasicBlock(); B.createBranch(loc, condBB, { startingIndex }); // Condition block: B.emitBlock(condBB); auto incomingIndex = condBB->createPhiArgument(wordTy, OwnershipKind::None); // Branch to the end block if the incoming index value is equal to the // end index (the limit if forward, 0 if reverse). auto atEnd = B.createBuiltinBinaryFunction(loc, "cmp_eq", wordTy, boolTy, { incomingIndex, reverse ? zero : limitWithinComponent }); auto bodyBB = createBasicBlock(); auto endBB = createBasicBlockAfter(bodyBB); B.createCondBranch(loc, atEnd, endBB, bodyBB); // Body block: B.emitBlock(bodyBB); // The index to use in this iteration (the incoming index if forward, // the incoming index - 1 if reverse) SILValue curIndex = incomingIndex; if (reverse) { assert(!loopLatch && "Only forward iteration supported with loop latch"); curIndex = B.createBuiltinBinaryFunction(loc, "sub", wordTy, wordTy, { incomingIndex, one }); } // Construct the dynamic pack index into the component. SILValue packExpansionIndex = B.createDynamicPackIndex(loc, curIndex, formalDynamicPackType); getInnermostPackExpansion()->ExpansionIndex = packExpansionIndex; // If there's an opened element environment, open it here. if (openedElementEnv) { B.createOpenPackElement(loc, packExpansionIndex, openedElementEnv); } // If there are multiple pack components in the overall pack, construct // the overall pack index. SILValue packIndex = packExpansionIndex; if (needsSlicing) { packIndex = B.createPackPackIndex(loc, componentIndex, packIndex, formalPackType); } // Emit the loop body in a scope as a convenience, since it's necessary // to avoid dominance problems anyway. { FullExpr scope(Cleanups, CleanupLocation(loc)); emitBody(curIndex, packExpansionIndex, packIndex); if (loopLatch && B.hasValidInsertionPoint()) { B.createBranch(loc, loopLatch); } } if (loopLatch) { B.emitBlock(loopLatch); } // The index to pass to the loop condition block (the current index + 1 // if forward, the current index if reverse) SILValue outgoingIndex = curIndex; if (!reverse) { outgoingIndex = B.createBuiltinBinaryFunction(loc, "add", wordTy, wordTy, { curIndex, one }); } B.createBranch(loc, condBB, {outgoingIndex}); // End block: B.emitBlock(endBB); } /// Given that we're within a dynamic pack loop with the same expansion /// shape as a pack expansion component of the given formal pack type, /// produce a pack index for the current component within the formal pack. /// /// Note that the *outer* pack index for the dynamic pack loop /// isn't necessarily correct for the given pack, just the *expansion* /// pack index. static SILValue emitPackPackIndexForActiveExpansion(SILGenFunction &SGF, SILLocation loc, CanPackType formalPackType, unsigned componentIndex) { auto activeExpansion = SGF.getInnermostPackExpansion(); auto packIndex = activeExpansion->ExpansionIndex; if (formalPackType->getNumElements() != 1) { packIndex = SGF.B.createPackPackIndex(loc, componentIndex, packIndex, formalPackType); } return packIndex; } void InPlacePackExpansionInitialization:: performPackExpansionInitialization(SILGenFunction &SGF, SILLocation loc, SILValue indexWithinComponent, llvm::function_ref fn) { // Enter a cleanup to destroy elements of the expansion up to the // current index. We only need to do this if the elements are // non-trivial, which we've already checked in order to decide whether // to set up the dormant full-expansion cleanup. So we can just check // that instead of looking at type properties again. bool needCleanups = ExpansionCleanup.isValid(); CleanupHandle packCleanup = CleanupHandle::invalid(); if (needCleanups) packCleanup = enterPartialDestroyCleanup(SGF, indexWithinComponent); // The pack index from the active pack expansion is just into the // expansion component; wrap it as necessary to index into the larger // pack/tuple element list. auto packIndex = emitPackPackIndexForActiveExpansion(SGF, loc, FormalPackType, ComponentIndex); // Translate the pattern type into the environment of the innermost // pack expansion. auto loweredPatternTy = getLoweredExpansionType().getPatternType(); if (auto env = SGF.getInnermostPackExpansion()->OpenedElementEnv) { // This AST-level transformation is fine on lowered types because // we're just replacing pack archetypes with element archetypes. loweredPatternTy = env->mapContextualPackTypeIntoElementContext(loweredPatternTy); } auto eltAddrTy = SILType::getPrimitiveAddressType(loweredPatternTy); // Project the element address. auto eltAddr = getElementAddress(SGF, loc, packIndex, eltAddrTy); // Enter a dormant address for the element, under the same condition // as above. CleanupHandle eltCleanup = CleanupHandle::invalid(); if (needCleanups) { eltCleanup = SGF.enterDestroyCleanup(eltAddr); SGF.Cleanups.setCleanupState(eltCleanup, CleanupState::Dormant); } // Emit the initialization into the temporary. TemporaryInitialization eltInit(eltAddr, eltCleanup); fn(&eltInit); // Deactivate the cleanups before continuing the loop. if (needCleanups) { SGF.Cleanups.forwardCleanup(packCleanup); SGF.Cleanups.forwardCleanup(eltCleanup); } } bool InPlacePackExpansionInitialization:: canPerformInPlacePackInitialization(GenericEnvironment *env, SILType eltAddrTy) const { auto loweredPatternTy = getLoweredExpansionType().getPatternType(); if (env) { loweredPatternTy = env->mapContextualPackTypeIntoElementContext(loweredPatternTy); } return loweredPatternTy == eltAddrTy.getASTType(); } SILValue InPlacePackExpansionInitialization:: getAddressForInPlacePackInitialization(SILGenFunction &SGF, SILLocation loc, SILType eltAddrTy) { auto packIndex = emitPackPackIndexForActiveExpansion(SGF, loc, FormalPackType, ComponentIndex); return getElementAddress(SGF, loc, packIndex, eltAddrTy); } void InPlacePackExpansionInitialization:: finishInitialization(SILGenFunction &SGF) { if (ExpansionCleanup.isValid()) SGF.Cleanups.setCleanupState(ExpansionCleanup, CleanupState::Active); } void InPlacePackExpansionInitialization:: enterDormantExpansionCleanup(SILGenFunction &SGF) { assert(!ExpansionCleanup.isValid()); auto loweredExpansionTy = getLoweredExpansionType(); auto loweredPatternTy = loweredExpansionTy.getPatternType(); // Enter a dormant cleanup to destroy the pack expansion elements // if they're non-trivial. if (!SGF.getTypeLowering(loweredPatternTy).isTrivial()) { ExpansionCleanup = enterPartialDestroyCleanup(SGF, /*limit*/SILValue()); SGF.Cleanups.setCleanupState(ExpansionCleanup, CleanupState::Dormant); } } std::unique_ptr PackExpansionInitialization::create(SILGenFunction &SGF, SILValue packAddr, CanPackType formalPackType, unsigned componentIndex) { auto init = std::make_unique(packAddr, formalPackType, componentIndex); init->enterDormantExpansionCleanup(SGF); return init; } CanPackExpansionType PackExpansionInitialization::getLoweredExpansionType() const { auto loweredPackTy = PackAddr->getType().castTo(); auto loweredComponentTy = loweredPackTy->getElementType(ComponentIndex); return cast(loweredComponentTy); } CleanupHandle PackExpansionInitialization::enterPartialDestroyCleanup(SILGenFunction &SGF, SILValue limitWithinComponent) { return SGF.enterPartialDestroyPackCleanup(PackAddr, FormalPackType, ComponentIndex, limitWithinComponent); } SILValue PackExpansionInitialization::getElementAddress(SILGenFunction &SGF, SILLocation loc, SILValue packIndex, SILType eltAddrTy) { return SGF.B.createPackElementGet(loc, packIndex, PackAddr, eltAddrTy); } std::unique_ptr TuplePackExpansionInitialization::create(SILGenFunction &SGF, SILValue tupleAddr, CanPackType inducedPackType, unsigned componentIndex) { auto init = std::make_unique(tupleAddr, inducedPackType, componentIndex); init->enterDormantExpansionCleanup(SGF); return init; } CanPackExpansionType TuplePackExpansionInitialization::getLoweredExpansionType() const { auto loweredTupleTy = TupleAddr->getType().castTo(); auto loweredComponentTy = loweredTupleTy.getElementType(ComponentIndex); return cast(loweredComponentTy); } CleanupHandle TuplePackExpansionInitialization:: enterPartialDestroyCleanup(SILGenFunction &SGF, SILValue limitWithinComponent) { return SGF.enterPartialDestroyTupleCleanup(TupleAddr, FormalPackType, ComponentIndex, limitWithinComponent); } SILValue TuplePackExpansionInitialization::getElementAddress(SILGenFunction &SGF, SILLocation loc, SILValue packIndex, SILType eltAddrTy) { return SGF.B.createTuplePackElementAddr(loc, packIndex, TupleAddr, eltAddrTy); } ManagedValue SILGenFunction::emitPackTransform(SILLocation loc, ManagedValue inputPackMV, CanPackType inputFormalPackType, unsigned inputComponentIndex, SILValue outputPackAddr, CanPackType outputFormalPackType, unsigned outputComponentIndex, bool isSimpleProjection, bool canForwardOutput, llvm::function_ref emitBody) { // This is an inherent limitation of the representation; we need pack // coroutines to get around it. assert((isSimpleProjection || canForwardOutput) && "we cannot support complex transformations that yield borrows"); CleanupCloner inputCloner(*this, inputPackMV); bool inputHasCleanup = inputPackMV.hasCleanup(); auto inputPackAddr = inputPackMV.forward(*this); auto inputPackTy = inputPackAddr->getType().castTo(); assert(inputPackTy->getNumElements() == inputFormalPackType->getNumElements()); auto inputComponentTy = inputPackTy->getSILElementType(inputComponentIndex); auto outputPackTy = outputPackAddr->getType().castTo(); assert(outputPackTy->getNumElements() == outputFormalPackType->getNumElements()); auto outputComponentTy = outputPackTy->getSILElementType(outputComponentIndex); SILType inputEltTy, outputEltTy; auto openedEnv = createOpenedElementValueEnvironment( {inputComponentTy, outputComponentTy}, {&inputEltTy, &outputEltTy}); auto &outputEltTL = getTypeLowering(outputEltTy); bool outputNeedsCleanup = (canForwardOutput && !outputEltTL.isTrivial()); // If the transformation is not a simple projection, we need to // create a tuple to hold the transformed values. SILValue outputTupleAddr; if (!isSimpleProjection) { // The tuple has a single component that matches exactly the expansion // component of the output pack. auto outputTupleTy = SILType::getPrimitiveObjectType( CanType(TupleType::get({outputComponentTy.getASTType()}, SGM.getASTContext()))); outputTupleAddr = emitTemporaryAllocation(loc, outputTupleTy); } emitDynamicPackLoop(loc, inputFormalPackType, inputComponentIndex, openedEnv, [&](SILValue indexWithinComponent, SILValue packExpansionIndex, SILValue inputPackIndex) { // Enter a cleanup for the remaining elements of the input // expansion component. CleanupHandle remainingInputEltsCleanup = CleanupHandle::invalid(); if (inputHasCleanup) { remainingInputEltsCleanup = enterPartialDestroyRemainingPackCleanup( inputPackAddr, inputFormalPackType, inputComponentIndex, indexWithinComponent); } // Enter a cleanup for the previous elements of the output // expansion component. CleanupHandle previousOutputEltsCleanup = CleanupHandle::invalid(); if (outputNeedsCleanup) { previousOutputEltsCleanup = enterPartialDestroyPackCleanup( outputPackAddr, outputFormalPackType, outputComponentIndex, indexWithinComponent); } // If this is not a simple projection, project the output tuple element // and encourage the transformation to initialize into it. SILValue outputEltAddr; TemporaryInitializationPtr outputEltInit; if (!isSimpleProjection) { outputEltAddr = B.createTuplePackElementAddr(loc, packExpansionIndex, outputTupleAddr, outputEltTy); outputEltInit = useBufferAsTemporary(outputEltAddr, outputEltTL); } // Retrieve the input value from the pack and manage it. auto inputEltAddr = B.createPackElementGet(loc, inputPackIndex, inputPackAddr, inputEltTy); ManagedValue inputElt = inputCloner.clone(inputEltAddr); // Apply the transform. ManagedValue outputElt = emitBody(inputElt, outputEltTy, canForwardOutput ? SGFContext(outputEltInit.get()) : SGFContext::AllowGuaranteedPlusZero); assert(canForwardOutput == (outputElt.isInContext() || outputElt.isPlusOneOrTrivial(*this)) && "transformation produced a value of the wrong ownership"); assert((outputElt.isInContext() || outputElt.getType() == outputEltTy) && "transformation produced a value of the wrong type"); // If this is a simple projection, then we should be able to just // write the value into the pack. if (isSimpleProjection) { assert(!outputElt.isInContext()); outputEltAddr = outputElt.forward(*this); // Otherwise, if the value is not already in the temporary, put it there. } else { if (!outputElt.isInContext()) outputElt.forwardInto(*this, loc, outputEltInit.get()); outputEltInit->getManagedAddress().forward(*this); } // Insert the output address into the output pack. SILValue outputPackIndex = packExpansionIndex; if (outputFormalPackType->getNumElements() != 1) { outputPackIndex = B.createPackPackIndex(loc, outputComponentIndex, outputPackIndex, outputFormalPackType); } B.createPackElementSet(loc, outputEltAddr, outputPackIndex, outputPackAddr); // Deactivate the partial cleanups. if (remainingInputEltsCleanup.isValid()) Cleanups.forwardCleanup(remainingInputEltsCleanup); if (previousOutputEltsCleanup.isValid()) Cleanups.forwardCleanup(previousOutputEltsCleanup); }); if (outputNeedsCleanup) { auto cleanup = enterPartialDestroyPackCleanup(outputPackAddr, outputFormalPackType, outputComponentIndex, /*limit*/ SILValue()); return ManagedValue::forOwnedAddressRValue(outputPackAddr, cleanup); } else if (canForwardOutput) { return ManagedValue::forTrivialAddressRValue(outputPackAddr); } else { return ManagedValue::forBorrowedAddressRValue(outputPackAddr); } }