// Since we have an RValue, we know that RValue invariants imply that all // subvalues that are addresses must be address only types. Such address only // types if they are +1 rvalues should be independent of any values from outside // the +1 rvalue emission (that is if someone else has a reference to the // address only type, we should have produced a copy). This means that it is // safe to move the value into new memory that is guaranteed to live through the // scope being pushed. As an additional complication due to SIL enforcing stack // ordering, we can not use a temporary stack location since any stack locations // that are inside the scope will be cleaned up while such a scope jumping stack // is still alive (violating stack ordering). Instead we use an alloc_box to // store the new value. allocbox-to-stack will then reorder/expand the stack // lifetimes to resolve the issues. static void lifetimeExtendAddressOnlyRValueSubValues( SILGenFunction &SGF, SILLocation loc, llvm::SmallVectorImpl<SILValue> &values, llvm::SmallVectorImpl<SILValue> &lifetimeExtendingBoxes) { for (SILValue &v : values) { // If v is not an address, it isn't interesting, continue. if (!v->getType().isAddress()) { continue; } // Otherwise, create the box and move the address only value into the box. assert(v->getType().isAddressOnly(SGF.getModule()) && "RValue invariants imply that all RValue subtypes that are " "addresses must be address only."); auto boxTy = SILBoxType::get(v->getType().getSwiftRValueType()); SILValue box = SGF.B.createAllocBox(loc, boxTy); SILValue addr = SGF.B.createProjectBox(loc, box, 0); SGF.B.createCopyAddr(loc, v, addr, IsTake, IsInitialization); // Then save the box so we create the box destroy in the caller and // overwrite v with the project box since that is where the value is now. lifetimeExtendingBoxes.emplace_back(box); v = addr; } }
// TODO: This should really be an operation on type lowering. void SILBuilder::emitShallowDestructureValueOperation( SILLocation Loc, SILValue V, llvm::SmallVectorImpl<SILValue> &Results) { // Once destructure is allowed everywhere, remove the projection code. // If we do not have a tuple or a struct, add to our results list and return. SILType Ty = V->getType(); if (!(Ty.is<TupleType>() || Ty.getStructOrBoundGenericStruct())) { Results.emplace_back(V); return; } // Otherwise, we want to destructure add the destructure and return. if (getFunction().hasQualifiedOwnership()) { auto *DI = emitDestructureValueOperation(Loc, V); copy(DI->getResults(), std::back_inserter(Results)); return; } // In non qualified ownership SIL, drop back to using projection code. llvm::SmallVector<Projection, 16> Projections; Projection::getFirstLevelProjections(V->getType(), getModule(), Projections); transform(Projections, std::back_inserter(Results), [&](const Projection &P) -> SILValue { return P.createObjectProjection(*this, Loc, V).get(); }); }
/// If AI is the version of an initializer where we pass in either an apply or /// an alloc_ref to initialize in place, validate that we are able to continue /// optimizing and return To static bool getDeadInstsAfterInitializerRemoved( ApplyInst *AI, llvm::SmallVectorImpl<SILInstruction *> &ToDestroy) { assert(ToDestroy.empty() && "We assume that ToDestroy is empty, so on " "failure we can clear without worrying about the " "caller accumulating and thus our eliminating " "passed in state."); SILValue Arg0 = AI->getArgument(0); if (Arg0->getType().isExistentialType()) { // This is a version of the initializer which receives a pre-allocated // buffer as first argument. To completely eliminate the allocation, we must // destroy the extra allocations as well as the initializer, if (auto *Result = dyn_cast<ApplyInst>(Arg0)) { ToDestroy.emplace_back(Result); return true; } return false; } if (auto *ARI = dyn_cast<AllocRefInst>(Arg0)) { if (all_of(ARI->getUses(), [&](Operand *Op) -> bool { if (Op->getUser() == AI) return true; if (auto *SRI = dyn_cast<StrongReleaseInst>(Op->getUser())) { ToDestroy.emplace_back(SRI); return true; } return false; })) { return true; } } // We may have added elements to the array before we failed. To avoid such a // problem, we clear the out array here. We assert at the beginning that the // out array is empty, so this is safe. ToDestroy.clear(); return true; }
// TODO: Can we put this on type lowering? It would take a little bit of work // since we would need to be able to handle aggregate trivial types which is not // represented today in TypeLowering. void SILBuilder::emitShallowDestructureAddressOperation( SILLocation Loc, SILValue V, llvm::SmallVectorImpl<SILValue> &Results) { // If we do not have a tuple or a struct, add to our results list. SILType Ty = V->getType(); if (!(Ty.is<TupleType>() || Ty.getStructOrBoundGenericStruct())) { Results.emplace_back(V); return; } llvm::SmallVector<Projection, 16> Projections; Projection::getFirstLevelProjections(V->getType(), getModule(), Projections); transform(Projections, std::back_inserter(Results), [&](const Projection &P) -> SILValue { return P.createAddressProjection(*this, Loc, V).get(); }); }