aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/CodeGen/CGException.cpp125
-rw-r--r--lib/CodeGen/CGException.h164
-rw-r--r--lib/CodeGen/CGObjC.cpp4
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp12
-rw-r--r--lib/CodeGen/CGObjCMac.cpp10
-rw-r--r--lib/CodeGen/CGStmt.cpp57
-rw-r--r--lib/CodeGen/CodeGenFunction.cpp685
-rw-r--r--lib/CodeGen/CodeGenFunction.h120
-rw-r--r--test/CodeGenCXX/condition.cpp16
-rw-r--r--test/CodeGenCXX/eh.cpp71
-rw-r--r--test/CodeGenObjC/gnu-exceptions.m8
11 files changed, 886 insertions, 386 deletions
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 1f00914ea4..d31cab5194 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -98,6 +98,11 @@ void EHScopeStack::popCleanup() {
InnermostEHCleanup = Cleanup.getEnclosingEHCleanup();
StartOfData += Cleanup.getAllocatedSize();
+ if (empty()) NextEHDestIndex = FirstEHDestIndex;
+
+ // Destroy the cleanup.
+ Cleanup.~EHCleanupScope();
+
// Check whether we can shrink the branch-fixups stack.
if (!BranchFixups.empty()) {
// If we no longer have any normal cleanups, all the fixups are
@@ -123,6 +128,8 @@ void EHScopeStack::popFilter() {
EHFilterScope &Filter = cast<EHFilterScope>(*begin());
StartOfData += EHFilterScope::getSizeForNumFilters(Filter.getNumFilters());
+ if (empty()) NextEHDestIndex = FirstEHDestIndex;
+
assert(CatchDepth > 0 && "mismatched filter push/pop");
CatchDepth--;
}
@@ -130,13 +137,16 @@ void EHScopeStack::popFilter() {
EHCatchScope *EHScopeStack::pushCatch(unsigned NumHandlers) {
char *Buffer = allocate(EHCatchScope::getSizeForNumHandlers(NumHandlers));
CatchDepth++;
- return new (Buffer) EHCatchScope(NumHandlers);
+ EHCatchScope *Scope = new (Buffer) EHCatchScope(NumHandlers);
+ for (unsigned I = 0; I != NumHandlers; ++I)
+ Scope->getHandlers()[I].Index = getNextEHDestIndex();
+ return Scope;
}
void EHScopeStack::pushTerminate() {
char *Buffer = allocate(EHTerminateScope::getSize());
CatchDepth++;
- new (Buffer) EHTerminateScope();
+ new (Buffer) EHTerminateScope(getNextEHDestIndex());
}
/// Remove any 'null' fixups on the stack. However, we can't pop more
@@ -158,20 +168,6 @@ void EHScopeStack::popNullFixups() {
BranchFixups.pop_back();
}
-void EHScopeStack::resolveBranchFixups(llvm::BasicBlock *Dest) {
- assert(Dest && "null block passed to resolveBranchFixups");
-
- if (BranchFixups.empty()) return;
- assert(hasNormalCleanups() &&
- "branch fixups exist with no normal cleanups on stack");
-
- for (unsigned I = 0, E = BranchFixups.size(); I != E; ++I)
- if (BranchFixups[I].Destination == Dest)
- BranchFixups[I].Destination = 0;
-
- popNullFixups();
-}
-
static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
// void *__cxa_allocate_exception(size_t thrown_size);
const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
@@ -756,8 +752,8 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
EHSelector.push_back(getPersonalityFn(*this, Personality));
// Accumulate all the handlers in scope.
- llvm::DenseMap<llvm::Value*, JumpDest> EHHandlers;
- JumpDest CatchAll;
+ llvm::DenseMap<llvm::Value*, UnwindDest> EHHandlers;
+ UnwindDest CatchAll;
bool HasEHCleanup = false;
bool HasEHFilter = false;
llvm::SmallVector<llvm::Value*, 8> EHFilters;
@@ -773,7 +769,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
case EHScope::Filter: {
assert(I.next() == EHStack.end() && "EH filter is not end of EH stack");
- assert(!CatchAll.Block && "EH filter reached after catch-all");
+ assert(!CatchAll.isValid() && "EH filter reached after catch-all");
// Filter scopes get added to the selector in wierd ways.
EHFilterScope &Filter = cast<EHFilterScope>(*I);
@@ -791,9 +787,10 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
case EHScope::Terminate:
// Terminate scopes are basically catch-alls.
- assert(!CatchAll.Block);
- CatchAll.Block = getTerminateHandler();
- CatchAll.ScopeDepth = EHStack.getEnclosingEHCleanup(I);
+ assert(!CatchAll.isValid());
+ CatchAll = UnwindDest(getTerminateHandler(),
+ EHStack.getEnclosingEHCleanup(I),
+ cast<EHTerminateScope>(*I).getDestIndex());
goto done;
case EHScope::Catch:
@@ -806,30 +803,32 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// Catch-all. We should only have one of these per catch.
if (!Handler.Type) {
- assert(!CatchAll.Block);
- CatchAll.Block = Handler.Block;
- CatchAll.ScopeDepth = EHStack.getEnclosingEHCleanup(I);
+ assert(!CatchAll.isValid());
+ CatchAll = UnwindDest(Handler.Block,
+ EHStack.getEnclosingEHCleanup(I),
+ Handler.Index);
continue;
}
// Check whether we already have a handler for this type.
- JumpDest &Dest = EHHandlers[Handler.Type];
- if (Dest.Block) continue;
+ UnwindDest &Dest = EHHandlers[Handler.Type];
+ if (Dest.isValid()) continue;
EHSelector.push_back(Handler.Type);
- Dest.Block = Handler.Block;
- Dest.ScopeDepth = EHStack.getEnclosingEHCleanup(I);
+ Dest = UnwindDest(Handler.Block,
+ EHStack.getEnclosingEHCleanup(I),
+ Handler.Index);
}
// Stop if we found a catch-all.
- if (CatchAll.Block) break;
+ if (CatchAll.isValid()) break;
}
done:
unsigned LastToEmitInLoop = EHSelector.size();
// If we have a catch-all, add null to the selector.
- if (CatchAll.Block) {
+ if (CatchAll.isValid()) {
EHSelector.push_back(getCatchAllValue(CGF));
// If we have an EH filter, we need to add those handlers in the
@@ -878,14 +877,15 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// filter (possibly with a cleanup), a catch-all, or another catch).
for (unsigned I = 2; I != LastToEmitInLoop; ++I) {
llvm::Value *Type = EHSelector[I];
- JumpDest Dest = EHHandlers[Type];
- assert(Dest.Block && "no handler entry for value in selector?");
+ UnwindDest Dest = EHHandlers[Type];
+ assert(Dest.isValid() && "no handler entry for value in selector?");
// Figure out where to branch on a match. As a debug code-size
// optimization, if the scope depth matches the innermost cleanup,
// we branch directly to the catch handler.
- llvm::BasicBlock *Match = Dest.Block;
- bool MatchNeedsCleanup = Dest.ScopeDepth != EHStack.getInnermostEHCleanup();
+ llvm::BasicBlock *Match = Dest.getBlock();
+ bool MatchNeedsCleanup =
+ Dest.getScopeDepth() != EHStack.getInnermostEHCleanup();
if (MatchNeedsCleanup)
Match = createBasicBlock("eh.match");
@@ -911,7 +911,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// Emit the final case in the selector.
// This might be a catch-all....
- if (CatchAll.Block) {
+ if (CatchAll.isValid()) {
assert(isa<llvm::ConstantPointerNull>(EHSelector.back()));
EmitBranchThroughEHCleanup(CatchAll);
@@ -930,7 +930,8 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
}
llvm::BasicBlock *CleanupContBB = createBasicBlock("ehspec.cleanup.cont");
- EmitBranchThroughEHCleanup(JumpDest(CleanupContBB, EHStack.stable_end()));
+ EmitBranchThroughEHCleanup(UnwindDest(CleanupContBB, EHStack.stable_end(),
+ EHStack.getNextEHDestIndex()));
EmitBlock(CleanupContBB);
if (HasEHCleanup)
@@ -975,26 +976,7 @@ llvm::BasicBlock *CodeGenFunction::EmitLandingPad() {
// ...or a cleanup.
} else {
- // We emit a jump to a notional label at the outermost unwind state.
- llvm::BasicBlock *Unwind = createBasicBlock("eh.resume");
- JumpDest Dest(Unwind, EHStack.stable_end());
- EmitBranchThroughEHCleanup(Dest);
-
- // The unwind block. We have to reload the exception here because
- // we might have unwound through arbitrary blocks, so the landing
- // pad might not dominate.
- EmitBlock(Unwind);
-
- // This can always be a call because we necessarily didn't find
- // anything on the EH stack which needs our help.
- llvm::Constant *RethrowFn;
- if (const char *RethrowName = Personality.getCatchallRethrowFnName())
- RethrowFn = getCatchallRethrowFn(CGF, RethrowName);
- else
- RethrowFn = getUnwindResumeOrRethrowFn();
- Builder.CreateCall(RethrowFn, Builder.CreateLoad(getExceptionSlot()))
- ->setDoesNotReturn();
- Builder.CreateUnreachable();
+ EmitBranchThroughEHCleanup(getRethrowDest());
}
// Restore the old IR generation state.
@@ -1537,6 +1519,35 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() {
return TerminateHandler;
}
+CodeGenFunction::UnwindDest CodeGenFunction::getRethrowDest() {
+ if (RethrowBlock.isValid()) return RethrowBlock;
+
+ CGBuilderTy::InsertPoint SavedIP = Builder.saveIP();
+
+ // We emit a jump to a notional label at the outermost unwind state.
+ llvm::BasicBlock *Unwind = createBasicBlock("eh.resume");
+ Builder.SetInsertPoint(Unwind);
+
+ const EHPersonality &Personality = EHPersonality::get(CGM.getLangOptions());
+
+ // This can always be a call because we necessarily didn't find
+ // anything on the EH stack which needs our help.
+ llvm::Constant *RethrowFn;
+ if (const char *RethrowName = Personality.getCatchallRethrowFnName())
+ RethrowFn = getCatchallRethrowFn(*this, RethrowName);
+ else
+ RethrowFn = getUnwindResumeOrRethrowFn();
+
+ Builder.CreateCall(RethrowFn, Builder.CreateLoad(getExceptionSlot()))
+ ->setDoesNotReturn();
+ Builder.CreateUnreachable();
+
+ Builder.restoreIP(SavedIP);
+
+ RethrowBlock = UnwindDest(Unwind, EHStack.stable_end(), 0);
+ return RethrowBlock;
+}
+
EHScopeStack::Cleanup::~Cleanup() {
llvm_unreachable("Cleanup is indestructable");
}
diff --git a/lib/CodeGen/CGException.h b/lib/CodeGen/CGException.h
index 3c6e1a5528..01536e35fb 100644
--- a/lib/CodeGen/CGException.h
+++ b/lib/CodeGen/CGException.h
@@ -100,15 +100,13 @@ public:
/// The catch handler for this type.
llvm::BasicBlock *Block;
- static Handler make(llvm::Value *Type, llvm::BasicBlock *Block) {
- Handler Temp;
- Temp.Type = Type;
- Temp.Block = Block;
- return Temp;
- }
+ /// The unwind destination index for this handler.
+ unsigned Index;
};
private:
+ friend class EHScopeStack;
+
Handler *getHandlers() {
return reinterpret_cast<Handler*>(this+1);
}
@@ -136,7 +134,8 @@ public:
void setHandler(unsigned I, llvm::Value *Type, llvm::BasicBlock *Block) {
assert(I < getNumHandlers());
- getHandlers()[I] = Handler::make(Type, Block);
+ getHandlers()[I].Type = Type;
+ getHandlers()[I].Block = Block;
}
const Handler &getHandler(unsigned I) const {
@@ -184,6 +183,39 @@ class EHCleanupScope : public EHScope {
/// created if needed before the cleanup is popped.
llvm::BasicBlock *EHBlock;
+ /// Extra information required for cleanups that have resolved
+ /// branches through them. This has to be allocated on the side
+ /// because everything on the cleanup stack has be trivially
+ /// movable.
+ struct ExtInfo {
+ /// The destinations of normal branch-afters and branch-throughs.
+ llvm::SmallPtrSet<llvm::BasicBlock*, 4> Branches;
+
+ /// Normal branch-afters.
+ llvm::SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
+ BranchAfters;
+
+ /// The destinations of EH branch-afters and branch-throughs.
+ /// TODO: optimize for the extremely common case of a single
+ /// branch-through.
+ llvm::SmallPtrSet<llvm::BasicBlock*, 4> EHBranches;
+
+ /// EH branch-afters.
+ llvm::SmallVector<std::pair<llvm::BasicBlock*,llvm::ConstantInt*>, 4>
+ EHBranchAfters;
+ };
+ mutable struct ExtInfo *ExtInfo;
+
+ struct ExtInfo &getExtInfo() {
+ if (!ExtInfo) ExtInfo = new struct ExtInfo();
+ return *ExtInfo;
+ }
+
+ const struct ExtInfo &getExtInfo() const {
+ if (!ExtInfo) ExtInfo = new struct ExtInfo();
+ return *ExtInfo;
+ }
+
public:
/// Gets the size required for a lazy cleanup scope with the given
/// cleanup-data requirements.
@@ -203,8 +235,14 @@ public:
IsNormalCleanup(IsNormal), IsEHCleanup(IsEH),
CleanupSize(CleanupSize), FixupDepth(FixupDepth),
EnclosingNormal(EnclosingNormal), EnclosingEH(EnclosingEH),
- NormalBlock(0), EHBlock(0)
- {}
+ NormalBlock(0), EHBlock(0), ExtInfo(0)
+ {
+ assert(this->CleanupSize == CleanupSize && "cleanup size overflow");
+ }
+
+ ~EHCleanupScope() {
+ delete ExtInfo;
+ }
bool isNormalCleanup() const { return IsNormalCleanup; }
llvm::BasicBlock *getNormalBlock() const { return NormalBlock; }
@@ -229,6 +267,102 @@ public:
return reinterpret_cast<EHScopeStack::Cleanup*>(getCleanupBuffer());
}
+ /// True if this cleanup scope has any branch-afters or branch-throughs.
+ bool hasBranches() const { return ExtInfo && !ExtInfo->Branches.empty(); }
+
+ /// Add a branch-after to this cleanup scope. A branch-after is a
+ /// branch from a point protected by this (normal) cleanup to a
+ /// point in the normal cleanup scope immediately containing it.
+ /// For example,
+ /// for (;;) { A a; break; }
+ /// contains a branch-after.
+ ///
+ /// Branch-afters each have their own destination out of the
+ /// cleanup, guaranteed distinct from anything else threaded through
+ /// it. Therefore branch-afters usually force a switch after the
+ /// cleanup.
+ void addBranchAfter(llvm::ConstantInt *Index,
+ llvm::BasicBlock *Block) {
+ struct ExtInfo &ExtInfo = getExtInfo();
+ if (ExtInfo.Branches.insert(Block))
+ ExtInfo.BranchAfters.push_back(std::make_pair(Block, Index));
+ }
+
+ /// Return the number of unique branch-afters on this scope.
+ unsigned getNumBranchAfters() const {
+ return ExtInfo ? ExtInfo->BranchAfters.size() : 0;
+ }
+
+ llvm::BasicBlock *getBranchAfterBlock(unsigned I) const {
+ assert(I < getNumBranchAfters());
+ return ExtInfo->BranchAfters[I].first;
+ }
+
+ llvm::ConstantInt *getBranchAfterIndex(unsigned I) const {
+ assert(I < getNumBranchAfters());
+ return ExtInfo->BranchAfters[I].second;
+ }
+
+ /// Add a branch-through to this cleanup scope. A branch-through is
+ /// a branch from a scope protected by this (normal) cleanup to an
+ /// enclosing scope other than the immediately-enclosing normal
+ /// cleanup scope.
+ ///
+ /// In the following example, the branch through B's scope is a
+ /// branch-through, while the branch through A's scope is a
+ /// branch-after:
+ /// for (;;) { A a; B b; break; }
+ ///
+ /// All branch-throughs have a common destination out of the
+ /// cleanup, one possibly shared with the fall-through. Therefore
+ /// branch-throughs usually don't force a switch after the cleanup.
+ ///
+ /// \return true if the branch-through was new to this scope
+ bool addBranchThrough(llvm::BasicBlock *Block) {
+ return getExtInfo().Branches.insert(Block);
+ }
+
+ /// Determines if this cleanup scope has any branch throughs.
+ bool hasBranchThroughs() const {
+ if (!ExtInfo) return false;
+ return (ExtInfo->BranchAfters.size() != ExtInfo->Branches.size());
+ }
+
+ // Same stuff, only for EH branches instead of normal branches.
+ // It's quite possible that we could find a better representation
+ // for this.
+
+ bool hasEHBranches() const { return ExtInfo && !ExtInfo->EHBranches.empty(); }
+ void addEHBranchAfter(llvm::ConstantInt *Index,
+ llvm::BasicBlock *Block) {
+ struct ExtInfo &ExtInfo = getExtInfo();
+ if (ExtInfo.EHBranches.insert(Block))
+ ExtInfo.EHBranchAfters.push_back(std::make_pair(Block, Index));
+ }
+
+ unsigned getNumEHBranchAfters() const {
+ return ExtInfo ? ExtInfo->EHBranchAfters.size() : 0;
+ }
+
+ llvm::BasicBlock *getEHBranchAfterBlock(unsigned I) const {
+ assert(I < getNumEHBranchAfters());
+ return ExtInfo->EHBranchAfters[I].first;
+ }
+
+ llvm::ConstantInt *getEHBranchAfterIndex(unsigned I) const {
+ assert(I < getNumEHBranchAfters());
+ return ExtInfo->EHBranchAfters[I].second;
+ }
+
+ bool addEHBranchThrough(llvm::BasicBlock *Block) {
+ return getExtInfo().EHBranches.insert(Block);
+ }
+
+ bool hasEHBranchThroughs() const {
+ if (!ExtInfo) return false;
+ return (ExtInfo->EHBranchAfters.size() != ExtInfo->EHBranches.size());
+ }
+
static bool classof(const EHScope *Scope) {
return (Scope->getKind() == Cleanup);
}
@@ -281,10 +415,13 @@ public:
/// An exceptions scope which calls std::terminate if any exception
/// reaches it.
class EHTerminateScope : public EHScope {
+ unsigned DestIndex : BitsRemaining;
public:
- EHTerminateScope() : EHScope(Terminate) {}
+ EHTerminateScope(unsigned Index) : EHScope(Terminate), DestIndex(Index) {}
static size_t getSize() { return sizeof(EHTerminateScope); }
+ unsigned getDestIndex() const { return DestIndex; }
+
static bool classof(const EHScope *Scope) {
return Scope->getKind() == Terminate;
}
@@ -344,6 +481,9 @@ public:
return copy;
}
+ bool encloses(iterator other) const { return Ptr >= other.Ptr; }
+ bool strictlyEncloses(iterator other) const { return Ptr > other.Ptr; }
+
bool operator==(iterator other) const { return Ptr == other.Ptr; }
bool operator!=(iterator other) const { return Ptr != other.Ptr; }
};
@@ -363,6 +503,8 @@ inline void EHScopeStack::popCatch() {
StartOfData += EHCatchScope::getSizeForNumHandlers(
cast<EHCatchScope>(*begin()).getNumHandlers());
+ if (empty()) NextEHDestIndex = FirstEHDestIndex;
+
assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
CatchDepth--;
}
@@ -373,6 +515,8 @@ inline void EHScopeStack::popTerminate() {
assert(isa<EHTerminateScope>(*begin()));
StartOfData += EHTerminateScope::getSize();
+ if (empty()) NextEHDestIndex = FirstEHDestIndex;
+
assert(CatchDepth > 0 && "mismatched catch/terminate push/pop");
CatchDepth--;
}
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 5eed0b6465..be060b42e1 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -793,7 +793,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
BreakContinueStack.pop_back();
- EmitBlock(AfterBody.Block);
+ EmitBlock(AfterBody.getBlock());
llvm::BasicBlock *FetchMore = createBasicBlock("fetchmore");
@@ -829,7 +829,7 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){
LV.getAddress());
}
- EmitBlock(LoopEnd.Block);
+ EmitBlock(LoopEnd.getBlock());
}
void CodeGenFunction::EmitObjCAtTryStmt(const ObjCAtTryStmt &S) {
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index 7fd2d36122..e4fb7bf421 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -2016,13 +2016,11 @@ void CGObjCGNU::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
if (S.getFinallyStmt())
CGF.ExitFinallyBlock(FinallyInfo);
- if (Cont.Block) {
- if (Cont.Block->use_empty())
- delete Cont.Block;
- else {
- CGF.EmitBranch(Cont.Block);
- CGF.EmitBlock(Cont.Block);
- }
+ if (Cont.isValid()) {
+ if (Cont.getBlock()->use_empty())
+ delete Cont.getBlock();
+ else
+ CGF.EmitBlock(Cont.getBlock());
}
}
diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index dc9593f6ea..d917c7d8a8 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -2953,11 +2953,11 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
// Pop the cleanup.
CGF.PopCleanupBlock();
- CGF.EmitBlock(FinallyEnd.Block);
+ CGF.EmitBlock(FinallyEnd.getBlock());
// Emit the rethrow block.
CGF.Builder.ClearInsertionPoint();
- CGF.EmitBlock(FinallyRethrow.Block, true);
+ CGF.EmitBlock(FinallyRethrow.getBlock(), true);
if (CGF.HaveInsertPoint()) {
CGF.Builder.CreateCall(ObjCTypes.getExceptionThrowFn(),
CGF.Builder.CreateLoad(RethrowPtr))
@@ -2965,7 +2965,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF,
CGF.Builder.CreateUnreachable();
}
- CGF.Builder.SetInsertPoint(FinallyEnd.Block);
+ CGF.Builder.SetInsertPoint(FinallyEnd.getBlock());
}
void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
@@ -5895,8 +5895,8 @@ void CGObjCNonFragileABIMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
if (S.getFinallyStmt())
CGF.ExitFinallyBlock(FinallyInfo);
- if (Cont.Block)
- CGF.EmitBlock(Cont.Block);
+ if (Cont.isValid())
+ CGF.EmitBlock(Cont.getBlock());
}
/// EmitThrowStmt - Generate code for a throw statement.
diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp
index f1740104fd..3bbecfa59c 100644
--- a/lib/CodeGen/CGStmt.cpp
+++ b/lib/CodeGen/CGStmt.cpp
@@ -248,32 +248,35 @@ void CodeGenFunction::EmitBranch(llvm::BasicBlock *Target) {
CodeGenFunction::JumpDest
CodeGenFunction::getJumpDestForLabel(const LabelStmt *S) {
JumpDest &Dest = LabelMap[S];
- if (Dest.Block) return Dest;
+ if (Dest.isValid()) return Dest;
// Create, but don't insert, the new block.
- Dest.Block = createBasicBlock(S->getName());
- Dest.ScopeDepth = EHScopeStack::stable_iterator::invalid();
+ Dest = JumpDest(createBasicBlock(S->getName()),
+ EHScopeStack::stable_iterator::invalid(),
+ NextCleanupDestIndex++);
return Dest;
}
void CodeGenFunction::EmitLabel(const LabelStmt &S) {
JumpDest &Dest = LabelMap[&S];
- // If we didn't needed a forward reference to this label, just go
+ // If we didn't need a forward reference to this label, just go
// ahead and create a destination at the current scope.
- if (!Dest.Block) {
+ if (!Dest.isValid()) {
Dest = getJumpDestInCurrentScope(S.getName());
// Otherwise, we need to give this label a target depth and remove
// it from the branch-fixups list.
} else {
- assert(!Dest.ScopeDepth.isValid() && "already emitted label!");
- Dest.ScopeDepth = EHStack.stable_begin();
+ assert(!Dest.getScopeDepth().isValid() && "already emitted label!");
+ Dest = JumpDest(Dest.getBlock(),
+ EHStack.stable_begin(),
+ Dest.getDestIndex());
- EHStack.resolveBranchFixups(Dest.Block);
+ ResolveBranchFixups(Dest.getBlock());
}
- EmitBlock(Dest.Block);
+ EmitBlock(Dest.getBlock());
}
@@ -373,7 +376,7 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
// Emit the header for the loop, which will also become
// the continue target.
JumpDest LoopHeader = getJumpDestInCurrentScope("while.cond");
- EmitBlock(LoopHeader.Block);
+ EmitBlock(LoopHeader.getBlock());
// Create an exit block for when the condition fails, which will
// also become the break target.
@@ -409,13 +412,13 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
// As long as the condition is true, go to the loop body.
llvm::BasicBlock *LoopBody = createBasicBlock("while.body");
if (EmitBoolCondBranch) {
- llvm::BasicBlock *ExitBlock = LoopExit.Block;
+ llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
if (ConditionScope.requiresCleanups())
ExitBlock = createBasicBlock("while.exit");
Builder.CreateCondBr(BoolCondVal, LoopBody, ExitBlock);
- if (ExitBlock != LoopExit.Block) {
+ if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
EmitBranchThroughCleanup(LoopExit);
}
@@ -435,15 +438,15 @@ void CodeGenFunction::EmitWhileStmt(const WhileStmt &S) {
ConditionScope.ForceCleanup();
// Branch to the loop header again.
- EmitBranch(LoopHeader.Block);
+ EmitBranch(LoopHeader.getBlock());
// Emit the exit block.
- EmitBlock(LoopExit.Block, true);
+ EmitBlock(LoopExit.getBlock(), true);
// The LoopHeader typically is just a branch if we skipped emitting
// a branch, try to erase it.
if (!EmitBoolCondBranch)
- SimplifyForwardingBlocks(LoopHeader.Block);
+ SimplifyForwardingBlocks(LoopHeader.getBlock());
}
void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
@@ -463,7 +466,7 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
BreakContinueStack.pop_back();
- EmitBlock(LoopCond.Block);
+ EmitBlock(LoopCond.getBlock());
// C99 6.8.5.2: "The evaluation of the controlling expression takes place
// after each execution of the loop body."
@@ -482,15 +485,15 @@ void CodeGenFunction::EmitDoStmt(const DoStmt &S) {
// As long as the condition is true, iterate the loop.
if (EmitBoolCondBranch)
- Builder.CreateCondBr(BoolCondVal, LoopBody, LoopExit.Block);
+ Builder.CreateCondBr(BoolCondVal, LoopBody, LoopExit.getBlock());
// Emit the exit block.
- EmitBlock(LoopExit.Block);
+ EmitBlock(LoopExit.getBlock());
// The DoCond block typically is just a branch if we skipped
// emitting a branch, try to erase it.
if (!EmitBoolCondBranch)
- SimplifyForwardingBlocks(LoopCond.Block);
+ SimplifyForwardingBlocks(LoopCond.getBlock());
}
void CodeGenFunction::EmitForStmt(const ForStmt &S) {
@@ -506,7 +509,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
// If there's an increment, the continue scope will be overwritten
// later.
JumpDest Continue = getJumpDestInCurrentScope("for.cond");
- llvm::BasicBlock *CondBlock = Continue.Block;
+ llvm::BasicBlock *CondBlock = Continue.getBlock();
EmitBlock(CondBlock);
// Create a cleanup scope for the condition variable cleanups.
@@ -516,7 +519,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
if (S.getCond()) {
// If the for statement has a condition scope, emit the local variable
// declaration.
- llvm::BasicBlock *ExitBlock = LoopExit.Block;
+ llvm::BasicBlock *ExitBlock = LoopExit.getBlock();
if (S.getConditionVariable()) {
EmitLocalBlockVarDecl(*S.getConditionVariable());
}
@@ -534,7 +537,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
BoolCondVal = EvaluateExprAsBool(S.getCond());
Builder.CreateCondBr(BoolCondVal, ForBody, ExitBlock);
- if (ExitBlock != LoopExit.Block) {
+ if (ExitBlock != LoopExit.getBlock()) {
EmitBlock(ExitBlock);
EmitBranchThroughCleanup(LoopExit);
}
@@ -570,7 +573,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
// If there is an increment, emit it next.
if (S.getInc()) {
- EmitBlock(Continue.Block);
+ EmitBlock(Continue.getBlock());
EmitStmt(S.getInc());
}
@@ -587,7 +590,7 @@ void CodeGenFunction::EmitForStmt(const ForStmt &S) {
}
// Emit the fall-through block.
- EmitBlock(LoopExit.Block, true);
+ EmitBlock(LoopExit.getBlock(), true);
}
void CodeGenFunction::EmitReturnOfRValue(RValue RV, QualType Ty) {
@@ -840,13 +843,15 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
// Otherwise, just forward the default block to the switch end.
} else {
- DefaultBlock->replaceAllUsesWith(SwitchExit.Block);
+ DefaultBlock->replaceAllUsesWith(SwitchExit.getBlock());
delete DefaultBlock;
}
}
+ ConditionScope.ForceCleanup();
+
// Emit continuation.
- EmitBlock(SwitchExit.Block, true);
+ EmitBlock(SwitchExit.getBlock(), true);
SwitchInsn = SavedSwitchInsn;
CaseRangeBlock = SavedCRBlock;
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index dbebd136ba..1d0d6a8ab5 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -31,8 +31,9 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
: BlockFunction(cgm, *this, Builder), CGM(cgm),
Target(CGM.getContext().Target),
Builder(cgm.getModule().getContext()),
+ NormalCleanupDest(0), EHCleanupDest(0), NextCleanupDestIndex(1),
ExceptionSlot(0), DebugInfo(0), IndirectBranch(0),
- SwitchInsn(0), CaseRangeBlock(0), InvokeDest(0),
+ SwitchInsn(0), CaseRangeBlock(0),
DidCallStackSave(false), UnreachableBlock(0),
CXXThisDecl(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0),
ConditionalBranchLevel(0), TerminateLandingPad(0), TerminateHandler(0),
@@ -89,26 +90,26 @@ void CodeGenFunction::EmitReturnBlock() {
// We have a valid insert point, reuse it if it is empty or there are no
// explicit jumps to the return block.
- if (CurBB->empty() || ReturnBlock.Block->use_empty()) {
- ReturnBlock.Block->replaceAllUsesWith(CurBB);
- delete ReturnBlock.Block;
+ if (CurBB->empty() || ReturnBlock.getBlock()->use_empty()) {
+ ReturnBlock.getBlock()->replaceAllUsesWith(CurBB);
+ delete ReturnBlock.getBlock();
} else
- EmitBlock(ReturnBlock.Block);
+ EmitBlock(ReturnBlock.getBlock());
return;
}
// Otherwise, if the return block is the target of a single direct
// branch then we can just put the code in that block instead. This
// cleans up functions which started with a unified return block.
- if (ReturnBlock.Block->hasOneUse()) {
+ if (ReturnBlock.getBlock()->hasOneUse()) {
llvm::BranchInst *BI =
- dyn_cast<llvm::BranchInst>(*ReturnBlock.Block->use_begin());
+ dyn_cast<llvm::BranchInst>(*ReturnBlock.getBlock()->use_begin());
if (BI && BI->isUnconditional() &&
- BI->getSuccessor(0) == ReturnBlock.Block) {
+ BI->getSuccessor(0) == ReturnBlock.getBlock()) {
// Reset insertion point and delete the branch.
Builder.SetInsertPoint(BI->getParent());
BI->eraseFromParent();
- delete ReturnBlock.Block;
+ delete ReturnBlock.getBlock();
return;
}
}
@@ -117,7 +118,7 @@ void CodeGenFunction::EmitReturnBlock() {
// unless it has uses. However, we still need a place to put the debug
// region.end for now.
- EmitBlock(ReturnBlock.Block);
+ EmitBlock(ReturnBlock.getBlock());
}
static void EmitIfUsed(CodeGenFunction &CGF, llvm::BasicBlock *BB) {
@@ -170,6 +171,7 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
}
}
+ EmitIfUsed(*this, RethrowBlock.getBlock());
EmitIfUsed(*this, TerminateLandingPad);
EmitIfUsed(*this, TerminateHandler);
EmitIfUsed(*this, UnreachableBlock);
@@ -585,7 +587,7 @@ llvm::BlockAddress *CodeGenFunction::GetAddrOfLabel(const LabelStmt *L) {
if (IndirectBranch == 0)
GetIndirectGotoBlock();
- llvm::BasicBlock *BB = getJumpDestForLabel(L).Block;
+ llvm::BasicBlock *BB = getJumpDestForLabel(L).getBlock();
// Make sure the indirect branch includes all of the address-taken blocks.
IndirectBranch->addDestination(BB);
@@ -666,41 +668,75 @@ llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) {
void CodeGenFunction::PopCleanupBlocks(EHScopeStack::stable_iterator Old) {
assert(Old.isValid());
- EHScopeStack::iterator E = EHStack.find(Old);
- while (EHStack.begin() != E)
- PopCleanupBlock();
+ 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);
+ }
}
-/// Creates a switch instruction to thread branches out of the given
-/// block (which is the exit block of a cleanup).
-static void CreateCleanupSwitch(CodeGenFunction &CGF,
- llvm::BasicBlock *Block) {
- if (Block->getTerminator()) {
- assert(isa<llvm::SwitchInst>(Block->getTerminator()) &&
- "cleanup block already has a terminator, but it isn't a switch");
- return;
+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;
+}
- llvm::Value *DestCodePtr
- = CGF.CreateTempAlloca(CGF.Builder.getInt32Ty(), "cleanup.dst");
- CGBuilderTy Builder(Block);
- llvm::Value *DestCode = Builder.CreateLoad(DestCodePtr, "tmp");
+static llvm::BasicBlock *CreateEHEntry(CodeGenFunction &CGF,
+ EHCleanupScope &Scope) {
+ assert(Scope.isEHCleanup());
+ llvm::BasicBlock *Entry = Scope.getEHBlock();
+ if (!Entry) {
+ Entry = CGF.createBasicBlock("eh.cleanup");
+ Scope.setEHBlock(Entry);
+ }
+ return Entry;
+}
- // Create a switch instruction to determine where to jump next.
- Builder.CreateSwitch(DestCode, CGF.getUnreachableBlock());
+/// Transitions the terminator of the given exit-block of a cleanup to
+/// be a cleanup switch.
+static llvm::SwitchInst *TransitionToCleanupSwitch(CodeGenFunction &CGF,
+ llvm::BasicBlock *Block) {
+ // If it's a branch, turn it into a switch whose default
+ // destination is its original target.
+ 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);
+ }
}
/// Attempts to reduce a cleanup's entry block to a fallthrough. This
/// is basically llvm::MergeBlockIntoPredecessor, except
-/// simplified/optimized for the tighter constraints on cleanup
-/// blocks.
-static void SimplifyCleanupEntry(CodeGenFunction &CGF,
- llvm::BasicBlock *Entry) {
+/// simplified/optimized for the tighter constraints on cleanup blocks.
+///
+/// Returns the new block, whatever it is.
+static llvm::BasicBlock *SimplifyCleanupEntry(CodeGenFunction &CGF,
+ llvm::BasicBlock *Entry) {
llvm::BasicBlock *Pred = Entry->getSinglePredecessor();
- if (!Pred) return;
+ if (!Pred) return Entry;
llvm::BranchInst *Br = dyn_cast<llvm::BranchInst>(Pred->getTerminator());
- if (!Br || Br->isConditional()) return;
+ if (!Br || Br->isConditional()) return Entry;
assert(Br->getSuccessor(0) == Entry);
// If we were previously inserting at the end of