static void EmitCleanup(CodeGenFunction &CGF, EHScopeStack::Cleanup *Fn, EHScopeStack::Cleanup::Flags flags, llvm::Value *ActiveFlag) { // EH cleanups always occur within a terminate scope. if (flags.isForEHCleanup()) CGF.EHStack.pushTerminate(); // If there's an active flag, load it and skip the cleanup if it's // false. llvm::BasicBlock *ContBB = nullptr; if (ActiveFlag) { ContBB = CGF.createBasicBlock("cleanup.done"); llvm::BasicBlock *CleanupBB = CGF.createBasicBlock("cleanup.action"); llvm::Value *IsActive = CGF.Builder.CreateLoad(ActiveFlag, "cleanup.is_active"); CGF.Builder.CreateCondBr(IsActive, CleanupBB, ContBB); CGF.EmitBlock(CleanupBB); } // Ask the cleanup to emit itself. Fn->Emit(CGF, flags); assert(CGF.HaveInsertPoint() && "cleanup ended with no insertion point?"); // Emit the continuation block if there was an active flag. if (ActiveFlag) CGF.EmitBlock(ContBB); // Leave the terminate scope. if (flags.isForEHCleanup()) CGF.EHStack.popTerminate(); }
static void EmitCleanup(CodeGenFunction &CGF, EHScopeStack::Cleanup *Fn, EHScopeStack::Cleanup::Flags flags, llvm::Value *ActiveFlag) { // Itanium EH cleanups occur within a terminate scope. Microsoft SEH doesn't // have this behavior, and the Microsoft C++ runtime will call terminate for // us if the cleanup throws. bool PushedTerminate = false; if (flags.isForEHCleanup() && !CGF.getTarget().getCXXABI().isMicrosoft()) { CGF.EHStack.pushTerminate(); PushedTerminate = true; } // If there's an active flag, load it and skip the cleanup if it's // false. llvm::BasicBlock *ContBB = nullptr; if (ActiveFlag) { ContBB = CGF.createBasicBlock("cleanup.done"); llvm::BasicBlock *CleanupBB = CGF.createBasicBlock("cleanup.action"); llvm::Value *IsActive = CGF.Builder.CreateLoad(ActiveFlag, "cleanup.is_active"); CGF.Builder.CreateCondBr(IsActive, CleanupBB, ContBB); CGF.EmitBlock(CleanupBB); } // Ask the cleanup to emit itself. Fn->Emit(CGF, flags); assert(CGF.HaveInsertPoint() && "cleanup ended with no insertion point?"); // Emit the continuation block if there was an active flag. if (ActiveFlag) CGF.EmitBlock(ContBB); // Leave the terminate scope. if (PushedTerminate) CGF.EHStack.popTerminate(); }
/// Pops a cleanup block. If the block includes a normal cleanup, the /// current insertion point is threaded through the cleanup, as are /// any branch fixups on the cleanup. void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { assert(!EHStack.empty() && "cleanup stack is empty!"); assert(isa<EHCleanupScope>(*EHStack.begin()) && "top not a cleanup!"); EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.begin()); assert(Scope.getFixupDepth() <= EHStack.getNumBranchFixups()); // Remember activation information. bool IsActive = Scope.isActive(); llvm::Value *NormalActiveFlag = Scope.shouldTestFlagInNormalCleanup() ? Scope.getActiveFlag() : nullptr; llvm::Value *EHActiveFlag = Scope.shouldTestFlagInEHCleanup() ? Scope.getActiveFlag() : nullptr; // Check whether we need an EH cleanup. This is only true if we've // generated a lazy EH cleanup block. llvm::BasicBlock *EHEntry = Scope.getCachedEHDispatchBlock(); assert(Scope.hasEHBranches() == (EHEntry != nullptr)); bool RequiresEHCleanup = (EHEntry != nullptr); EHScopeStack::stable_iterator EHParent = Scope.getEnclosingEHScope(); // Check the three conditions which might require a normal cleanup: // - whether there are branch fix-ups through this cleanup unsigned FixupDepth = Scope.getFixupDepth(); bool HasFixups = EHStack.getNumBranchFixups() != FixupDepth; // - whether there are branch-throughs or branch-afters bool HasExistingBranches = Scope.hasBranches(); // - whether there's a fallthrough llvm::BasicBlock *FallthroughSource = Builder.GetInsertBlock(); bool HasFallthrough = (FallthroughSource != nullptr && IsActive); // Branch-through fall-throughs leave the insertion point set to the // end of the last cleanup, which points to the current scope. The // rest of IR gen doesn't need to worry about this; it only happens // during the execution of PopCleanupBlocks(). bool HasPrebranchedFallthrough = (FallthroughSource && FallthroughSource->getTerminator()); // If this is a normal cleanup, then having a prebranched // fallthrough implies that the fallthrough source unconditionally // jumps here. assert(!Scope.isNormalCleanup() || !HasPrebranchedFallthrough || (Scope.getNormalBlock() && FallthroughSource->getTerminator()->getSuccessor(0) == Scope.getNormalBlock())); bool RequiresNormalCleanup = false; if (Scope.isNormalCleanup() && (HasFixups || HasExistingBranches || HasFallthrough)) { RequiresNormalCleanup = true; } // If we have a prebranched fallthrough into an inactive normal // cleanup, rewrite it so that it leads to the appropriate place. if (Scope.isNormalCleanup() && HasPrebranchedFallthrough && !IsActive) { llvm::BasicBlock *prebranchDest; // If the prebranch is semantically branching through the next // cleanup, just forward it to the next block, leaving the // insertion point in the prebranched block. if (FallthroughIsBranchThrough) { EHScope &enclosing = *EHStack.find(Scope.getEnclosingNormalCleanup()); prebranchDest = CreateNormalEntry(*this, cast<EHCleanupScope>(enclosing)); // Otherwise, we need to make a new block. If the normal cleanup // isn't being used at all, we could actually reuse the normal // entry block, but this is simpler, and it avoids conflicts with // dead optimistic fixup branches. } else { prebranchDest = createBasicBlock("forwarded-prebranch"); EmitBlock(prebranchDest); } llvm::BasicBlock *normalEntry = Scope.getNormalBlock(); assert(normalEntry && !normalEntry->use_empty()); ForwardPrebranchedFallthrough(FallthroughSource, normalEntry, prebranchDest); } // If we don't need the cleanup at all, we're done. if (!RequiresNormalCleanup && !RequiresEHCleanup) { destroyOptimisticNormalEntry(*this, Scope); EHStack.popCleanup(); // safe because there are no fixups assert(EHStack.getNumBranchFixups() == 0 || EHStack.hasNormalCleanups()); return; } // Copy the cleanup emission data out. Note that SmallVector // guarantees maximal alignment for its buffer regardless of its // type parameter. SmallVector<char, 8*sizeof(void*)> CleanupBuffer; CleanupBuffer.reserve(Scope.getCleanupSize()); memcpy(CleanupBuffer.data(), Scope.getCleanupBuffer(), Scope.getCleanupSize()); CleanupBuffer.set_size(Scope.getCleanupSize()); EHScopeStack::Cleanup *Fn = reinterpret_cast<EHScopeStack::Cleanup*>(CleanupBuffer.data()); EHScopeStack::Cleanup::Flags cleanupFlags; if (Scope.isNormalCleanup()) cleanupFlags.setIsNormalCleanupKind(); if (Scope.isEHCleanup()) cleanupFlags.setIsEHCleanupKind(); if (!RequiresNormalCleanup) { destroyOptimisticNormalEntry(*this, Scope); EHStack.popCleanup(); } else { // If we have a fallthrough and no other need for the cleanup, // emit it directly. if (HasFallthrough && !HasPrebranchedFallthrough && !HasFixups && !HasExistingBranches) { destroyOptimisticNormalEntry(*this, Scope); EHStack.popCleanup(); EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag); // Otherwise, the best approach is to thread everything through // the cleanup block and then try to clean up after ourselves. } else { // Force the entry block to exist. llvm::BasicBlock *NormalEntry = CreateNormalEntry(*this, Scope); // I. Set up the fallthrough edge in. CGBuilderTy::InsertPoint savedInactiveFallthroughIP; // If there's a fallthrough, we need to store the cleanup // destination index. For fall-throughs this is always zero. if (HasFallthrough) { if (!HasPrebranchedFallthrough) Builder.CreateStore(Builder.getInt32(0), getNormalCleanupDestSlot()); // Otherwise, save and clear the IP if we don't have fallthrough // because the cleanup is inactive. } else if (FallthroughSource) { assert(!IsActive && "source without fallthrough for active cleanup"); savedInactiveFallthroughIP = Builder.saveAndClearIP(); } // II. Emit the entry block. This implicitly branches to it if // we have fallthrough. All the fixups and existing branches // should already be branched to it. EmitBlock(NormalEntry); // III. Figure out where we're going and build the cleanup // epilogue. bool HasEnclosingCleanups = (Scope.getEnclosingNormalCleanup() != EHStack.stable_end()); // Compute the branch-through dest if we need it: // - if there are branch-throughs threaded through the scope // - if fall-through is a branch-through // - if there are fixups that will be optimistically forwarded // to the enclosing cleanup llvm::BasicBlock *BranchThroughDest = nullptr; if (Scope.hasBranchThroughs() || (FallthroughSource && FallthroughIsBranchThrough) || (HasFixups && HasEnclosingCleanups)) { assert(HasEnclosingCleanups); EHScope &S = *EHStack.find(Scope.getEnclosingNormalCleanup()); BranchThroughDest = CreateNormalEntry(*this, cast<EHCleanupScope>(S)); } llvm::BasicBlock *FallthroughDest = nullptr; SmallVector<llvm::Instruction*, 2> InstsToAppend; // If there's exactly one branch-after and no other threads, // we can route it without a switch. if (!Scope.hasBranchThroughs() && !HasFixups && !HasFallthrough && Scope.getNumBranchAfters() == 1) { assert(!BranchThroughDest || !IsActive); // TODO: clean up the possibly dead stores to the cleanup dest slot. llvm::BasicBlock *BranchAfter = Scope.getBranchAfterBlock(0); InstsToAppend.push_back(llvm::BranchInst::Create(BranchAfter)); // Build a switch-out if we need it: // - if there are branch-afters threaded through the scope // - if fall-through is a branch-after // - if there are fixups that have nowhere left to go and // so must be immediately resolved } else if (Scope.getNumBranchAfters() || (HasFallthrough && !FallthroughIsBranchThrough) || (HasFixups && !HasEnclosingCleanups)) { llvm::BasicBlock *Default = (BranchThroughDest ? BranchThroughDest : getUnreachableBlock()); // TODO: base this on the number of branch-afters and fixups const unsigned SwitchCapacity = 10; llvm::LoadInst *Load = new llvm::LoadInst(getNormalCleanupDestSlot(), "cleanup.dest"); llvm::SwitchInst *Switch = llvm::SwitchInst::Create(Load, Default, SwitchCapacity); InstsToAppend.push_back(Load); InstsToAppend.push_back(Switch); // Branch-after fallthrough. if (FallthroughSource && !FallthroughIsBranchThrough) { FallthroughDest = createBasicBlock("cleanup.cont"); if (HasFallthrough) Switch->addCase(Builder.getInt32(0), FallthroughDest); } for (unsigned I = 0, E = Scope.getNumBranchAfters(); I != E; ++I) { Switch->addCase(Scope.getBranchAfterIndex(I), Scope.getBranchAfterBlock(I)); } // If there aren't any enclosing cleanups, we can resolve all // the fixups now. if (HasFixups && !HasEnclosingCleanups) ResolveAllBranchFixups(*this, Switch, NormalEntry); } else { // We should always have a branch-through destination in this case. assert(BranchThroughDest); InstsToAppend.push_back(llvm::BranchInst::Create(BranchThroughDest)); } // IV. Pop the cleanup and emit it. EHStack.popCleanup(); assert(EHStack.hasNormalCleanups() == HasEnclosingCleanups); EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag); // Append the prepared cleanup prologue from above. llvm::BasicBlock *NormalExit = Builder.GetInsertBlock(); for (unsigned I = 0, E = InstsToAppend.size(); I != E; ++I) NormalExit->getInstList().push_back(InstsToAppend[I]); // Optimistically hope that any fixups will continue falling through. for (unsigned I = FixupDepth, E = EHStack.getNumBranchFixups(); I < E; ++I) { BranchFixup &Fixup = EHStack.getBranchFixup(I); if (!Fixup.Destination) continue; if (!Fixup.OptimisticBranchBlock) { new llvm::StoreInst(Builder.getInt32(Fixup.DestinationIndex), getNormalCleanupDestSlot(), Fixup.InitialBranch); Fixup.InitialBranch->setSuccessor(0, NormalEntry); } Fixup.OptimisticBranchBlock = NormalExit; } // V. Set up the fallthrough edge out. // Case 1: a fallthrough source exists but doesn't branch to the // cleanup because the cleanup is inactive. if (!HasFallthrough && FallthroughSource) { // Prebranched fallthrough was forwarded earlier. // Non-prebranched fallthrough doesn't need to be forwarded. // Either way, all we need to do is restore the IP we cleared before. assert(!IsActive); Builder.restoreIP(savedInactiveFallthroughIP); // Case 2: a fallthrough source exists and should branch to the // cleanup, but we're not supposed to branch through to the next // cleanup. } else if (HasFallthrough && FallthroughDest) { assert(!FallthroughIsBranchThrough); EmitBlock(FallthroughDest); // Case 3: a fallthrough source exists and should branch to the // cleanup and then through to the next. } else if (HasFallthrough) { // Everything is already set up for this. // Case 4: no fallthrough source exists. } else { Builder.ClearInsertionPoint(); } // VI. Assorted cleaning. // Check whether we can merge NormalEntry into a single predecessor. // This might invalidate (non-IR) pointers to NormalEntry. llvm::BasicBlock *NewNormalEntry = SimplifyCleanupEntry(*this, NormalEntry); // If it did invalidate those pointers, and NormalEntry was the same // as NormalExit, go back and patch up the fixups. if (NewNormalEntry != NormalEntry && NormalEntry == NormalExit) for (unsigned I = FixupDepth, E = EHStack.getNumBranchFixups(); I < E; ++I) EHStack.getBranchFixup(I).OptimisticBranchBlock = NewNormalEntry; } } assert(EHStack.hasNormalCleanups() || EHStack.getNumBranchFixups() == 0); // Emit the EH cleanup if required. if (RequiresEHCleanup) { ApplyDebugLocation AutoRestoreLocation(*this, CurEHLocation); CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP(); EmitBlock(EHEntry); // We only actually emit the cleanup code if the cleanup is either // active or was used before it was deactivated. if (EHActiveFlag || IsActive) { cleanupFlags.setIsForEHCleanup(); EmitCleanup(*this, Fn, cleanupFlags, EHActiveFlag); } Builder.CreateBr(getEHDispatchBlock(EHParent)); Builder.restoreIP(SavedIP); SimplifyCleanupEntry(*this, EHEntry); } }