/// If \p Op has instructions in the instruction range (Start, End] which may /// decrement it, return the first such instruction. Returns None /// if no such instruction exists. We assume that Start and End are both in the /// same basic block. Optional<SILBasicBlock::iterator> swift:: valueHasARCDecrementOrCheckInInstructionRange(SILValue Op, SILBasicBlock::iterator Start, SILBasicBlock::iterator End, AliasAnalysis *AA) { assert(Start->getParent() == End->getParent() && "Start and End should be in the same basic block"); // If Start == End, then we have an empty range, return nothing. if (Start == End) return None; // Otherwise, until Start != End. while (Start != End) { // Check if Start can decrement or check Op's ref count. If so, return // Start. Ref count checks do not have side effects, but are barriers for // retains. if (mayDecrementRefCount(&*Start, Op, AA) || mayCheckRefCount(&*Start)) return Start; // Otherwise, increment our iterator. ++Start; } // If all such instructions cannot decrement Op, return nothing. return None; }
/// If \p Op has arc uses in the instruction range [Start, End), return the /// first such instruction. Otherwise return None. We assume that /// Start and End are both in the same basic block. Optional<SILBasicBlock::iterator> swift:: valueHasARCUsesInInstructionRange(SILValue Op, SILBasicBlock::iterator Start, SILBasicBlock::iterator End, AliasAnalysis *AA) { assert(Start->getParent() == End->getParent() && "Start and End should be in the same basic block"); // If Start == End, then we have an empty range, return false. if (Start == End) return None; // Otherwise, until Start != End. while (Start != End) { // Check if Start can use Op in an ARC relevant way. If so, return true. if (mayHaveSymmetricInterference(&*Start, Op, AA)) return Start; // Otherwise, increment our iterator. ++Start; } // If all such instructions cannot use Op, return false. return None; }
/// If \p Op has arc uses in the instruction range (Start, End], return the /// first such instruction. Otherwise return None. We assume that Start and End /// are both in the same basic block. Optional<SILBasicBlock::iterator> swift::valueHasARCUsesInReverseInstructionRange(SILValue Op, SILBasicBlock::iterator Start, SILBasicBlock::iterator End, AliasAnalysis *AA) { assert(Start->getParent() == End->getParent() && "Start and End should be in the same basic block"); assert(End != End->getParent()->end() && "End should be mapped to an actual instruction"); // If Start == End, then we have an empty range, return false. if (Start == End) return None; // Otherwise, until End == Start. while (Start != End) { // Check if Start can use Op in an ARC relevant way. If so, return true. if (mayHaveSymmetricInterference(&*End, Op, AA)) return End; // Otherwise, decrement our iterator. --End; } // If all such instructions cannot use Op, return false. return None; }
/// Perform outlining on the function and return any newly created outlined /// functions. bool tryOutline(SILOptFunctionBuilder &FuncBuilder, SILFunction *Fun, SmallVectorImpl<SILFunction *> &FunctionsAdded) { SmallPtrSet<SILBasicBlock *, 32> Visited; SmallVector<SILBasicBlock *, 128> Worklist; OutlinePatterns patterns(FuncBuilder); // Traverse the function. Worklist.push_back(&*Fun->begin()); while (!Worklist.empty()) { SILBasicBlock *CurBlock = Worklist.pop_back_val(); if (!Visited.insert(CurBlock).second) continue; SILBasicBlock::iterator CurInst = CurBlock->begin(); // Go over the instructions trying to match and replace patterns. while (CurInst != CurBlock->end()) { if (OutlinePattern *match = patterns.tryToMatch(CurInst)) { SILFunction *F; SILBasicBlock::iterator LastInst; std::tie(F, LastInst) = match->outline(Fun->getModule()); if (F) FunctionsAdded.push_back(F); CurInst = LastInst; assert(LastInst->getParent() == CurBlock); } else if (isa<TermInst>(CurInst)) { std::copy(CurBlock->succ_begin(), CurBlock->succ_end(), std::back_inserter(Worklist)); ++CurInst; } else { ++CurInst; } } } return false; }
/// Handle CSE of open_existential_ref instructions. /// Returns true if uses of open_existential_ref can /// be replaced by a dominating instruction. /// \Inst is the open_existential_ref instruction /// \V is the dominating open_existential_ref instruction /// \I is the iterator referring to the current instruction. bool CSE::processOpenExistentialRef(SILInstruction *Inst, ValueBase *V, SILBasicBlock::iterator &I) { assert(isa<OpenExistentialRefInst>(Inst)); llvm::SmallSetVector<SILInstruction *, 16> Candidates; auto OldOpenedArchetype = getOpenedArchetypeOf(Inst); auto NewOpenedArchetype = getOpenedArchetypeOf(dyn_cast<SILInstruction>(V)); TypeSubstitutionMap TypeSubstMap; TypeSubstMap[OldOpenedArchetype.getPointer()] = NewOpenedArchetype; // Collect all candidates that may contain opened archetypes // that need to be replaced. for (auto Use : Inst->getUses()) { auto User = Use->getUser(); if (!User->getTypeDependentOperands().empty()) { if (canHandle(User)) { auto It = AvailableValues->begin(User); if (It != AvailableValues->end()) { return false; } } Candidates.insert(User); } if (!isa<TermInst>(User)) continue; // The current use of the opened archetype is a terminator instruction. // Check if any of the successor BBs uses this opened archetype in the // types of its basic block arguments. If this is the case, replace // those uses by the new opened archetype. auto Successors = User->getParent()->getSuccessorBlocks(); for (auto Successor : Successors) { if (Successor->bbarg_empty()) continue; // If a BB has any arguments, update their types if necessary. updateBasicBlockArgTypes(Successor, TypeSubstMap); } } // Now process candidates. // TODO: Move it to CSE instance to avoid recreating it every time? SILOpenedArchetypesTracker OpenedArchetypesTracker(*Inst->getFunction()); // Register the new archetype to be used. OpenedArchetypesTracker.registerOpenedArchetypes(dyn_cast<SILInstruction>(V)); // Use a cloner. It makes copying the instruction and remapping of // opened archetypes trivial. InstructionCloner Cloner(I->getFunction()); Cloner.registerOpenedExistentialRemapping( OldOpenedArchetype->castTo<ArchetypeType>(), NewOpenedArchetype); auto &Builder = Cloner.getBuilder(); Builder.setOpenedArchetypesTracker(&OpenedArchetypesTracker); llvm::SmallPtrSet<SILInstruction *, 16> Processed; // Now clone each candidate and replace the opened archetype // by a dominating one. while (!Candidates.empty()) { auto Candidate = Candidates.pop_back_val(); if (Processed.count(Candidate)) continue; // True if a candidate depends on the old opened archetype. bool DependsOnOldOpenedArchetype = !Candidate->getTypeDependentOperands().empty(); if (!Candidate->use_empty() && Candidate->getType().getSwiftRValueType()->hasOpenedExistential()) { // Check if the result type of the candidate depends on the opened // existential in question. auto ResultDependsOnOldOpenedArchetype = Candidate->getType().getSwiftRValueType().findIf( [&OldOpenedArchetype](Type t) -> bool { if (t.getCanonicalTypeOrNull() == OldOpenedArchetype) return true; return false; }); if (ResultDependsOnOldOpenedArchetype) { DependsOnOldOpenedArchetype |= ResultDependsOnOldOpenedArchetype; // We need to update uses of this candidate, because their types // may be affected. for (auto Use : Candidate->getUses()) { Candidates.insert(Use->getUser()); } } } // Remember that this candidate was processed already. Processed.insert(Candidate); // No need to clone if there is no dependency on the old opened archetype. if (!DependsOnOldOpenedArchetype) continue; Builder.getOpenedArchetypes().addOpenedArchetypeOperands( Candidate->getTypeDependentOperands()); Builder.setInsertionPoint(Candidate); auto NewI = Cloner.clone(Candidate); // Result types of candidate's uses instructions may be using this archetype. // Thus, we need to try to replace it there. Candidate->replaceAllUsesWith(NewI); if (I == Candidate->getIterator()) I = NewI->getIterator(); eraseFromParentWithDebugInsts(Candidate, I); } return true; }