Add cleanups for exceptional edges. WIP.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@90940 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp
index 923f1f8..14ee90d 100644
--- a/lib/CodeGen/CGDecl.cpp
+++ b/lib/CodeGen/CGDecl.cpp
@@ -581,22 +581,39 @@
if (const ConstantArrayType *Array =
getContext().getAsConstantArrayType(Ty)) {
- DelayedCleanupBlock Scope(*this);
- QualType BaseElementTy = getContext().getBaseElementType(Array);
- const llvm::Type *BasePtr = ConvertType(BaseElementTy);
- BasePtr = llvm::PointerType::getUnqual(BasePtr);
- llvm::Value *BaseAddrPtr =
- Builder.CreateBitCast(DeclPtr, BasePtr);
- EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
+ {
+ DelayedCleanupBlock Scope(*this);
+ QualType BaseElementTy = getContext().getBaseElementType(Array);
+ const llvm::Type *BasePtr = ConvertType(BaseElementTy);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ Builder.CreateBitCast(DeclPtr, BasePtr);
+ EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
- // Make sure to jump to the exit block.
- EmitBranch(Scope.getCleanupExitBlock());
+ // Make sure to jump to the exit block.
+ EmitBranch(Scope.getCleanupExitBlock());
+ }
+ if (Exceptions) {
+ EHCleanupBlock Cleanup(*this);
+ QualType BaseElementTy = getContext().getBaseElementType(Array);
+ const llvm::Type *BasePtr = ConvertType(BaseElementTy);
+ BasePtr = llvm::PointerType::getUnqual(BasePtr);
+ llvm::Value *BaseAddrPtr =
+ Builder.CreateBitCast(DeclPtr, BasePtr);
+ EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
+ }
} else {
- DelayedCleanupBlock Scope(*this);
- EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
+ {
+ DelayedCleanupBlock Scope(*this);
+ EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
- // Make sure to jump to the exit block.
- EmitBranch(Scope.getCleanupExitBlock());
+ // Make sure to jump to the exit block.
+ EmitBranch(Scope.getCleanupExitBlock());
+ }
+ if (Exceptions) {
+ EHCleanupBlock Cleanup(*this);
+ EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
+ }
}
}
}
@@ -608,8 +625,6 @@
llvm::Constant* F = CGM.GetAddrOfFunction(FD);
assert(F && "Could not find function!");
- DelayedCleanupBlock scope(*this);
-
const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD);
// In some cases, the type of the function argument will be different from
@@ -619,20 +634,40 @@
//
// To fix this we insert a bitcast here.
QualType ArgTy = Info.arg_begin()->type;
- DeclPtr = Builder.CreateBitCast(DeclPtr, ConvertType(ArgTy));
+ {
+ DelayedCleanupBlock scope(*this);
- CallArgList Args;
- Args.push_back(std::make_pair(RValue::get(DeclPtr),
- getContext().getPointerType(D.getType())));
+ CallArgList Args;
+ Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr,
+ ConvertType(ArgTy))),
+ getContext().getPointerType(D.getType())));
+ EmitCall(Info, F, Args);
+ }
+ if (Exceptions) {
+ EHCleanupBlock Cleanup(*this);
- EmitCall(Info, F, Args);
+ CallArgList Args;
+ Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr,
+ ConvertType(ArgTy))),
+ getContext().getPointerType(D.getType())));
+ EmitCall(Info, F, Args);
+ }
}
if (needsDispose && CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) {
- DelayedCleanupBlock scope(*this);
- llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
- V = Builder.CreateLoad(V);
- BuildBlockRelease(V);
+ {
+ DelayedCleanupBlock scope(*this);
+ llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
+ V = Builder.CreateLoad(V);
+ BuildBlockRelease(V);
+ }
+ // FIXME: Turn this on and audit the codegen
+ if (0 && Exceptions) {
+ EHCleanupBlock Cleanup(*this);
+ llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
+ V = Builder.CreateLoad(V);
+ BuildBlockRelease(V);
+ }
}
}
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp
index 11cf9ce..bcb59f5 100644
--- a/lib/CodeGen/CGException.cpp
+++ b/lib/CodeGen/CGException.cpp
@@ -650,3 +650,55 @@
EmitBlock(FinallyEnd);
}
+
+CodeGenFunction::EHCleanupBlock::~EHCleanupBlock() {
+ llvm::BasicBlock *Cont1 = CGF.createBasicBlock("cont");
+ CGF.EmitBranch(Cont1);
+ CGF.setInvokeDest(PreviousInvokeDest);
+
+
+ CGF.EmitBlock(CleanupHandler);
+
+ llvm::Constant *Personality =
+ CGF.CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
+ (CGF.VMContext),
+ true),
+ "__gxx_personality_v0");
+ Personality = llvm::ConstantExpr::getBitCast(Personality, CGF.PtrToInt8Ty);
+ llvm::Value *llvm_eh_exception =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
+ llvm::Value *llvm_eh_selector =
+ CGF.CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
+
+ llvm::Value *Exc = CGF.Builder.CreateCall(llvm_eh_exception, "exc");
+ const llvm::IntegerType *Int8Ty;
+ const llvm::PointerType *PtrToInt8Ty;
+ Int8Ty = llvm::Type::getInt8Ty(CGF.VMContext);
+ // C string type. Used in lots of places.
+ PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
+ llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
+ llvm::SmallVector<llvm::Value*, 8> Args;
+ Args.clear();
+ Args.push_back(Exc);
+ Args.push_back(Personality);
+ Args.push_back(Null);
+ CGF.Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
+
+ CGF.EmitBlock(CleanupEntryBB);
+
+ CGF.EmitBlock(Cont1);
+
+ if (CGF.getInvokeDest()) {
+ llvm::BasicBlock *Cont = CGF.createBasicBlock("invoke.cont");
+ CGF.Builder.CreateInvoke(getUnwindResumeOrRethrowFn(CGF), Cont,
+ CGF.getInvokeDest(), Exc);
+ CGF.EmitBlock(Cont);
+ } else
+ CGF.Builder.CreateCall(getUnwindResumeOrRethrowFn(CGF), Exc);
+
+ CGF.Builder.CreateUnreachable();
+
+ CGF.EmitBlock(Cont);
+ if (CGF.Exceptions)
+ CGF.setInvokeDest(CleanupHandler);
+}
diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp
index 87f53e8..fde944f 100644
--- a/lib/CodeGen/CGExpr.cpp
+++ b/lib/CodeGen/CGExpr.cpp
@@ -137,8 +137,16 @@
const CXXDestructorDecl *Dtor =
ClassDecl->getDestructor(getContext());
- DelayedCleanupBlock scope(*this);
- EmitCXXDestructorCall(Dtor, Dtor_Complete, Val.getAggregateAddr());
+ {
+ DelayedCleanupBlock scope(*this);
+ EmitCXXDestructorCall(Dtor, Dtor_Complete,
+ Val.getAggregateAddr());
+ }
+ if (Exceptions) {
+ EHCleanupBlock Cleanup(*this);
+ EmitCXXDestructorCall(Dtor, Dtor_Complete,
+ Val.getAggregateAddr());
+ }
}
}
}
diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp
index 4b32999..adfd75b 100644
--- a/lib/CodeGen/CodeGenFunction.cpp
+++ b/lib/CodeGen/CodeGenFunction.cpp
@@ -34,6 +34,7 @@
ConditionalBranchLevel(0) {
LLVMIntTy = ConvertType(getContext().IntTy);
LLVMPointerWidth = Target.getPointerWidth(0);
+ Exceptions = getContext().getLangOptions().Exceptions;
}
ASTContext &CodeGenFunction::getContext() const {
@@ -625,9 +626,10 @@
void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock,
llvm::BasicBlock *CleanupExitBlock,
+ llvm::BasicBlock *PreviousInvokeDest,
bool EHOnly) {
CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock,
- EHOnly));
+ PreviousInvokeDest, EHOnly));
}
void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize) {
@@ -651,6 +653,8 @@
bool EHOnly = CE.EHOnly;
+ setInvokeDest(CE.PreviousInvokeDest);
+
CleanupEntries.pop_back();
// Check if any branch fixups pointed to the scope we just popped. If so,
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 854eb53..5e23e26 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -107,6 +107,7 @@
const llvm::Type *LLVMIntTy;
uint32_t LLVMPointerWidth;
+ bool Exceptions;
public:
/// ObjCEHValueStack - Stack of Objective-C exception values, used for
/// rethrows.
@@ -115,8 +116,12 @@
/// PushCleanupBlock - Push a new cleanup entry on the stack and set the
/// passed in block as the cleanup block.
void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock,
- llvm::BasicBlock *CleanupExitBlock = 0,
+ llvm::BasicBlock *CleanupExitBlock,
+ llvm::BasicBlock *PreviousInvokeDest,
bool EHOnly = false);
+ void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock) {
+ PushCleanupBlock(CleanupEntryBlock, 0, getInvokeDest(), false);
+ }
/// CleanupBlockInfo - A struct representing a popped cleanup block.
struct CleanupBlockInfo {
@@ -139,9 +144,35 @@
: CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb), EHOnly(ehonly) {}
};
+ /// EHCleanupBlock - RAII object that will create a cleanup block for the
+ /// exceptional edge and set the insert point to that block. When destroyed,
+ /// it creates the cleanup edge and sets the insert point to the previous
+ /// block.
+ class EHCleanupBlock {
+ CodeGenFunction& CGF;
+ llvm::BasicBlock *Cont;
+ llvm::BasicBlock *CleanupHandler;
+ llvm::BasicBlock *CleanupEntryBB;
+ llvm::BasicBlock *PreviousInvokeDest;
+ public:
+ EHCleanupBlock(CodeGenFunction &cgf)
+ : CGF(cgf), Cont(CGF.createBasicBlock("cont")),
+ CleanupHandler(CGF.createBasicBlock("ehcleanup")),
+ CleanupEntryBB(CGF.createBasicBlock("ehcleanup.rest")),
+ PreviousInvokeDest(CGF.getInvokeDest()) {
+ CGF.EmitBranch(Cont);
+ CGF.Builder.SetInsertPoint(CleanupEntryBB);
+
+ // FIXME: set up terminate handler here
+ // CGF.setInvokeDest(TerminateHandler);
+ }
+ ~EHCleanupBlock();
+ };
+
/// PopCleanupBlock - Will pop the cleanup entry on the stack, process all
/// branch fixups and return a block info struct with the switch block and end
- /// block.
+ /// block. This will also reset the invoke handler to the previous value
+ /// from when the cleanup block was created.
CleanupBlockInfo PopCleanupBlock();
/// DelayedCleanupBlock - RAII object that will create a cleanup block and set
@@ -152,13 +183,15 @@
llvm::BasicBlock *CurBB;
llvm::BasicBlock *CleanupEntryBB;
llvm::BasicBlock *CleanupExitBB;
+ llvm::BasicBlock *CurInvokeDest;
bool EHOnly;
public:
DelayedCleanupBlock(CodeGenFunction &cgf, bool ehonly = false)
: CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()),
- CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0),
- EHOnly(ehonly) {
+ CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0),
+ CurInvokeDest(CGF.getInvokeDest()),
+ EHOnly(ehonly) {
CGF.Builder.SetInsertPoint(CleanupEntryBB);
}
@@ -169,7 +202,8 @@
}
~DelayedCleanupBlock() {
- CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB, EHOnly);
+ CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB, CurInvokeDest,
+ EHOnly);
// FIXME: This is silly, move this into the builder.
if (CurBB)
CGF.Builder.SetInsertPoint(CurBB);
@@ -316,13 +350,20 @@
/// inserted into the current function yet.
std::vector<llvm::BranchInst *> BranchFixups;
+ /// PreviousInvokeDest - The invoke handler from the start of the cleanup
+ /// region.
+ llvm::BasicBlock *PreviousInvokeDest;
+
/// EHOnly - Perform this only on the exceptional edge, not the main edge.
bool EHOnly;
explicit CleanupEntry(llvm::BasicBlock *CleanupEntryBlock,
- llvm::BasicBlock *CleanupExitBlock, bool ehonly)
- : CleanupEntryBlock(CleanupEntryBlock),
+ llvm::BasicBlock *CleanupExitBlock,
+ llvm::BasicBlock *PreviousInvokeDest,
+ bool ehonly)
+ : CleanupEntryBlock(CleanupEntryBlock),
CleanupExitBlock(CleanupExitBlock),
+ PreviousInvokeDest(PreviousInvokeDest),
EHOnly(ehonly) {}
};