#include "CGCleanup.h"
#include "CodeGenFunction.h"
#include "llvm/Support/SaveAndRestore.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.getAggregatePointer());
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, nullptr, ScalarLiteral);
Address addr =
CGF.CreateDefaultAlignTempAlloca(V->getType(), "saved-rvalue");
CGF.Builder.CreateStore(V, addr);
return saved_type(addr.getPointer(), nullptr, ScalarAddress);
}
if (rv.isComplex()) {
CodeGenFunction::ComplexPairTy V = rv.getComplexVal();
llvm::Type *ComplexTy =
llvm::StructType::get(V.first->getType(), V.second->getType());
Address addr = CGF.CreateDefaultAlignTempAlloca(ComplexTy, "saved-complex");
CGF.Builder.CreateStore(V.first, CGF.Builder.CreateStructGEP(addr, 0));
CGF.Builder.CreateStore(V.second, CGF.Builder.CreateStructGEP(addr, 1));
return saved_type(addr.getPointer(), nullptr, ComplexAddress);
}
assert(rv.isAggregate());
Address V = rv.getAggregateAddress(); if (!DominatingLLVMValue::needsSaving(V.getPointer()))
return saved_type(V.getPointer(), V.getElementType(), AggregateLiteral,
V.getAlignment().getQuantity());
Address addr =
CGF.CreateTempAlloca(V.getType(), CGF.getPointerAlign(), "saved-rvalue");
CGF.Builder.CreateStore(V.getPointer(), addr);
return saved_type(addr.getPointer(), V.getElementType(), AggregateAddress,
V.getAlignment().getQuantity());
}
RValue DominatingValue<RValue>::saved_type::restore(CodeGenFunction &CGF) {
auto getSavingAddress = [&](llvm::Value *value) {
auto *AI = cast<llvm::AllocaInst>(value);
return Address(value, AI->getAllocatedType(),
CharUnits::fromQuantity(AI->getAlign().value()));
};
switch (K) {
case ScalarLiteral:
return RValue::get(Value);
case ScalarAddress:
return RValue::get(CGF.Builder.CreateLoad(getSavingAddress(Value)));
case AggregateLiteral:
return RValue::getAggregate(
Address(Value, ElementType, CharUnits::fromQuantity(Align)));
case AggregateAddress: {
auto addr = CGF.Builder.CreateLoad(getSavingAddress(Value));
return RValue::getAggregate(
Address(addr, ElementType, CharUnits::fromQuantity(Align)));
}
case ComplexAddress: {
Address address = getSavingAddress(Value);
llvm::Value *real =
CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(address, 0));
llvm::Value *imag =
CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(address, 1));
return RValue::getComplex(real, imag);
}
}
llvm_unreachable("bad saved r-value kind");
}
char *EHScopeStack::allocate(size_t Size) {
Size = llvm::alignTo(Size, ScopeStackAlignment);
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;
}
void EHScopeStack::deallocate(size_t Size) {
StartOfData += llvm::alignTo(Size, ScopeStackAlignment);
}
bool EHScopeStack::containsOnlyLifetimeMarkers(
EHScopeStack::stable_iterator Old) const {
for (EHScopeStack::iterator it = begin(); stabilize(it) != Old; it++) {
EHCleanupScope *cleanup = dyn_cast<EHCleanupScope>(&*it);
if (!cleanup || !cleanup->isLifetimeMarker())
return false;
}
return true;
}
bool EHScopeStack::requiresLandingPad() const {
for (stable_iterator si = getInnermostEHScope(); si != stable_end(); ) {
if (auto *cleanup = dyn_cast<EHCleanupScope>(&*find(si)))
if (cleanup->isLifetimeMarker()) {
si = cleanup->getEnclosingEHScope();
continue;
}
return true;
}
return false;
}
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();
}
void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) {
char *Buffer = allocate(EHCleanupScope::getSizeForCleanupSize(Size));
bool IsNormalCleanup = Kind & NormalCleanup;
bool IsEHCleanup = Kind & EHCleanup;
bool IsLifetimeMarker = Kind & LifetimeMarker;
if (InnermostEHScope != stable_end() &&
find(InnermostEHScope)->getKind() == EHScope::Terminate)
IsEHCleanup = false;
EHCleanupScope *Scope =
new (Buffer) EHCleanupScope(IsNormalCleanup,
IsEHCleanup,
Size,
BranchFixups.size(),
InnermostNormalCleanup,
InnermostEHScope);
if (IsNormalCleanup)
InnermostNormalCleanup = stable_begin();
if (IsEHCleanup)
InnermostEHScope = stable_begin();
if (IsLifetimeMarker)
Scope->setLifetimeMarker();
if (CGF->getLangOpts().EHAsynch && IsEHCleanup && !IsLifetimeMarker &&
CGF->getTarget().getCXXABI().isMicrosoft())
CGF->EmitSehCppScopeBegin();
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();
deallocate(Cleanup.getAllocatedSize());
Cleanup.Destroy();
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());
deallocate(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 == nullptr)
BranchFixups.pop_back();
}
Address CodeGenFunction::createCleanupActiveFlag() {
Address active = CreateTempAllocaWithoutCast(
Builder.getInt1Ty(), CharUnits::One(), "cleanup.cond");
setBeforeOutermostConditional(Builder.getFalse(), active);
Builder.CreateStore(Builder.getTrue(), active);
return active;
}
void CodeGenFunction::initFullExprCleanupWithFlag(Address ActiveFlag) {
EHCleanupScope &cleanup = cast<EHCleanupScope>(*EHStack.begin());
assert(!cleanup.hasActiveFlag() && "cleanup already has active flag?");
cleanup.setActiveFlag(ActiveFlag);
if (cleanup.isNormalCleanup()) cleanup.setTestFlagInNormalCleanup();
if (cleanup.isEHCleanup()) cleanup.setTestFlagInEHCleanup();
}
void EHScopeStack::Cleanup::anchor() {}
static void createStoreInstBefore(llvm::Value *value, Address addr,
llvm::Instruction *beforeInst) {
auto store = new llvm::StoreInst(value, addr.getPointer(), beforeInst);
store->setAlignment(addr.getAlignment().getAsAlign());
}
static llvm::LoadInst *createLoadInstBefore(Address addr, const Twine &name,
llvm::Instruction *beforeInst) {
return new llvm::LoadInst(addr.getElementType(), addr.getPointer(), name,
false, addr.getAlignment().getAsAlign(),
beforeInst);
}
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 == nullptr) continue;
if (Fixup.OptimisticBranchBlock == nullptr) {
createStoreInstBefore(CGF.Builder.getInt32(Fixup.DestinationIndex),
CGF.getNormalCleanupDestSlot(),
Fixup.InitialBranch);
Fixup.InitialBranch->setSuccessor(0, CleanupEntry);
}
if (!CasesAdded.insert(Fixup.Destination).second)
continue;
Switch->addCase(CGF.Builder.getInt32(Fixup.DestinationIndex),
Fixup.Destination);
}
CGF.EHStack.clearFixups();
}
static llvm::SwitchInst *TransitionToCleanupSwitch(CodeGenFunction &CGF,
llvm::BasicBlock *Block) {
llvm::Instruction *Term = Block->getTerminator();
assert(Term && "can't transition block without terminator");
if (llvm::BranchInst *Br = dyn_cast<llvm::BranchInst>(Term)) {
assert(Br->isUnconditional());
auto Load = createLoadInstBefore(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 = nullptr;
ResolvedAny = true;
llvm::BasicBlock *BranchBB = Fixup.OptimisticBranchBlock;
if (!BranchBB)
continue;
if (!ModifiedOptimisticBlocks.insert(BranchBB).second)
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,
std::initializer_list<llvm::Value **> ValuesToReload) {
assert(Old.isValid());
bool HadBranches = false;
while (EHStack.stable_begin() != Old) {
EHCleanupScope &Scope = cast<EHCleanupScope>(*EHStack.begin());
HadBranches |= Scope.hasBranches();
bool FallThroughIsBranchThrough =
Old.strictlyEncloses(Scope.getEnclosingNormalCleanup());
PopCleanupBlock(FallThroughIsBranchThrough);
}
if (!HadBranches)
return;
for (llvm::Value **ReloadedValue : ValuesToReload) {
auto *Inst = dyn_cast_or_null<llvm::Instruction>(*ReloadedValue);
if (!Inst)
continue;
auto *AI = dyn_cast<llvm::AllocaInst>(Inst);
if (AI && AI->isStaticAlloca())
continue;
Address Tmp =
CreateDefaultAlignTempAlloca(Inst->getType(), "tmp.exprcleanup");
llvm::BasicBlock::iterator InsertBefore;
if (auto *Invoke = dyn_cast<llvm::InvokeInst>(Inst))
InsertBefore = Invoke->getNormalDest()->getFirstInsertionPt();
else
InsertBefore = std::next(Inst->getIterator());
CGBuilderTy(CGM, &*InsertBefore).CreateStore(Inst, Tmp);
*ReloadedValue = Builder.CreateLoad(Tmp);
}
}
void CodeGenFunction::PopCleanupBlocks(
EHScopeStack::stable_iterator Old, size_t OldLifetimeExtendedSize,
std::initializer_list<llvm::Value **> ValuesToReload) {
PopCleanupBlocks(Old, ValuesToReload);
for (size_t I = OldLifetimeExtendedSize,
E = LifetimeExtendedCleanupStack.size(); I != E; ) {
assert((I % alignof(LifetimeExtendedCleanupHeader) == 0) &&
"misaligned cleanup stack entry");
LifetimeExtendedCleanupHeader &Header =
reinterpret_cast<LifetimeExtendedCleanupHeader&>(
LifetimeExtendedCleanupStack[I]);
I += sizeof(Header);
EHStack.pushCopyOfCleanup(Header.getKind(),
&LifetimeExtendedCleanupStack[I],
Header.getSize());
I += Header.getSize();
if (Header.isConditional()) {
Address ActiveFlag =
reinterpret_cast<Address &>(LifetimeExtendedCleanupStack[I]);
initFullExprCleanupWithFlag(ActiveFlag);
I += sizeof(ActiveFlag);
}
}
LifetimeExtendedCleanupStack.resize(OldLifetimeExtendedSize);
}
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,
Address ActiveFlag) {
llvm::BasicBlock *ContBB = nullptr;
if (ActiveFlag.isValid()) {
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.isValid())
CGF.EmitBlock(ContBB);
}
static void ForwardPrebranchedFallthrough(llvm::BasicBlock *Exit,
llvm::BasicBlock *From,
llvm::BasicBlock *To) {
llvm::Instruction *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;
++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.getPointer());
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();
Address NormalActiveFlag =
Scope.shouldTestFlagInNormalCleanup() ? Scope.getActiveFlag()
: Address::invalid();
Address EHActiveFlag =
Scope.shouldTestFlagInEHCleanup() ? Scope.getActiveFlag()
: Address::invalid();
llvm::BasicBlock *EHEntry = Scope.getCachedEHDispatchBlock();
assert(Scope.hasEHBranches() == (EHEntry != nullptr));
bool RequiresEHCleanup = (EHEntry != nullptr);
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 != nullptr && 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;
}
auto *CleanupSource = reinterpret_cast<char *>(Scope.getCleanupBuffer());
alignas(EHScopeStack::ScopeStackAlignment) char
CleanupBufferStack[8 * sizeof(void *)];
std::unique_ptr<char[]> CleanupBufferHeap;
size_t CleanupSize = Scope.getCleanupSize();
EHScopeStack::Cleanup *Fn;
if (CleanupSize <= sizeof(CleanupBufferStack)) {
memcpy(CleanupBufferStack, CleanupSource, CleanupSize);
Fn = reinterpret_cast<EHScopeStack::Cleanup *>(CleanupBufferStack);
} else {
CleanupBufferHeap.reset(new char[CleanupSize]);
memcpy(CleanupBufferHeap.get(), CleanupSource, CleanupSize);
Fn = reinterpret_cast<EHScopeStack::Cleanup *>(CleanupBufferHeap.get());
}
EHScopeStack::Cleanup::Flags cleanupFlags;
if (Scope.isNormalCleanup())
cleanupFlags.setIsNormalCleanupKind();
if (Scope.isEHCleanup())
cleanupFlags.setIsEHCleanupKind();
bool IsEHa = getLangOpts().EHAsynch && !Scope.isLifetimeMarker();
const EHPersonality &Personality = EHPersonality::get(*this);
if (!RequiresNormalCleanup) {
if (IsEHa && getInvokeDest()) {
if (Personality.isMSVCXXPersonality())
EmitSehCppScopeEnd();
}
destroyOptimisticNormalEntry(*this, Scope);
EHStack.popCleanup();
} else {
if (HasFallthrough && !HasPrebranchedFallthrough && !HasFixups &&
!HasExistingBranches) {
if (IsEHa && getInvokeDest()) {
if (Personality.isMSVCXXPersonality())
EmitSehCppScopeEnd();
else
EmitSehTryScopeEnd();
}
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);
if (IsEHa) {
if (Personality.isMSVCXXPersonality())
EmitSehCppScopeEnd();
else
EmitSehTryScopeEnd();
}
bool HasEnclosingCleanups =
(Scope.getEnclosingNormalCleanup() != EHStack.stable_end());
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 (!Scope.hasBranchThroughs() && !HasFixups && !HasFallthrough &&
Scope.getNumBranchAfters() == 1) {
assert(!BranchThroughDest || !IsActive);
llvm::Instruction *NormalCleanupDestSlot =
cast<llvm::Instruction>(getNormalCleanupDestSlot().getPointer());
if (NormalCleanupDestSlot->hasOneUse()) {
NormalCleanupDestSlot->user_back()->eraseFromParent();
NormalCleanupDestSlot->eraseFromParent();
NormalCleanupDest = Address::invalid();
}
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;
cleanupFlags.setHasExitSwitch();
llvm::LoadInst *Load =
createLoadInstBefore(getNormalCleanupDestSlot(), "cleanup.dest",
nullptr);
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) {
createStoreInstBefore(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);
llvm::BasicBlock *NextAction = getEHDispatchBlock(EHParent);
bool PushedTerminate = false;
SaveAndRestore<llvm::Instruction *> RestoreCurrentFuncletPad(
CurrentFuncletPad);
llvm::CleanupPadInst *CPI = nullptr;
const EHPersonality &Personality = EHPersonality::get(*this);
if (Personality.usesFuncletPads()) {
llvm::Value *ParentPad = CurrentFuncletPad;
if (!ParentPad)
ParentPad = llvm::ConstantTokenNone::get(CGM.getLLVMContext());
CurrentFuncletPad = CPI = Builder.CreateCleanupPad(ParentPad);
}
if (!Personality.isMSVCPersonality()) {
EHStack.pushTerminate();
PushedTerminate = true;
}
if (EHActiveFlag.isValid() || IsActive) {
cleanupFlags.setIsForEHCleanup();
EmitCleanup(*this, Fn, cleanupFlags, EHActiveFlag);
}
if (CPI)
Builder.CreateCleanupRet(CPI, NextAction);
else
Builder.CreateBr(NextAction);
if (PushedTerminate)
EHStack.popTerminate();
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 = nullptr;
Builder.ClearInsertionPoint();
return;
}
llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex());
createStoreInstBefore(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;
Address var = Scope.getActiveFlag();
if (!var.isValid()) {
var = CGF.CreateTempAlloca(CGF.Builder.getInt1Ty(), CharUnits::One(),
"cleanup.isactive");
Scope.setActiveFlag(var);
assert(dominatingIP && "no existing variable and no dominating IP!");
llvm::Constant *value = CGF.Builder.getInt1(kind == ForDeactivation);
if (CGF.isInConditionalBranch()) {
CGF.setBeforeOutermostConditional(value, var);
} else {
createStoreInstBefore(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() &&
CurrentCleanupScopeDepth.strictlyEncloses(C)) {
if (!Scope.isNormalCleanup() && getLangOpts().EHAsynch) {
PopCleanupBlock();
} else {
CGBuilderTy::InsertPoint SavedIP = Builder.saveAndClearIP();
PopCleanupBlock();
Builder.restoreIP(SavedIP);
}
return;
}
SetupCleanupBlockActivation(*this, C, ForDeactivation, dominatingIP);
Scope.setActive(false);
}
Address CodeGenFunction::getNormalCleanupDestSlot() {
if (!NormalCleanupDest.isValid())
NormalCleanupDest =
CreateDefaultAlignTempAlloca(Builder.getInt32Ty(), "cleanup.dest.slot");
return NormalCleanupDest;
}
void CodeGenFunction::EmitCXXTemporary(const CXXTemporary *Temporary,
QualType TempType,
Address Ptr) {
pushDestroy(NormalAndEHCleanup, Ptr, TempType, destroyCXXObject,
true);
}
static void EmitSehScope(CodeGenFunction &CGF,
llvm::FunctionCallee &SehCppScope) {
llvm::BasicBlock *InvokeDest = CGF.getInvokeDest();
assert(CGF.Builder.GetInsertBlock() && InvokeDest);
llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
SmallVector<llvm::OperandBundleDef, 1> BundleList =
CGF.getBundlesForFunclet(SehCppScope.getCallee());
if (CGF.CurrentFuncletPad)
BundleList.emplace_back("funclet", CGF.CurrentFuncletPad);
CGF.Builder.CreateInvoke(SehCppScope, Cont, InvokeDest, None, BundleList);
CGF.EmitBlock(Cont);
}
void CodeGenFunction::EmitSehCppScopeBegin() {
assert(getLangOpts().EHAsynch);
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, false);
llvm::FunctionCallee SehCppScope =
CGM.CreateRuntimeFunction(FTy, "llvm.seh.scope.begin");
EmitSehScope(*this, SehCppScope);
}
void CodeGenFunction::EmitSehCppScopeEnd() {
assert(getLangOpts().EHAsynch);
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, false);
llvm::FunctionCallee SehCppScope =
CGM.CreateRuntimeFunction(FTy, "llvm.seh.scope.end");
EmitSehScope(*this, SehCppScope);
}
void CodeGenFunction::EmitSehTryScopeBegin() {
assert(getLangOpts().EHAsynch);
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, false);
llvm::FunctionCallee SehCppScope =
CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.begin");
EmitSehScope(*this, SehCppScope);
}
void CodeGenFunction::EmitSehTryScopeEnd() {
assert(getLangOpts().EHAsynch);
llvm::FunctionType *FTy =
llvm::FunctionType::get(CGM.VoidTy, false);
llvm::FunctionCallee SehCppScope =
CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end");
EmitSehScope(*this, SehCppScope);
}