#include "CodeGenFunction.h"
#include "CGCleanup.h"
using namespace clang;
using namespace CodeGen;
bool DominatingValue<RValue>::saved_type::needsSaving(RValue rv) {
if (rv.isScalar())
return DominatingLLVMValue::needsSaving(rv.getScalarVal());
if (rv.isAggregate())
return DominatingLLVMValue::needsSaving(rv.getAggregateAddr());
return true;
}
DominatingValue<RValue>::saved_type
DominatingValue<RValue>::saved_type::save(CodeGenFunction &CGF, RValue rv) {
if (rv.isScalar()) {
llvm::Value *V = rv.getScalarVal();
if (!DominatingLLVMValue::needsSaving(V))
return saved_type(V, ScalarLiteral);
llvm::Value *addr = CGF.CreateTempAlloca(V->getType(), "saved-rvalue");
CGF.Builder.CreateStore(V, addr);
return saved_type(addr, ScalarAddress);
}
if (rv.isComplex()) {
CodeGenFunction::ComplexPairTy V = rv.getComplexVal();
llvm::Type *ComplexTy =
llvm::StructType::get(V.first->getType(), V.second->getType(),
(void*) 0);
llvm::Value *addr = CGF.CreateTempAlloca(ComplexTy, "saved-complex");
CGF.StoreComplexToAddr(V, addr, false);
return saved_type(addr, ComplexAddress);
}
assert(rv.isAggregate());
llvm::Value *V = rv.getAggregateAddr(); if (!DominatingLLVMValue::needsSaving(V))
return saved_type(V, AggregateLiteral);
llvm::Value *addr = CGF.CreateTempAlloca(V->getType(), "saved-rvalue");
CGF.Builder.CreateStore(V, addr);
return saved_type(addr, AggregateAddress);
}
RValue DominatingValue<RValue>::saved_type::restore(CodeGenFunction &CGF) {
switch (K) {
case ScalarLiteral:
return RValue::get(Value);
case ScalarAddress:
return RValue::get(CGF.Builder.CreateLoad(Value));
case AggregateLiteral:
return RValue::getAggregate(Value);
case AggregateAddress:
return RValue::getAggregate(CGF.Builder.CreateLoad(Value));
case ComplexAddress:
return RValue::getComplex(CGF.LoadComplexFromAddr(Value, false));
}
llvm_unreachable("bad saved r-value kind");
}
char *EHScopeStack::allocate(size_t Size) {
if (!StartOfBuffer) {
unsigned Capacity = 1024;
while (Capacity < Size) Capacity *= 2;
StartOfBuffer = new char[Capacity];
StartOfData = EndOfBuffer = StartOfBuffer + Capacity;
} else if (static_cast<size_t>(StartOfData - StartOfBuffer) < Size) {
unsigned CurrentCapacity = EndOfBuffer - StartOfBuffer;
unsigned UsedCapacity = CurrentCapacity - (StartOfData - StartOfBuffer);
unsigned NewCapacity = CurrentCapacity;
do {
NewCapacity *= 2;
} while (NewCapacity < UsedCapacity + Size);
char *NewStartOfBuffer = new char[NewCapacity];
char *NewEndOfBuffer = NewStartOfBuffer + NewCapacity;
char *NewStartOfData = NewEndOfBuffer - UsedCapacity;
memcpy(NewStartOfData, StartOfData, UsedCapacity);
delete [] StartOfBuffer;
StartOfBuffer = NewStartOfBuffer;
EndOfBuffer = NewEndOfBuffer;
StartOfData = NewStartOfData;
}
assert(StartOfBuffer + Size <= StartOfData);
StartOfData -= Size;
return StartOfData;
}
EHScopeStack::stable_iterator
EHScopeStack::getInnermostActiveNormalCleanup() const {
for (stable_iterator si = getInnermostNormalCleanup(), se = stable_end();
si != se; ) {
EHCleanupScope &cleanup = cast<EHCleanupScope>(*find(si));
if (cleanup.isActive()) return si;
si = cleanup.getEnclosingNormalCleanup();
}
return stable_end();
}
EHScopeStack::stable_iterator EHScopeStack::getInnermostActiveEHScope() const {
for (stable_iterator si = getInnermostEHScope(), se = stable_end();
si != se; ) {
EHCleanupScope *cleanup = dyn_cast<EHCleanupScope>(&*find(si));
if (cleanup && !cleanup->isActive()) {
si = cleanup->getEnclosingEHScope();
continue;
}
return si;
}
return stable_end();
}
void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) {
assert(((Size % sizeof(void*)) == 0) && "cleanup type is misaligned");
char *Buffer = allocate(EHCleanupScope::getSizeForCleanupSize(Size));
bool IsNormalCleanup = Kind & NormalCleanup;
bool IsEHCleanup = Kind & EHCleanup;
bool IsActive = !(Kind & InactiveCleanup);
EHCleanupScope *Scope =
new (Buffer) EHCleanupScope(IsNormalCleanup,
IsEHCleanup,
IsActive,
Size,
BranchFixups.size(),
InnermostNormalCleanup,
InnermostEHScope);
if (IsNormalCleanup)
InnermostNormalCleanup = stable_begin();
if (IsEHCleanup)
InnermostEHScope = stable_begin();
return Scope->getCleanupBuffer();
}
void EHScopeStack::popCleanup() {
assert(!empty() && "popping exception stack when not empty");
assert(isa<EHCleanupScope>(*begin()));
EHCleanupScope &Cleanup = cast<EHCleanupScope>(*begin());
InnermostNormalCleanup = Cleanup.getEnclosingNormalCleanup();
InnermostEHScope = Cleanup.getEnclosingEHScope();
StartOfData += Cleanup.getAllocatedSize();
Cleanup.~EHCleanupScope();
if (!BranchFixups.empty()) {
if (!hasNormalCleanups())
BranchFixups.clear();
else
popNullFixups();
}
}
EHFilterScope *EHScopeStack::pushFilter(unsigned numFilters) {
assert(getInnermostEHScope() == stable_end());
char *buffer = allocate(EHFilterScope::getSizeForNumFilters(numFilters));
EHFilterScope *filter = new (buffer) EHFilterScope(numFilters);
InnermostEHScope = stable_begin();
return filter;
}
void EHScopeStack::popFilter() {
assert(!empty() && "popping exception stack when not empty");
EHFilterScope &filter = cast<EHFilterScope>(*begin());
StartOfData += EHFilterScope::getSizeForNumFilters(filter.getNumFilters());
InnermostEHScope = filter.getEnclosingEHScope();
}
EHCatchScope *EHScopeStack::pushCatch(unsigned numHandlers) {
char *buffer = allocate(EHCatchScope::getSizeForNumHandlers(numHandlers));
EHCatchScope *scope =
new (buffer) EHCatchScope(numHandlers, InnermostEHScope);
InnermostEHScope = stable_begin();
return scope;
}
void EHScopeStack::pushTerminate() {
char *Buffer = allocate(EHTerminateScope::getSize());
new (Buffer) EHTerminateScope(InnermostEHScope);
InnermostEHScope = stable_begin();
}
void EHScopeStack::popNullFixups() {
assert(hasNormalCleanups());
EHScopeStack::iterator it = find(InnermostNormalCleanup);
unsigned MinSize = cast<EHCleanupScope>(*it).getFixupDepth();
assert(BranchFixups.size() >= MinSize && "fixup stack out of order");
while (BranchFixups.size() > MinSize &&
BranchFixups.back().Destination == 0)
BranchFixups.pop_back();
}
void CodeGenFunction::initFullExprCleanup() {
llvm::AllocaInst *active
= CreateTempAlloca(Builder.getInt1Ty(), "cleanup.cond");
setBeforeOutermostConditional(Builder.getFalse(), active);
Builder.CreateStore(Builder.getTrue(), active);
EHCleanupScope &cleanup = cast<EHCleanupScope>(*EHStack.begin());
assert(cleanup.getActiveFlag() == 0 && "cleanup already has active flag?");
cleanup.setActiveFlag(active);
if (cleanup.isNormalCleanup()) cleanup.setTestFlagInNormalCleanup();
if (cleanup.isEHCleanup()) cleanup.setTestFlagInEHCleanup();
}
void EHScopeStack::Cleanup::anchor() {}
static void ResolveAllBranchFixups(CodeGenFunction &CGF,
llvm::SwitchInst *Switch,
llvm::BasicBlock *CleanupEntry) {
llvm::SmallPtrSet<llvm::BasicBlock*, 4> CasesAdded;
for (unsigned I = 0, E = CGF.EHStack.getNumBranchFixups(); I != E; ++I) {
BranchFixup &Fixup = CGF.EHStack.getBranchFixup(I);
if (Fixup.Destination == 0) continue;
if (Fixup.OptimisticBranchBlock == 0) {
new llvm::StoreInst(CGF.Builder.getInt32(Fixup.DestinationIndex),
CGF.getNormalCleanupDestSlot(),
Fixup.InitialBranch);
Fixup.InitialBranch->setSuccessor(0, CleanupEntry);
}
if (!CasesAdded.insert(Fixup.Destination)) continue;
Switch->addCase(CGF.Builder.getInt32(Fixup.DestinationIndex),
Fixup.Destination);
}
CGF.EHStack.clearFixups();
}
static llvm::SwitchInst *TransitionToCleanupSwitch(CodeGenFunction &CGF,
llvm::BasicBlock *Block) {
llvm::TerminatorInst *Term = Block->getTerminator();
assert(Term && "can't transition block without terminator");
if (llvm::BranchInst *Br = dyn_cast<llvm::BranchInst>(Term)) {
assert(Br->isUnconditional());
llvm::LoadInst *Load =
new llvm::LoadInst(CGF.getNormalCleanupDestSlot(), "cleanup.dest", Term);
llvm::SwitchInst *Switch =
llvm::SwitchInst::Create(Load, Br->getSuccessor(0), 4, Block);
Br->eraseFromParent();
return Switch;
} else {
return cast<llvm::SwitchInst>(Term);
}
}
void CodeGenFunction::ResolveBranchFixups(llvm::BasicBlock *Block) {
assert(Block && "resolving a null target block");
if (!EHStack.getNumBranchFixups()) return;
assert(EHStack.hasNormalCleanups() &&
"branch fixups exist with no normal cleanups on stack");
llvm::SmallPtrSet<llvm::BasicBlock*, 4> ModifiedOptimisticBlocks;
bool ResolvedAny = false;
for (unsigned I = 0, E = EHStack.getNumBranchFixups(); I != E; ++I) {
BranchFixup &Fixup = EHStack.getBranchFixup(I);
if (Fixup.Destination != Block) continue;
Fixup.Destination = 0;
ResolvedAny = true;
llvm::BasicBlock *BranchBB = Fixup.OptimisticBranchBlock;
if (!BranchBB)
continue;
if (!ModifiedOptimisticBlocks.insert(BranchBB))
continue;
llvm::SwitchInst *Switch = TransitionToCleanupSwitch(*this, BranchBB);
Switch->addCase(Builder.getInt32(Fixup.DestinationIndex), Block);
}
if (ResolvedAny)
EHStack.popNullFixups();
}
void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old) {
assert(Old.isValid());
while (EHStack.stable_begin() != Old) {
EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.begin());
bool FallThroughIsBranchThrough =
Old.strictlyEncloses(Scope.getEnclosingNormalCleanup());
PopCleanupBlock(FallThroughIsBranchThrough);
}
}
static llvm::BasicBlock *CreateNormalEntry(CodeGenFunction &CGF,
EHCleanupScope &Scope) {
assert(Scope.isNormalCleanup());
llvm::BasicBlock *Entry = Scope.getNormalBlock();
if (!Entry) {
Entry = CGF.createBasicBlock("cleanup");
Scope.setNormalBlock(Entry);
}
return Entry;
}
static llvm::BasicBlock *SimplifyCleanupEntry(CodeGenFunction &CGF,
llvm::BasicBlock *Entry) {
llvm::BasicBlock *Pred = Entry->getSinglePredecessor();
if (!Pred) return Entry;
llvm::BranchInst *Br = dyn_cast<llvm::BranchInst>(Pred->getTerminator());
if (!Br || Br->isConditional()) return Entry;
assert(Br->getSuccessor(0) == Entry);
bool WasInsertBlock = CGF.Builder.GetInsertBlock() == Entry;
assert(!WasInsertBlock || CGF.Builder.GetInsertPoint() == Entry->end());
Br->eraseFromParent();
Entry->replaceAllUsesWith(Pred);
Pred->getInstList().splice(Pred->end(), Entry->getInstList());
Entry->eraseFromParent();
if (WasInsertBlock)
CGF.Builder.SetInsertPoint(Pred);
return Pred;
}
static void EmitCleanup(CodeGenFunction &CGF,
EHScopeStack::Cleanup *Fn,
EHScopeStack::Cleanup::Flags flags,
llvm::Value *ActiveFlag) {
if (flags.isForEHCleanup()) CGF.EHStack.pushTerminate();
llvm::BasicBlock *ContBB = 0;
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);
}
Fn->Emit(CGF, flags);
assert(CGF.HaveInsertPoint() && "cleanup ended with no insertion point?");
if (ActiveFlag)
CGF.EmitBlock(ContBB);
if (flags.isForEHCleanup()) CGF.EHStack.popTerminate();
}
static void ForwardPrebranchedFallthrough(llvm::BasicBlock *Exit,
llvm::BasicBlock *From,
llvm::BasicBlock *To) {
llvm::TerminatorInst *Term = Exit->getTerminator();
if (llvm::BranchInst *Br = dyn_cast<llvm::BranchInst>(Term)) {
assert(Br->isUnconditional() && Br->getSuccessor(0) == From);
Br->setSuccessor(0, To);
} else {
llvm::SwitchInst *Switch = cast<llvm::SwitchInst>(Term);
for (unsigned I = 0, E = Switch->getNumSuccessors(); I != E; ++I)
if (Switch->getSuccessor(I) == From)
Switch->setSuccessor(I, To);
}
}
static void destroyOptimisticNormalEntry(CodeGenFunction &CGF,
EHCleanupScope &scope) {
llvm::BasicBlock *entry = scope.getNormalBlock();
if (!entry) return;
llvm::BasicBlock *unreachableBB = CGF.getUnreachableBlock();
for (llvm::BasicBlock::use_iterator
i = entry->use_begin(), e = entry->use_end(); i != e; ) {
llvm::Use &use = i.getUse();
++i;
use.set(unreachableBB);
llvm::SwitchInst *si = cast<llvm::SwitchInst>(use.getUser());
if (si->getNumCases() == 1 && si->getDefaultDest() == unreachableBB) {
llvm::BranchInst::Create(si->case_begin().getCaseSuccessor(), si);
llvm::LoadInst *condition = cast<llvm::LoadInst>(si->getCondition());
si->eraseFromParent();
assert(condition->getOperand(0) == CGF.NormalCleanupDest);
assert(condition->use_empty());
condition->eraseFromParent();
}
}
assert(entry->use_empty());
delete entry;
}
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());
bool IsActive = Scope.isActive();
llvm::Value *NormalActiveFlag =
Scope.shouldTestFlagInNormalCleanup() ? Scope.getActiveFlag() : 0;
llvm::Value *EHActiveFlag =
Scope.shouldTestFlagInEHCleanup() ? Scope.getActiveFlag() : 0;
llvm::BasicBlock *EHEntry = Scope.getCachedEHDispatchBlock();
assert(Scope.hasEHBranches() == (EHEntry != 0));
bool RequiresEHCleanup = (EHEntry != 0);
EHScopeStack::stable_iterator EHParent = Scope.getEnclosingEHScope();
unsigned FixupDepth = Scope.getFixupDepth();
bool HasFixups = EHStack.getNumBranchFixups() != FixupDepth;
bool HasExistingBranches = Scope.hasBranches();
llvm::BasicBlock *FallthroughSource = Builder.GetInsertBlock();
bool HasFallthrough = (FallthroughSource != 0 && IsActive);
bool HasPrebranchedFallthrough =
(FallthroughSource && FallthroughSource->getTerminator());
assert(!Scope.isNormalCleanup() || !HasPrebranchedFallthrough ||
(Scope.getNormalBlock() &&
FallthroughSource->getTerminator()->getSuccessor(0)
== Scope.getNormalBlock()));
bool RequiresNormalCleanup = false;
if (Scope.isNormalCleanup() &&
(HasFixups || HasExistingBranches || HasFallthrough)) {
RequiresNormalCleanup = true;
}
if (Scope.isNormalCleanup() && HasPrebranchedFallthrough && !IsActive) {
llvm::BasicBlock *prebranchDest;
if (FallthroughIsBranchThrough) {
EHScope &enclosing = *EHStack.find(Scope.getEnclosingNormalCleanup());
prebranchDest = CreateNormalEntry(*this, cast<EHCleanupScope>(enclosing));
} else {
prebranchDest = createBasicBlock("forwarded-prebranch");
EmitBlock(prebranchDest);
}
llvm::BasicBlock *normalEntry = Scope.getNormalBlock();
assert(normalEntry && !normalEntry->use_empty());
ForwardPrebranchedFallthrough(FallthroughSource,
normalEntry, prebranchDest);
}
if (!RequiresNormalCleanup && !RequiresEHCleanup) {
destroyOptimisticNormalEntry(*this, Scope);
EHStack.popCleanup(); assert(EHStack.getNumBranchFixups() == 0 ||
EHStack.hasNormalCleanups());
return;
}
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 (HasFallthrough && !HasPrebranchedFallthrough &&
!HasFixups && !HasExistingBranches) {
destroyOptimisticNormalEntry(*this, Scope);
EHStack.popCleanup();
EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag);
} else {
llvm::BasicBlock *NormalEntry = CreateNormalEntry(*this, Scope);
CGBuilderTy::InsertPoint savedInactiveFallthroughIP;
if (HasFallthrough) {
if (!HasPrebranchedFallthrough)
Builder.CreateStore(Builder.getInt32(0), getNormalCleanupDestSlot());
} else if (FallthroughSource) {
assert(!IsActive && "source without fallthrough for active cleanup");
savedInactiveFallthroughIP = Builder.saveAndClearIP();
}
EmitBlock(NormalEntry);
bool HasEnclosingCleanups =
(Scope.getEnclosingNormalCleanup() != EHStack.stable_end());
llvm::BasicBlock *BranchThroughDest = 0;
if (Scope.hasBranchThroughs() ||
(FallthroughSource && FallthroughIsBranchThrough) ||
(HasFixups && HasEnclosingCleanups)) {
assert(HasEnclosingCleanups);
EHScope &S = *EHStack.find(Scope.getEnclosingNormalCleanup());
BranchThroughDest = CreateNormalEntry(*this, cast<EHCleanupScope>(S));
}
llvm::BasicBlock *FallthroughDest = 0;
SmallVector<llvm::Instruction*, 2> InstsToAppend;
if (!Scope.hasBranchThroughs() && !HasFixups && !HasFallthrough &&
Scope.getNumBranchAfters() == 1) {
assert(!BranchThroughDest || !IsActive);
llvm::BasicBlock *BranchAfter = Scope.getBranchAfterBlock(0);
InstsToAppend.push_back(llvm::BranchInst::Create(BranchAfter));
} else if (Scope.getNumBranchAfters() ||
(HasFallthrough && !FallthroughIsBranchThrough) ||
(HasFixups && !HasEnclosingCleanups)) {
llvm::BasicBlock *Default =
(BranchThroughDest ? BranchThroughDest : getUnreachableBlock());
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);
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 (HasFixups && !HasEnclosingCleanups)
ResolveAllBranchFixups(*this, Switch, NormalEntry);
} else {
assert(BranchThroughDest);
InstsToAppend.push_back(llvm::BranchInst::Create(BranchThroughDest));
}
EHStack.popCleanup();
assert(EHStack.hasNormalCleanups() == HasEnclosingCleanups);
EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag);
llvm::BasicBlock *NormalExit = Builder.GetInsertBlock();
for (unsigned I = 0, E = InstsToAppend.size(); I != E; ++I)
NormalExit->getInstList().push_back(InstsToAppend[I]);
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;
}
if (!HasFallthrough && FallthroughSource) {
assert(!IsActive);
Builder.restoreIP(savedInactiveFallthroughIP);
} else if (HasFallthrough && FallthroughDest) {
assert(!FallthroughIsBranchThrough);
EmitBlock(FallthroughDest);
} else if (HasFallthrough) {
} else {
Builder.ClearInsertionPoint();
}
llvm::BasicBlock *NewNormalEntry =
SimplifyCleanupEntry(*this, NormalEntry);
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);
if (RequiresEHCleanup) {
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
EmitBlock(EHEntry);
if (EHActiveFlag || IsActive) {
cleanupFlags.setIsForEHCleanup();
EmitCleanup(*this, Fn, cleanupFlags, EHActiveFlag);
}
Builder.CreateBr(getEHDispatchBlock(EHParent));
Builder.restoreIP(SavedIP);
SimplifyCleanupEntry(*this, EHEntry);
}
}
bool CodeGenFunction::isObviouslyBranchWithoutCleanups(JumpDest Dest) const {
assert(Dest.getScopeDepth().encloses(EHStack.stable_begin())
&& "stale jump destination");
EHScopeStack::stable_iterator TopCleanup =
EHStack.getInnermostActiveNormalCleanup();
if (TopCleanup == EHStack.stable_end() ||
TopCleanup.encloses(Dest.getScopeDepth())) return true;
return false;
}
void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) {
assert(Dest.getScopeDepth().encloses(EHStack.stable_begin())
&& "stale jump destination");
if (!HaveInsertPoint())
return;
llvm::BranchInst *BI = Builder.CreateBr(Dest.getBlock());
EHScopeStack::stable_iterator
TopCleanup = EHStack.getInnermostActiveNormalCleanup();
if (TopCleanup == EHStack.stable_end() ||
TopCleanup.encloses(Dest.getScopeDepth())) { Builder.ClearInsertionPoint();
return;
}
if (!Dest.getScopeDepth().isValid()) {
BranchFixup &Fixup = EHStack.addBranchFixup();
Fixup.Destination = Dest.getBlock();
Fixup.DestinationIndex = Dest.getDestIndex();
Fixup.InitialBranch = BI;
Fixup.OptimisticBranchBlock = 0;
Builder.ClearInsertionPoint();
return;
}
llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex());
new llvm::StoreInst(Index, getNormalCleanupDestSlot(), BI);
{
EHCleanupScope &Scope =
cast<EHCleanupScope>(*EHStack.find(TopCleanup));
BI->setSuccessor(0, CreateNormalEntry(*this, Scope));
}
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 (!E.strictlyEncloses(I)) {
Scope.addBranchAfter(Index, Dest.getBlock());
break;
}
if (!Scope.addBranchThrough(Dest.getBlock()))
break;
}
}
Builder.ClearInsertionPoint();
}
static bool IsUsedAsNormalCleanup(EHScopeStack &EHStack,
EHScopeStack::stable_iterator C) {
if (cast<EHCleanupScope>(*EHStack.find(C)).getNormalBlock())
return true;
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 (EHStack.find(cleanup)->hasEHBranches())
return true;
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;
}
enum ForActivation_t {
ForActivation,
ForDeactivation
};
static void SetupCleanupBlockActivation(CodeGenFunction &CGF,
EHScopeStack::stable_iterator C,
ForActivation_t kind,
llvm::Instruction *dominatingIP) {
EHCleanupScope &Scope = cast<EHCleanupScope>(*CGF.EHStack.find(C));
bool isActivatedInConditional =
(kind == ForActivation && CGF.isInConditionalBranch());
bool needFlag = false;
if (Scope.isNormalCleanup() &&
(isActivatedInConditional || IsUsedAsNormalCleanup(CGF.EHStack, C))) {
Scope.setTestFlagInNormalCleanup();
needFlag = true;
}
if (Scope.isEHCleanup() &&
(isActivatedInConditional || IsUsedAsEHCleanup(CGF.EHStack, C))) {
Scope.setTestFlagInEHCleanup();
needFlag = true;
}
if (!needFlag) return;
llvm::AllocaInst *var = Scope.getActiveFlag();
if (!var) {
var = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), "cleanup.isactive");
Scope.setActiveFlag(var);
assert(dominatingIP && "no existing variable and no dominating IP!");
llvm::Value *value = CGF.Builder.getInt1(kind == ForDeactivation);
if (CGF.isInConditionalBranch()) {
CGF.setBeforeOutermostConditional(value, var);
} else {
new llvm::StoreInst(value, var, dominatingIP);
}
}
CGF.Builder.CreateStore(CGF.Builder.getInt1(kind == ForActivation), var);
}
void CodeGenFunction::ActivateCleanupBlock(EHScopeStack::stable_iterator C,
llvm::Instruction *dominatingIP) {
assert(C != EHStack.stable_end() && "activating bottom of stack?");
EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(C));
assert(!Scope.isActive() && "double activation");
SetupCleanupBlockActivation(*this, C, ForActivation, dominatingIP);
Scope.setActive(true);
}
void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C,
llvm::Instruction *dominatingIP) {
assert(C != EHStack.stable_end() && "deactivating bottom of stack?");
EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.find(C));
assert(Scope.isActive() && "double deactivation");
if (C == EHStack.stable_begin()) {
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
PopCleanupBlock();
Builder.restoreIP(SavedIP);
return;
}
SetupCleanupBlockActivation(*this, C, ForDeactivation, dominatingIP);
Scope.setActive(false);
}
llvm::Value *CodeGenFunction::getNormalCleanupDestSlot() {
if (!NormalCleanupDest)
NormalCleanupDest =
CreateTempAlloca(Builder.getInt32Ty(), "cleanup.dest.slot");
return NormalCleanupDest;
}
void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary,
QualType TempType,
llvm::Value *Ptr) {
pushDestroy(NormalAndEHCleanup, Ptr, TempType, destroyCXXObject,
true);
}