void CodeGenFunction::EmitBranchThroughEHCleanup(UnwindDest Dest) { // We should never get invalid scope depths for an UnwindDest; that // implies that the destination wasn't set up correctly. assert(Dest.getScopeDepth().isValid() && "invalid scope depth on EH dest?"); if (!HaveInsertPoint()) return; // Create the branch. llvm::BranchInst *BI = Builder.CreateBr(Dest.getBlock()); // Calculate the innermost active cleanup. EHScopeStack::stable_iterator InnermostCleanup = EHStack.getInnermostActiveEHCleanup(); // If the destination is in the same EH cleanup scope as us, we // don't need to thread through anything. if (InnermostCleanup.encloses(Dest.getScopeDepth())) { Builder.ClearInsertionPoint(); return; } assert(InnermostCleanup != EHStack.stable_end()); // Store the index at the start. llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex()); new llvm::StoreInst(Index, getEHCleanupDestSlot(), BI); // Adjust BI to point to the first cleanup block. { EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(InnermostCleanup)); BI->setSuccessor(0, CreateEHEntry(*this, Scope)); } // Add this destination to all the scopes involved. for (EHScopeStack::stable_iterator I = InnermostCleanup, E = Dest.getScopeDepth(); ; ) { assert(E.strictlyEncloses(I)); EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(I)); assert(Scope.isEHCleanup()); I = Scope.getEnclosingEHCleanup(); // If this is the last cleanup we're propagating through, add this // as a branch-after. if (I == E) { Scope.addEHBranchAfter(Index, Dest.getBlock()); break; } // Otherwise, add it as a branch-through. If this isn't new // information, all the rest of the work has been done before. if (!Scope.addEHBranchThrough(Dest.getBlock())) break; } Builder.ClearInsertionPoint(); }
/// Pops cleanup blocks until the given savepoint is reached. void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old) { assert(Old.isValid()); while (EHStack.stable_begin() != Old) { EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.begin()); // As long as Old strictly encloses the scope's enclosing normal // cleanup, we're going to emit another normal cleanup which // fallthrough can propagate through. bool FallThroughIsBranchThrough = Old.strictlyEncloses(Scope.getEnclosingNormalCleanup()); PopCleanupBlock(FallThroughIsBranchThrough); } }
/// isObviouslyBranchWithoutCleanups - Return true if a branch to the /// specified destination obviously has no cleanups to run. 'false' is always /// a conservatively correct answer for this method. bool CodeGenFunction::isObviouslyBranchWithoutCleanups(JumpDest Dest) const { assert(Dest.getScopeDepth().encloses(EHStack.stable_begin()) && "stale jump destination"); // Calculate the innermost active normal cleanup. EHScopeStack::stable_iterator TopCleanup = EHStack.getInnermostActiveNormalCleanup(); // If we're not in an active normal cleanup scope, or if the // destination scope is within the innermost active normal cleanup // scope, we don't need to worry about fixups. if (TopCleanup == EHStack.stable_end() || TopCleanup.encloses(Dest.getScopeDepth())) // works for invalid return true; // Otherwise, we might need some cleanups. return false; }
static bool IsUsedAsNormalCleanup(EHScopeStack &EHStack, EHScopeStack::stable_iterator C) { // If we needed a normal block for any reason, that counts. if (cast<EHCleanupScope>(*EHStack.find(C)).getNormalBlock()) return true; // Check whether any enclosed cleanups were needed. for (EHScopeStack::stable_iterator I = EHStack.getInnermostNormalCleanup(); I != C; ) { assert(C.strictlyEncloses(I)); EHCleanupScope &S = cast<EHCleanupScope>(*EHStack.find(I)); if (S.getNormalBlock()) return true; I = S.getEnclosingNormalCleanup(); } return false; }
static bool IsUsedAsEHCleanup(EHScopeStack &EHStack, EHScopeStack::stable_iterator cleanup) { // If we needed an EH block for any reason, that counts. if (EHStack.find(cleanup)->hasEHBranches()) return true; // Check whether any enclosed cleanups were needed. for (EHScopeStack::stable_iterator i = EHStack.getInnermostEHScope(); i != cleanup; ) { assert(cleanup.strictlyEncloses(i)); EHScope &scope = *EHStack.find(i); if (scope.hasEHBranches()) return true; i = scope.getEnclosingEHScope(); } return false; }
/// Terminate the current block by emitting a branch which might leave /// the current cleanup-protected scope. The target scope may not yet /// be known, in which case this will require a fixup. /// /// As a side-effect, this method clears the insertion point. void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) { assert(Dest.getScopeDepth().encloses(EHStack.stable_begin()) && "stale jump destination"); if (!HaveInsertPoint()) return; // Create the branch. llvm::BranchInst *BI = Builder.CreateBr(Dest.getBlock()); // Calculate the innermost active normal cleanup. EHScopeStack::stable_iterator TopCleanup = EHStack.getInnermostActiveNormalCleanup(); // If we're not in an active normal cleanup scope, or if the // destination scope is within the innermost active normal cleanup // scope, we don't need to worry about fixups. if (TopCleanup == EHStack.stable_end() || TopCleanup.encloses(Dest.getScopeDepth())) { // works for invalid Builder.ClearInsertionPoint(); return; } // If we can't resolve the destination cleanup scope, just add this // to the current cleanup scope as a branch fixup. if (!Dest.getScopeDepth().isValid()) { BranchFixup &Fixup = EHStack.addBranchFixup(); Fixup.Destination = Dest.getBlock(); Fixup.DestinationIndex = Dest.getDestIndex(); Fixup.InitialBranch = BI; Fixup.OptimisticBranchBlock = nullptr; Builder.ClearInsertionPoint(); return; } // Otherwise, thread through all the normal cleanups in scope. // Store the index at the start. llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex()); new llvm::StoreInst(Index, getNormalCleanupDestSlot(), BI); // Adjust BI to point to the first cleanup block. { EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(TopCleanup)); BI->setSuccessor(0, CreateNormalEntry(*this, Scope)); } // Add this destination to all the scopes involved. EHScopeStack::stable_iterator I = TopCleanup; EHScopeStack::stable_iterator E = Dest.getScopeDepth(); if (E.strictlyEncloses(I)) { while (true) { EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(I)); assert(Scope.isNormalCleanup()); I = Scope.getEnclosingNormalCleanup(); // If this is the last cleanup we're propagating through, tell it // that there's a resolved jump moving through it. if (!E.strictlyEncloses(I)) { Scope.addBranchAfter(Index, Dest.getBlock()); break; } // Otherwise, tell the scope that there's a jump propoagating // through it. If this isn't new information, all the rest of // the work has been done before. if (!Scope.addBranchThrough(Dest.getBlock())) break; } } Builder.ClearInsertionPoint(); }
/// Activate a cleanup that was created in an inactivated state. void CodeGenFunction::ActivateCleanup(EHScopeStack::stable_iterator C) { assert(C != EHStack.stable_end() && "activating bottom of stack?"); EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(C)); assert(!Scope.isActive() && "double activation"); // Calculate whether the cleanup was used: bool Used = false; // - as a normal cleanup if (Scope.isNormalCleanup()) { bool NormalUsed = false; if (Scope.getNormalBlock()) { NormalUsed = true; } else { // Check whether any enclosed cleanups were needed. for (EHScopeStack::stable_iterator I = EHStack.getInnermostNormalCleanup(); I != C; ) { assert(C.strictlyEncloses(I)); EHCleanupScope &S = cast<EHCleanupScope>(*EHStack.find(I)); if (S.getNormalBlock()) { NormalUsed = true; break; } I = S.getEnclosingNormalCleanup(); } } if (NormalUsed) Used = true; else Scope.setActivatedBeforeNormalUse(true); } // - as an EH cleanup if (Scope.isEHCleanup()) { bool EHUsed = false; if (Scope.getEHBlock()) { EHUsed = true; } else { // Check whether any enclosed cleanups were needed. for (EHScopeStack::stable_iterator I = EHStack.getInnermostEHCleanup(); I != C; ) { assert(C.strictlyEncloses(I)); EHCleanupScope &S = cast<EHCleanupScope>(*EHStack.find(I)); if (S.getEHBlock()) { EHUsed = true; break; } I = S.getEnclosingEHCleanup(); } } if (EHUsed) Used = true; else Scope.setActivatedBeforeEHUse(true); } llvm::AllocaInst *Var = EHCleanupScope::activeSentinel(); if (Used) { Var = CreateTempAlloca(Builder.getInt1Ty()); InitTempAlloca(Var, Builder.getFalse()); } Scope.setActiveVar(Var); }