/// Returns the Apply and WitnessMethod instructions that use the /// open_existential_addr instructions, or null if at least one of the /// instructions is missing. static ApplyWitnessPair getOpenExistentialUsers(OpenExistentialAddrInst *OE) { ApplyInst *AI = nullptr; WitnessMethodInst *WMI = nullptr; ApplyWitnessPair Empty = std::make_pair(nullptr, nullptr); for (auto *UI : getNonDebugUses(OE)) { auto *User = UI->getUser(); if (!isa<WitnessMethodInst>(User) && User->isTypeDependentOperand(UI->getOperandNumber())) continue; // Check that we have a single Apply user. if (auto *AA = dyn_cast<ApplyInst>(User)) { if (AI) return Empty; AI = AA; continue; } // Check that we have a single WMI user. if (auto *W = dyn_cast<WitnessMethodInst>(User)) { if (WMI) return Empty; WMI = W; continue; } // Unknown instruction. return Empty; } // Both instructions need to exist. if (!WMI || !AI) return Empty; // Make sure that the WMI and AI match. if (AI->getCallee() != WMI) return Empty; // We have exactly the pattern that we expected. return std::make_pair(AI, WMI); }
ApplyInst *SILGlobalOpt::getHoistedApplyForInitializer( ApplyInst *AI, DominanceInfo *DT, SILFunction *InitF, SILFunction *ParentF, llvm::DenseMap<SILFunction *, ApplyInst *> &ParentFuncs) { auto PFI = ParentFuncs.find(ParentF); if (PFI == ParentFuncs.end()) { ParentFuncs[ParentF] = AI; // It's the first time we found a call to InitF in this function, so we // try to hoist it out of any loop. return AI; } // Found a replacement for this init call. Ensure the replacement dominates // the original call site. ApplyInst *CommonAI = PFI->second; assert( cast<FunctionRefInst>(CommonAI->getCallee())->getReferencedFunction() == InitF && "ill-formed global init call"); SILBasicBlock *DomBB = DT->findNearestCommonDominator(AI->getParent(), CommonAI->getParent()); // We must not move initializers around availability-checks. if (isAvailabilityCheckOnDomPath(DomBB, CommonAI->getParent(), DT)) return nullptr; ApplyInst *Result = nullptr; if (DomBB != CommonAI->getParent()) { CommonAI->moveBefore(&*DomBB->begin()); placeFuncRef(CommonAI, DT); // Try to hoist the existing AI again if we move it to another block, // e.g. from a loop exit into the loop. Result = CommonAI; } AI->replaceAllUsesWith(CommonAI); AI->eraseFromParent(); HasChanged = true; return Result; }
/// Optimize placement of initializer calls given a list of calls to the /// same initializer. All original initialization points must be dominated by /// the final initialization calls. /// /// The current heuristic hoists all initialization points within a function to /// a single dominating call in the outer loop preheader. void SILGlobalOpt::placeInitializers(SILFunction *InitF, ArrayRef<ApplyInst*> Calls) { DEBUG(llvm::dbgs() << "GlobalOpt: calls to " << demangle_wrappers::demangleSymbolAsString(InitF->getName()) << " : " << Calls.size() << "\n"); // Map each initializer-containing function to its final initializer call. llvm::DenseMap<SILFunction*, ApplyInst*> ParentFuncs; for (auto *AI : Calls) { assert(AI->getNumArguments() == 0 && "ill-formed global init call"); assert(cast<FunctionRefInst>(AI->getCallee())->getReferencedFunction() == InitF && "wrong init call"); SILFunction *ParentF = AI->getFunction(); DominanceInfo *DT = DA->get(ParentF); auto PFI = ParentFuncs.find(ParentF); ApplyInst *HoistAI = nullptr; if (PFI != ParentFuncs.end()) { // Found a replacement for this init call. // Ensure the replacement dominates the original call site. ApplyInst *CommonAI = PFI->second; assert(cast<FunctionRefInst>(CommonAI->getCallee()) ->getReferencedFunction() == InitF && "ill-formed global init call"); SILBasicBlock *DomBB = DT->findNearestCommonDominator(AI->getParent(), CommonAI->getParent()); // We must not move initializers around availability-checks. if (!isAvailabilityCheckOnDomPath(DomBB, CommonAI->getParent(), DT)) { if (DomBB != CommonAI->getParent()) { CommonAI->moveBefore(&*DomBB->begin()); placeFuncRef(CommonAI, DT); // Try to hoist the existing AI again if we move it to another block, // e.g. from a loop exit into the loop. HoistAI = CommonAI; } AI->replaceAllUsesWith(CommonAI); AI->eraseFromParent(); HasChanged = true; } } else { ParentFuncs[ParentF] = AI; // It's the first time we found a call to InitF in this function, so we // try to hoist it out of any loop. HoistAI = AI; } if (HoistAI) { // Move this call to the outermost loop preheader. SILBasicBlock *BB = HoistAI->getParent(); typedef llvm::DomTreeNodeBase<SILBasicBlock> DomTreeNode; DomTreeNode *Node = DT->getNode(BB); while (Node) { SILBasicBlock *DomParentBB = Node->getBlock(); if (isAvailabilityCheck(DomParentBB)) { DEBUG(llvm::dbgs() << " don't hoist above availability check at bb" << DomParentBB->getDebugID() << "\n"); break; } BB = DomParentBB; if (!isInLoop(BB)) break; Node = Node->getIDom(); } if (BB == HoistAI->getParent()) { // BB is either unreachable or not in a loop. DEBUG(llvm::dbgs() << " skipping (not in a loop): " << *HoistAI << " in " << HoistAI->getFunction()->getName() << "\n"); } else { DEBUG(llvm::dbgs() << " hoisting: " << *HoistAI << " in " << HoistAI->getFunction()->getName() << "\n"); HoistAI->moveBefore(&*BB->begin()); placeFuncRef(HoistAI, DT); HasChanged = true; } } } }