static bool prepareExtraEpilog(SILGenFunction &SGF, JumpDest &dest, SILLocation &loc, SILValue *arg) { assert(!SGF.B.hasValidInsertionPoint()); // If we don't have a destination, we don't need to emit the epilog. if (!dest.isValid()) return false; // If the destination isn't used, we don't need to emit the epilog. SILBasicBlock *epilogBB = dest.getBlock(); auto pi = epilogBB->pred_begin(), pe = epilogBB->pred_end(); if (pi == pe) { dest = JumpDest::invalid(); SGF.eraseBasicBlock(epilogBB); return false; } assert(epilogBB->getNumArguments() <= 1); assert((epilogBB->getNumArguments() == 1) == (arg != nullptr)); if (arg) *arg = epilogBB->args_begin()[0]; bool reposition = true; // If the destination has a single branch predecessor, // consider emitting the epilog into it. SILBasicBlock *predBB = *pi; if (++pi == pe) { if (auto branch = dyn_cast<BranchInst>(predBB->getTerminator())) { assert(branch->getArgs().size() == epilogBB->getNumArguments()); // Save the location and operand information from the branch, // then destroy it. loc = branch->getLoc(); if (arg) *arg = branch->getArgs()[0]; predBB->erase(branch); // Erase the rethrow block. SGF.eraseBasicBlock(epilogBB); epilogBB = predBB; reposition = false; } } // Reposition the block to the end of the postmatter section // unless we're emitting into a single predecessor. if (reposition) { SGF.B.moveBlockTo(epilogBB, SGF.F.end()); } SGF.B.setInsertionPoint(epilogBB); return true; }
void SILGenFunction::emitRethrowEpilog(SILLocation topLevel) { assert(!B.hasValidInsertionPoint()); // If we don't have a rethrow destination, we're done. if (!ThrowDest.isValid()) return; // If the rethrow destination isn't used, we're done. SILBasicBlock *rethrowBB = ThrowDest.getBlock(); if (rethrowBB->pred_empty()) { ThrowDest = JumpDest::invalid(); eraseBasicBlock(rethrowBB); return; } SILLocation throwLoc = topLevel; SILValue exn = rethrowBB->args_begin()[0]; bool reposition = true; // If the rethrow destination has a single branch predecessor, // consider emitting the rethrow into it. SILBasicBlock *predBB = *rethrowBB->pred_begin(); if (std::next(rethrowBB->pred_begin()) == rethrowBB->pred_end()) { if (auto branch = dyn_cast<BranchInst>(predBB->getTerminator())) { assert(branch->getArgs().size() == 1); // Save the location and operand information from the branch, // then destroy it. throwLoc = branch->getLoc(); exn = branch->getArgs()[0]; predBB->erase(branch); // Erase the rethrow block. eraseBasicBlock(rethrowBB); rethrowBB = predBB; reposition = false; } } // Reposition the rethrow block to the end of the postmatter section // unless we're emitting into a single predecessor. if (reposition) { B.moveBlockTo(rethrowBB, F.end()); } B.setInsertionPoint(rethrowBB); Cleanups.emitCleanupsForReturn(ThrowDest.getCleanupLocation()); B.createThrow(throwLoc, exn); ThrowDest = JumpDest::invalid(); }
/// \brief Populate the body of the cloned closure, modifying instructions as /// necessary to take into consideration the removed parameters. void PromotedParamCloner::populateCloned() { SILFunction *Cloned = getCloned(); // Create arguments for the entry block SILBasicBlock *OrigEntryBB = &*Orig->begin(); SILBasicBlock *ClonedEntryBB = Cloned->createBasicBlock(); unsigned ArgNo = 0; auto I = OrigEntryBB->args_begin(), E = OrigEntryBB->args_end(); while (I != E) { if (count(PromotedArgIndices, ArgNo)) { // Create a new argument with the promoted type. auto boxTy = (*I)->getType().castTo<SILBoxType>(); assert(boxTy->getLayout()->getFields().size() == 1 && "promoting multi-field boxes not implemented yet"); auto promotedTy = boxTy->getFieldType(Cloned->getModule(), 0); auto *promotedArg = ClonedEntryBB->createFunctionArgument(promotedTy, (*I)->getDecl()); PromotedParameters.insert(*I); // Map any projections of the box to the promoted argument. for (auto use : (*I)->getUses()) { if (auto project = dyn_cast<ProjectBoxInst>(use->getUser())) { ValueMap.insert(std::make_pair(project, promotedArg)); } } } else { // Create a new argument which copies the original argument. SILValue MappedValue = ClonedEntryBB->createFunctionArgument( (*I)->getType(), (*I)->getDecl()); ValueMap.insert(std::make_pair(*I, MappedValue)); } ++ArgNo; ++I; } getBuilder().setInsertionPoint(ClonedEntryBB); BBMap.insert(std::make_pair(OrigEntryBB, ClonedEntryBB)); // Recursively visit original BBs in depth-first preorder, starting with the // entry block, cloning all instructions other than terminators. visitSILBasicBlock(OrigEntryBB); // Now iterate over the BBs and fix up the terminators. for (auto BI = BBMap.begin(), BE = BBMap.end(); BI != BE; ++BI) { getBuilder().setInsertionPoint(BI->second); visit(BI->first->getTerminator()); } }
/// \brief Populate the body of the cloned closure, modifying instructions as /// necessary to take into consideration the removed parameters. void PromotedParamCloner::populateCloned() { SILFunction *Cloned = getCloned(); // Create arguments for the entry block SILBasicBlock *OrigEntryBB = &*Orig->begin(); SILBasicBlock *ClonedEntryBB = Cloned->createBasicBlock(); SmallVector<SILValue, 4> entryArgs; entryArgs.reserve(OrigEntryBB->getArguments().size()); // Initialize all NewPromotedArgs slots to an invalid value. NewPromotedArgs.resize(OrigEntryBB->getArguments().size()); unsigned ArgNo = 0; auto I = OrigEntryBB->args_begin(), E = OrigEntryBB->args_end(); while (I != E) { if (count(PromotedArgIndices, ArgNo)) { // Create a new argument with the promoted type. auto boxTy = (*I)->getType().castTo<SILBoxType>(); assert(boxTy->getLayout()->getFields().size() == 1 && "promoting multi-field boxes not implemented yet"); auto promotedTy = boxTy->getFieldType(Cloned->getModule(), 0); auto *promotedArg = ClonedEntryBB->createFunctionArgument(promotedTy, (*I)->getDecl()); OrigPromotedParameters.insert(*I); NewPromotedArgs[ArgNo] = promotedArg; // All uses of the promoted box should either be projections, which are // folded when visited, or copy/destroy operations which are ignored. entryArgs.push_back(SILValue()); } else { // Create a new argument which copies the original argument. entryArgs.push_back(ClonedEntryBB->createFunctionArgument( (*I)->getType(), (*I)->getDecl())); } ++ArgNo; ++I; } // Visit original BBs in depth-first preorder, starting with the // entry block, cloning all instructions and terminators. cloneFunctionBody(Orig, ClonedEntryBB, entryArgs); }
std::pair<Optional<SILValue>, SILLocation> SILGenFunction::emitEpilogBB(SILLocation TopLevel) { assert(ReturnDest.getBlock() && "no epilog bb prepared?!"); SILBasicBlock *epilogBB = ReturnDest.getBlock(); SILLocation ImplicitReturnFromTopLevel = ImplicitReturnLocation::getImplicitReturnLoc(TopLevel); SmallVector<SILValue, 4> directResults; Optional<SILLocation> returnLoc = None; // If the current BB isn't terminated, and we require a return, then we // are not allowed to fall off the end of the function and can't reach here. if (NeedsReturn && B.hasValidInsertionPoint()) B.createUnreachable(ImplicitReturnFromTopLevel); if (epilogBB->pred_empty()) { // If the epilog was not branched to at all, kill the BB and // just emit the epilog into the current BB. while (!epilogBB->empty()) epilogBB->back().eraseFromParent(); eraseBasicBlock(epilogBB); // If the current bb is terminated then the epilog is just unreachable. if (!B.hasValidInsertionPoint()) return { None, TopLevel }; // We emit the epilog at the current insertion point. returnLoc = ImplicitReturnFromTopLevel; } else if (std::next(epilogBB->pred_begin()) == epilogBB->pred_end() && !B.hasValidInsertionPoint()) { // If the epilog has a single predecessor and there's no current insertion // point to fall through from, then we can weld the epilog to that // predecessor BB. // Steal the branch argument as the return value if present. SILBasicBlock *pred = *epilogBB->pred_begin(); BranchInst *predBranch = cast<BranchInst>(pred->getTerminator()); assert(predBranch->getArgs().size() == epilogBB->args_size() && "epilog predecessor arguments does not match block params"); for (auto index : indices(predBranch->getArgs())) { SILValue result = predBranch->getArgs()[index]; directResults.push_back(result); epilogBB->getArgument(index)->replaceAllUsesWith(result); } // If we are optimizing, we should use the return location from the single, // previously processed, return statement if any. if (predBranch->getLoc().is<ReturnLocation>()) { returnLoc = predBranch->getLoc(); } else { returnLoc = ImplicitReturnFromTopLevel; } // Kill the branch to the now-dead epilog BB. pred->erase(predBranch); // Move any instructions from the EpilogBB to the end of the 'pred' block. pred->spliceAtEnd(epilogBB); // Finally we can erase the epilog BB. eraseBasicBlock(epilogBB); // Emit the epilog into its former predecessor. B.setInsertionPoint(pred); } else { // Move the epilog block to the end of the ordinary section. auto endOfOrdinarySection = StartOfPostmatter; B.moveBlockTo(epilogBB, endOfOrdinarySection); // Emit the epilog into the epilog bb. Its arguments are the // direct results. directResults.append(epilogBB->args_begin(), epilogBB->args_end()); // If we are falling through from the current block, the return is implicit. B.emitBlock(epilogBB, ImplicitReturnFromTopLevel); } // Emit top-level cleanups into the epilog block. assert(!Cleanups.hasAnyActiveCleanups(getCleanupsDepth(), ReturnDest.getDepth()) && "emitting epilog in wrong scope"); auto cleanupLoc = CleanupLocation::get(TopLevel); Cleanups.emitCleanupsForReturn(cleanupLoc); // If the return location is known to be that of an already // processed return, use it. (This will get triggered when the // epilog logic is simplified.) // // Otherwise make the ret instruction part of the cleanups. if (!returnLoc) returnLoc = cleanupLoc; // Build the return value. We don't do this if there are no direct // results; this can happen for void functions, but also happens when // prepareEpilog was asked to not add result arguments to the epilog // block. SILValue returnValue; if (!directResults.empty()) { assert(directResults.size() == F.getConventions().getNumDirectSILResults()); returnValue = buildReturnValue(*this, TopLevel, directResults); } return { returnValue, *returnLoc }; }
void GenericCloner::populateCloned() { SILFunction *Cloned = getCloned(); // Create arguments for the entry block. SILBasicBlock *OrigEntryBB = &*Original.begin(); SILBasicBlock *ClonedEntryBB = Cloned->createBasicBlock(); getBuilder().setInsertionPoint(ClonedEntryBB); llvm::SmallVector<AllocStackInst *, 8> AllocStacks; AllocStackInst *ReturnValueAddr = nullptr; // Create the entry basic block with the function arguments. auto I = OrigEntryBB->args_begin(), E = OrigEntryBB->args_end(); int ArgIdx = 0; while (I != E) { SILArgument *OrigArg = *I; RegularLocation Loc((Decl *)OrigArg->getDecl()); AllocStackInst *ASI = nullptr; SILType mappedType = remapType(OrigArg->getType()); if (ReInfo.isArgConverted(ArgIdx)) { // We need an alloc_stack as a replacement for the indirect parameter. assert(mappedType.isAddress()); mappedType = mappedType.getObjectType(); ASI = getBuilder().createAllocStack(Loc, mappedType); ValueMap[OrigArg] = ASI; AllocStacks.push_back(ASI); if (ReInfo.isResultIndex(ArgIdx)) { // This result is converted from indirect to direct. The return inst // needs to load the value from the alloc_stack. See below. assert(!ReturnValueAddr); ReturnValueAddr = ASI; } else { // Store the new direct parameter to the alloc_stack. auto *NewArg = ClonedEntryBB->createArgument(mappedType, OrigArg->getDecl()); getBuilder().createStore(Loc, NewArg, ASI, StoreOwnershipQualifier::Unqualified); // Try to create a new debug_value from an existing debug_value_addr. for (Operand *ArgUse : OrigArg->getUses()) { if (auto *DVAI = dyn_cast<DebugValueAddrInst>(ArgUse->getUser())) { getBuilder().createDebugValue(DVAI->getLoc(), NewArg, DVAI->getVarInfo()); break; } } } } else { auto *NewArg = ClonedEntryBB->createArgument(mappedType, OrigArg->getDecl()); ValueMap[OrigArg] = NewArg; } ++I; ++ArgIdx; } BBMap.insert(std::make_pair(OrigEntryBB, ClonedEntryBB)); // Recursively visit original BBs in depth-first preorder, starting with the // entry block, cloning all instructions other than terminators. visitSILBasicBlock(OrigEntryBB); // Now iterate over the BBs and fix up the terminators. for (auto BI = BBMap.begin(), BE = BBMap.end(); BI != BE; ++BI) { getBuilder().setInsertionPoint(BI->second); TermInst *OrigTermInst = BI->first->getTerminator(); if (auto *RI = dyn_cast<ReturnInst>(OrigTermInst)) { SILValue ReturnValue; if (ReturnValueAddr) { // The result is converted from indirect to direct. We have to load the // returned value from the alloc_stack. ReturnValue = getBuilder().createLoad(ReturnValueAddr->getLoc(), ReturnValueAddr, LoadOwnershipQualifier::Unqualified); } for (AllocStackInst *ASI : reverse(AllocStacks)) { getBuilder().createDeallocStack(ASI->getLoc(), ASI); } if (ReturnValue) { getBuilder().createReturn(RI->getLoc(), ReturnValue); continue; } } else if (isa<ThrowInst>(OrigTermInst)) { for (AllocStackInst *ASI : reverse(AllocStacks)) { getBuilder().createDeallocStack(ASI->getLoc(), ASI); } } visit(BI->first->getTerminator()); } }