Add cleanups for exceptional edges. WIP.

llvm-svn: 90940
This commit is contained in:
Mike Stump 2009-12-09 03:35:49 +00:00
parent daa3d6bb50
commit aff69af918
5 changed files with 174 additions and 34 deletions

View File

@ -581,22 +581,39 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
if (const ConstantArrayType *Array = if (const ConstantArrayType *Array =
getContext().getAsConstantArrayType(Ty)) { getContext().getAsConstantArrayType(Ty)) {
DelayedCleanupBlock Scope(*this); {
QualType BaseElementTy = getContext().getBaseElementType(Array); DelayedCleanupBlock Scope(*this);
const llvm::Type *BasePtr = ConvertType(BaseElementTy); QualType BaseElementTy = getContext().getBaseElementType(Array);
BasePtr = llvm::PointerType::getUnqual(BasePtr); const llvm::Type *BasePtr = ConvertType(BaseElementTy);
llvm::Value *BaseAddrPtr = BasePtr = llvm::PointerType::getUnqual(BasePtr);
Builder.CreateBitCast(DeclPtr, BasePtr); llvm::Value *BaseAddrPtr =
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr); Builder.CreateBitCast(DeclPtr, BasePtr);
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
// Make sure to jump to the exit block. // Make sure to jump to the exit block.
EmitBranch(Scope.getCleanupExitBlock()); 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 { } 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. // Make sure to jump to the exit block.
EmitBranch(Scope.getCleanupExitBlock()); EmitBranch(Scope.getCleanupExitBlock());
}
if (Exceptions) {
EHCleanupBlock Cleanup(*this);
EmitCXXDestructorCall(D, Dtor_Complete, DeclPtr);
}
} }
} }
} }
@ -608,8 +625,6 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
llvm::Constant* F = CGM.GetAddrOfFunction(FD); llvm::Constant* F = CGM.GetAddrOfFunction(FD);
assert(F && "Could not find function!"); assert(F && "Could not find function!");
DelayedCleanupBlock scope(*this);
const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD); const CGFunctionInfo &Info = CGM.getTypes().getFunctionInfo(FD);
// In some cases, the type of the function argument will be different from // In some cases, the type of the function argument will be different from
@ -619,20 +634,40 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// //
// To fix this we insert a bitcast here. // To fix this we insert a bitcast here.
QualType ArgTy = Info.arg_begin()->type; QualType ArgTy = Info.arg_begin()->type;
DeclPtr = Builder.CreateBitCast(DeclPtr, ConvertType(ArgTy)); {
DelayedCleanupBlock scope(*this);
CallArgList Args; CallArgList Args;
Args.push_back(std::make_pair(RValue::get(DeclPtr), Args.push_back(std::make_pair(RValue::get(Builder.CreateBitCast(DeclPtr,
getContext().getPointerType(D.getType()))); 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) { if (needsDispose && CGM.getLangOptions().getGCMode() != LangOptions::GCOnly) {
DelayedCleanupBlock scope(*this); {
llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding"); DelayedCleanupBlock scope(*this);
V = Builder.CreateLoad(V); llvm::Value *V = Builder.CreateStructGEP(DeclPtr, 1, "forwarding");
BuildBlockRelease(V); 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);
}
} }
} }

View File

@ -650,3 +650,55 @@ void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
EmitBlock(FinallyEnd); 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);
}

View File

@ -137,8 +137,16 @@ RValue CodeGenFunction::EmitReferenceBindingToExpr(const Expr* E,
const CXXDestructorDecl *Dtor = const CXXDestructorDecl *Dtor =
ClassDecl->getDestructor(getContext()); 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());
}
} }
} }
} }

View File

@ -34,6 +34,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm)
ConditionalBranchLevel(0) { ConditionalBranchLevel(0) {
LLVMIntTy = ConvertType(getContext().IntTy); LLVMIntTy = ConvertType(getContext().IntTy);
LLVMPointerWidth = Target.getPointerWidth(0); LLVMPointerWidth = Target.getPointerWidth(0);
Exceptions = getContext().getLangOptions().Exceptions;
} }
ASTContext &CodeGenFunction::getContext() const { ASTContext &CodeGenFunction::getContext() const {
@ -625,9 +626,10 @@ llvm::Value* CodeGenFunction::EmitVAListRef(const Expr* E) {
void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock, void CodeGenFunction::PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock,
llvm::BasicBlock *CleanupExitBlock, llvm::BasicBlock *CleanupExitBlock,
llvm::BasicBlock *PreviousInvokeDest,
bool EHOnly) { bool EHOnly) {
CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock, CleanupEntries.push_back(CleanupEntry(CleanupEntryBlock, CleanupExitBlock,
EHOnly)); PreviousInvokeDest, EHOnly));
} }
void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize) { void CodeGenFunction::EmitCleanupBlocks(size_t OldCleanupStackSize) {
@ -651,6 +653,8 @@ CodeGenFunction::CleanupBlockInfo CodeGenFunction::PopCleanupBlock() {
bool EHOnly = CE.EHOnly; bool EHOnly = CE.EHOnly;
setInvokeDest(CE.PreviousInvokeDest);
CleanupEntries.pop_back(); CleanupEntries.pop_back();
// Check if any branch fixups pointed to the scope we just popped. If so, // Check if any branch fixups pointed to the scope we just popped. If so,

View File

@ -107,6 +107,7 @@ public:
const llvm::Type *LLVMIntTy; const llvm::Type *LLVMIntTy;
uint32_t LLVMPointerWidth; uint32_t LLVMPointerWidth;
bool Exceptions;
public: public:
/// ObjCEHValueStack - Stack of Objective-C exception values, used for /// ObjCEHValueStack - Stack of Objective-C exception values, used for
/// rethrows. /// rethrows.
@ -115,8 +116,12 @@ public:
/// PushCleanupBlock - Push a new cleanup entry on the stack and set the /// PushCleanupBlock - Push a new cleanup entry on the stack and set the
/// passed in block as the cleanup block. /// passed in block as the cleanup block.
void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock, void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock,
llvm::BasicBlock *CleanupExitBlock = 0, llvm::BasicBlock *CleanupExitBlock,
llvm::BasicBlock *PreviousInvokeDest,
bool EHOnly = false); bool EHOnly = false);
void PushCleanupBlock(llvm::BasicBlock *CleanupEntryBlock) {
PushCleanupBlock(CleanupEntryBlock, 0, getInvokeDest(), false);
}
/// CleanupBlockInfo - A struct representing a popped cleanup block. /// CleanupBlockInfo - A struct representing a popped cleanup block.
struct CleanupBlockInfo { struct CleanupBlockInfo {
@ -139,9 +144,35 @@ public:
: CleanupBlock(cb), SwitchBlock(sb), EndBlock(eb), EHOnly(ehonly) {} : 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 /// 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 /// 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(); CleanupBlockInfo PopCleanupBlock();
/// DelayedCleanupBlock - RAII object that will create a cleanup block and set /// DelayedCleanupBlock - RAII object that will create a cleanup block and set
@ -152,13 +183,15 @@ public:
llvm::BasicBlock *CurBB; llvm::BasicBlock *CurBB;
llvm::BasicBlock *CleanupEntryBB; llvm::BasicBlock *CleanupEntryBB;
llvm::BasicBlock *CleanupExitBB; llvm::BasicBlock *CleanupExitBB;
llvm::BasicBlock *CurInvokeDest;
bool EHOnly; bool EHOnly;
public: public:
DelayedCleanupBlock(CodeGenFunction &cgf, bool ehonly = false) DelayedCleanupBlock(CodeGenFunction &cgf, bool ehonly = false)
: CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()), : CGF(cgf), CurBB(CGF.Builder.GetInsertBlock()),
CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0), CleanupEntryBB(CGF.createBasicBlock("cleanup")), CleanupExitBB(0),
EHOnly(ehonly) { CurInvokeDest(CGF.getInvokeDest()),
EHOnly(ehonly) {
CGF.Builder.SetInsertPoint(CleanupEntryBB); CGF.Builder.SetInsertPoint(CleanupEntryBB);
} }
@ -169,7 +202,8 @@ public:
} }
~DelayedCleanupBlock() { ~DelayedCleanupBlock() {
CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB, EHOnly); CGF.PushCleanupBlock(CleanupEntryBB, CleanupExitBB, CurInvokeDest,
EHOnly);
// FIXME: This is silly, move this into the builder. // FIXME: This is silly, move this into the builder.
if (CurBB) if (CurBB)
CGF.Builder.SetInsertPoint(CurBB); CGF.Builder.SetInsertPoint(CurBB);
@ -316,13 +350,20 @@ private:
/// inserted into the current function yet. /// inserted into the current function yet.
std::vector<llvm::BranchInst *> BranchFixups; 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. /// EHOnly - Perform this only on the exceptional edge, not the main edge.
bool EHOnly; bool EHOnly;
explicit CleanupEntry(llvm::BasicBlock *CleanupEntryBlock, explicit CleanupEntry(llvm::BasicBlock *CleanupEntryBlock,
llvm::BasicBlock *CleanupExitBlock, bool ehonly) llvm::BasicBlock *CleanupExitBlock,
: CleanupEntryBlock(CleanupEntryBlock), llvm::BasicBlock *PreviousInvokeDest,
bool ehonly)
: CleanupEntryBlock(CleanupEntryBlock),
CleanupExitBlock(CleanupExitBlock), CleanupExitBlock(CleanupExitBlock),
PreviousInvokeDest(PreviousInvokeDest),
EHOnly(ehonly) {} EHOnly(ehonly) {}
}; };