// At each release point, release the reaching values that have been stored to // this address. // // The caller has already determined that all Stores are to the same element // within an otherwise dead object. static void insertReleases(ArrayRef<StoreInst*> Stores, ArrayRef<SILInstruction*> ReleasePoints, SILSSAUpdater &SSAUp) { assert(!Stores.empty()); SILValue StVal = Stores.front()->getSrc(); SSAUp.Initialize(StVal->getType()); for (auto *Store : Stores) SSAUp.AddAvailableValue(Store->getParent(), Store->getSrc()); SILLocation Loc = Stores[0]->getLoc(); for (auto *RelPoint : ReleasePoints) { SILBuilder B(RelPoint); // This does not use the SSAUpdater::RewriteUse API because it does not do // the right thing for local uses. We have already ensured a single store // per block, and all release points occur after all stores. Therefore we // can simply ask SSAUpdater for the reaching store. SILValue RelVal = SSAUp.GetValueAtEndOfBlock(RelPoint->getParent()); if (StVal->getType().isReferenceCounted(RelPoint->getModule())) B.createStrongRelease(Loc, RelVal, Atomicity::Atomic); else B.createReleaseValue(Loc, RelVal, Atomicity::Atomic); } }
static void updateSSAForUseOfInst(SILSSAUpdater &Updater, SmallVectorImpl<SILArgument*> &InsertedPHIs, const llvm::DenseMap<ValueBase *, SILValue> &ValueMap, SILBasicBlock *Header, SILBasicBlock *EntryCheckBlock, ValueBase *Inst) { if (Inst->use_empty()) return; // Find the mapped instruction. assert(ValueMap.count(Inst) && "Expected to find value in map!"); SILValue MappedValue = ValueMap.find(Inst)->second; assert(MappedValue); // For each use of a specific result value of the instruction. if (Inst->hasValue()) { SILValue Res(Inst); assert(Res->getType() == MappedValue->getType() && "The types must match"); InsertedPHIs.clear(); Updater.Initialize(Res->getType()); Updater.AddAvailableValue(Header, Res); Updater.AddAvailableValue(EntryCheckBlock, MappedValue); // Because of the way that phi nodes are represented we have to collect all // uses before we update SSA. Modifying one phi node can invalidate another // unrelated phi nodes operands through the common branch instruction (that // has to be modified). This would invalidate a plain ValueUseIterator. // Instead we collect uses wrapping uses in branches specially so that we // can reconstruct the use even after the branch has been modified. SmallVector<UseWrapper, 8> StoredUses; for (auto *U : Res->getUses()) StoredUses.push_back(UseWrapper(U)); for (auto U : StoredUses) { Operand *Use = U; SILInstruction *User = Use->getUser(); assert(User && "Missing user"); // Ignore uses in the same basic block. if (User->getParent() == Header) continue; assert(User->getParent() != EntryCheckBlock && "The entry check block should dominate the header"); Updater.RewriteUse(*Use); } // Canonicalize inserted phis to avoid extra BB Args. for (SILArgument *Arg : InsertedPHIs) { if (SILInstruction *Inst = replaceBBArgWithCast(Arg)) { Arg->replaceAllUsesWith(Inst); // DCE+SimplifyCFG runs as a post-pass cleanup. // DCE replaces dead arg values with undef. // SimplifyCFG deletes the dead BB arg. } } } }
static void updateSSA(SILModule &M, SILLoop *Loop, DenseMap<SILValue, SmallVector<SILValue, 8>> &LoopLiveOutValues) { SILSSAUpdater SSAUp; for (auto &MapEntry : LoopLiveOutValues) { // Collect out of loop uses of this value. auto OrigValue = MapEntry.first; SmallVector<UseWrapper, 16> UseList; for (auto Use : OrigValue->getUses()) if (!Loop->contains(Use->getUser()->getParent())) UseList.push_back(UseWrapper(Use)); // Update SSA of use with the available values. SSAUp.Initialize(OrigValue->getType()); SSAUp.AddAvailableValue(OrigValue->getParentBlock(), OrigValue); for (auto NewValue : MapEntry.second) SSAUp.AddAvailableValue(NewValue->getParentBlock(), NewValue); for (auto U : UseList) { Operand *Use = U; SSAUp.RewriteUse(*Use); } } }