diff options
author | rdivacky <rdivacky@FreeBSD.org> | 2009-12-01 11:08:04 +0000 |
---|---|---|
committer | rdivacky <rdivacky@FreeBSD.org> | 2009-12-01 11:08:04 +0000 |
commit | 4b08eb6308ca90a6c08e2fc79d100821b1b1f6aa (patch) | |
tree | 867cbbe32a66fd7d62dd9ce9df23a23fefdb8290 /lib/CodeGen/CGException.cpp | |
parent | 6df2408694f81a03eb8b0e3b013272042233c061 (diff) | |
download | FreeBSD-src-4b08eb6308ca90a6c08e2fc79d100821b1b1f6aa.zip FreeBSD-src-4b08eb6308ca90a6c08e2fc79d100821b1b1f6aa.tar.gz |
Update clang to r90226.
Diffstat (limited to 'lib/CodeGen/CGException.cpp')
-rw-r--r-- | lib/CodeGen/CGException.cpp | 390 |
1 files changed, 360 insertions, 30 deletions
diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index adfd005..420e275 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -11,6 +11,10 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/StmtCXX.h" + +#include "llvm/Intrinsics.h" + #include "CodeGenFunction.h" using namespace clang; using namespace CodeGen; @@ -35,29 +39,158 @@ static llvm::Constant *getThrowFn(CodeGenFunction &CGF) { std::vector<const llvm::Type*> Args(3, Int8PtrTy); const llvm::FunctionType *FTy = - llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), - Args, false); + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), + Args, false); return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw"); } +static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) { + // void __cxa_rethrow (); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow"); +} + +static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) { + // void* __cxa_begin_catch (); + + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + std::vector<const llvm::Type*> Args(1, Int8PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(Int8PtrTy, Args, false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch"); +} + +static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) { + // void __cxa_end_catch (); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false); + + return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch"); +} + +// FIXME: Eventually this will all go into the backend. Set from the target for +// now. +static int using_sjlj_exceptions = 0; + +static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) { + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext()); + std::vector<const llvm::Type*> Args(1, Int8PtrTy); + + const llvm::FunctionType *FTy = + llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args, + false); + + if (using_sjlj_exceptions) + return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume"); + return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow"); +} + +// CopyObject - Utility to copy an object. Calls copy constructor as necessary. +// N is casted to the right type. +static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) { + QualType ObjectType = E->getType(); + + // Store the throw exception in the exception object. + if (!CGF.hasAggregateLLVMType(ObjectType)) { + llvm::Value *Value = CGF.EmitScalarExpr(E); + const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); + + CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); + } else { + const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); + const CXXRecordDecl *RD; + RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); + llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty); + if (RD->hasTrivialCopyConstructor()) { + CGF.EmitAggExpr(E, This, false); + } else if (CXXConstructorDecl *CopyCtor + = RD->getCopyConstructor(CGF.getContext(), 0)) { + // FIXME: region management + llvm::Value *Src = CGF.EmitLValue(E).getAddress(); + + // Stolen from EmitClassAggrMemberwiseCopy + llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, + Ctor_Complete); + CallArgList CallArgs; + CallArgs.push_back(std::make_pair(RValue::get(This), + CopyCtor->getThisType(CGF.getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + CopyCtor->getParamDecl(0)->getType())); + QualType ResultType = + CopyCtor->getType()->getAs<FunctionType>()->getResultType(); + CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, CopyCtor); + // FIXME: region management + } else + CGF.ErrorUnsupported(E, "uncopyable object"); + } +} + +// CopyObject - Utility to copy an object. Calls copy constructor as necessary. +// N is casted to the right type. +static void CopyObject(CodeGenFunction &CGF, QualType ObjectType, + llvm::Value *E, llvm::Value *N) { + // Store the throw exception in the exception object. + if (!CGF.hasAggregateLLVMType(ObjectType)) { + llvm::Value *Value = E; + const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); + + CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy)); + } else { + const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0); + const CXXRecordDecl *RD; + RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl()); + llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty); + if (RD->hasTrivialCopyConstructor()) { + CGF.EmitAggregateCopy(This, E, ObjectType); + } else if (CXXConstructorDecl *CopyCtor + = RD->getCopyConstructor(CGF.getContext(), 0)) { + // FIXME: region management + llvm::Value *Src = E; + + // Stolen from EmitClassAggrMemberwiseCopy + llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor, + Ctor_Complete); + CallArgList CallArgs; + CallArgs.push_back(std::make_pair(RValue::get(This), + CopyCtor->getThisType(CGF.getContext()))); + + // Push the Src ptr. + CallArgs.push_back(std::make_pair(RValue::get(Src), + CopyCtor->getParamDecl(0)->getType())); + QualType ResultType = + CopyCtor->getType()->getAs<FunctionType>()->getResultType(); + CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs), + Callee, CallArgs, CopyCtor); + // FIXME: region management + } else + llvm::llvm_unreachable("uncopyable object"); + } +} + void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { - // FIXME: Handle rethrows. if (!E->getSubExpr()) { - ErrorUnsupported(E, "rethrow expression"); + Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn(); + Builder.CreateUnreachable(); + + // Clear the insertion point to indicate we are in unreachable code. + Builder.ClearInsertionPoint(); return; } QualType ThrowType = E->getSubExpr()->getType(); - // FIXME: We only handle non-class types for now. - if (ThrowType->isRecordType()) { - ErrorUnsupported(E, "throw expression"); - return; - } - // FIXME: Handle cleanup. if (!CleanupEntries.empty()){ - ErrorUnsupported(E, "throw expression"); + ErrorUnsupported(E, "throw expression with cleanup entries"); return; } @@ -71,28 +204,11 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { llvm::ConstantInt::get(SizeTy, TypeSize), "exception"); - // Store the throw exception in the exception object. - if (!hasAggregateLLVMType(ThrowType)) { - llvm::Value *Value = EmitScalarExpr(E->getSubExpr()); - const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0); - - Builder.CreateStore(Value, Builder.CreateBitCast(ExceptionPtr, ValuePtrTy)); - } else { - // FIXME: Handle complex and aggregate expressions. - ErrorUnsupported(E, "throw expression"); - } + CopyObject(*this, E->getSubExpr(), ExceptionPtr); // Now throw the exception. const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); - - llvm::SmallString<256> OutName; - llvm::raw_svector_ostream Out(OutName); - mangleCXXRtti(CGM.getMangleContext(), ThrowType, Out); - - // FIXME: Is it OK to use CreateRuntimeVariable for this? - llvm::Constant *TypeInfo = - CGM.CreateRuntimeVariable(llvm::Type::getInt8Ty(getLLVMContext()), - OutName.c_str()); + llvm::Constant *TypeInfo = CGM.GenerateRtti(ThrowType); llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy); llvm::CallInst *ThrowCall = @@ -103,3 +219,217 @@ void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) { // Clear the insertion point to indicate we are in unreachable code. Builder.ClearInsertionPoint(); } + +void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) { +#if 1 + EmitStmt(S.getTryBlock()); + if (0) { + getBeginCatchFn(*this); + getEndCatchFn(*this); + getUnwindResumeOrRethrowFn(*this); + CopyObject(*this, QualType(), 0, 0); + } +#else + // FIXME: The below is still just a sketch of the code we need. + // Pointer to the personality function + llvm::Constant *Personality = + CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty + (VMContext), + true), + "__gxx_personality_v0"); + Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty); + + llvm::BasicBlock *PrevLandingPad = getInvokeDest(); + llvm::BasicBlock *TryHandler = createBasicBlock("try.handler"); +#if 0 + llvm::BasicBlock *FinallyBlock = createBasicBlock("finally"); +#endif + llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw"); + llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end"); + +#if 0 + // Push an EH context entry, used for handling rethrows. + PushCleanupBlock(FinallyBlock); +#endif + + // Emit the statements in the try {} block + setInvokeDest(TryHandler); + + EmitStmt(S.getTryBlock()); + + // Jump to end if there is no exception + EmitBranchThroughCleanup(FinallyEnd); + + // Emit the handlers + EmitBlock(TryHandler); + + const llvm::IntegerType *Int8Ty; + const llvm::PointerType *PtrToInt8Ty; + Int8Ty = llvm::Type::getInt8Ty(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> SelectorArgs; + llvm::Value *llvm_eh_exception = + CGM.getIntrinsic(llvm::Intrinsic::eh_exception); + llvm::Value *llvm_eh_selector = + CGM.getIntrinsic(llvm::Intrinsic::eh_selector); + llvm::Value *llvm_eh_typeid_for = + CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for); + // Exception object + llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); + llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow"); + + SelectorArgs.push_back(Exc); + SelectorArgs.push_back(Personality); + + bool HasCatchAll = false; + for (unsigned i = 0; i<S.getNumHandlers(); ++i) { + const CXXCatchStmt *C = S.getHandler(i); + VarDecl *CatchParam = C->getExceptionDecl(); + if (CatchParam) { + llvm::Value *EHType = CGM.GenerateRtti(C->getCaughtType().getNonReferenceType()); + SelectorArgs.push_back(EHType); + } else { + // null indicates catch all + SelectorArgs.push_back(Null); + HasCatchAll = true; + } + } + + // We use a cleanup unless there was already a catch all. + if (!HasCatchAll) { + SelectorArgs.push_back(Null); + } + + // Find which handler was matched. + llvm::Value *Selector + = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(), + SelectorArgs.end(), "selector"); + for (unsigned i = 0; i<S.getNumHandlers(); ++i) { + const CXXCatchStmt *C = S.getHandler(i); + VarDecl *CatchParam = C->getExceptionDecl(); + Stmt *CatchBody = C->getHandlerBlock(); + + llvm::BasicBlock *Next = 0; + + if (SelectorArgs[i+2] != Null) { + llvm::BasicBlock *Match = createBasicBlock("match"); + Next = createBasicBlock("catch.next"); + const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext()); + llvm::Value *Id + = Builder.CreateCall(llvm_eh_typeid_for, + Builder.CreateBitCast(SelectorArgs[i+2], + Int8PtrTy)); + Builder.CreateCondBr(Builder.CreateICmpEQ(Selector, Id), + Match, Next); + EmitBlock(Match); + } + + llvm::BasicBlock *MatchEnd = createBasicBlock("match.end"); + llvm::BasicBlock *MatchHandler = createBasicBlock("match.handler"); + + PushCleanupBlock(MatchEnd); + setInvokeDest(MatchHandler); + + llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc); + + // Bind the catch parameter if it exists. + if (CatchParam) { + QualType CatchType = CatchParam->getType().getNonReferenceType(); + if (!CatchType.getTypePtr()->isPointerType()) + CatchType = getContext().getPointerType(CatchType); + ExcObject = + Builder.CreateBitCast(ExcObject, ConvertType(CatchType)); + // CatchParam is a ParmVarDecl because of the grammar + // construction used to handle this, but for codegen purposes + // we treat this as a local decl. + EmitLocalBlockVarDecl(*CatchParam); +#if 0 + // FIXME: objects with ctors, references + Builder.CreateStore(ExcObject, GetAddrOfLocalVar(CatchParam)); +#else + CopyObject(*this, CatchParam->getType().getNonReferenceType(), + ExcObject, GetAddrOfLocalVar(CatchParam)); +#endif + } + + EmitStmt(CatchBody); + EmitBranchThroughCleanup(FinallyEnd); + + EmitBlock(MatchHandler); + + llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc"); + // We are required to emit this call to satisfy LLVM, even + // though we don't use the result. + llvm::SmallVector<llvm::Value*, 8> Args; + Args.push_back(Exc); + Args.push_back(Personality); + Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + 0)); + Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + Builder.CreateStore(Exc, RethrowPtr); + EmitBranchThroughCleanup(FinallyRethrow); + + CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); + + EmitBlock(MatchEnd); + + // Unfortunately, we also have to generate another EH frame here + // in case this throws. + llvm::BasicBlock *MatchEndHandler = + createBasicBlock("match.end.handler"); + llvm::BasicBlock *Cont = createBasicBlock("myinvoke.cont"); + Builder.CreateInvoke(getEndCatchFn(*this), + Cont, MatchEndHandler, + Args.begin(), Args.begin()); + + EmitBlock(Cont); + if (Info.SwitchBlock) + EmitBlock(Info.SwitchBlock); + if (Info.EndBlock) + EmitBlock(Info.EndBlock); + + EmitBlock(MatchEndHandler); + Exc = Builder.CreateCall(llvm_eh_exception, "exc"); + // We are required to emit this call to satisfy LLVM, even + // though we don't use the result. + Args.clear(); + Args.push_back(Exc); + Args.push_back(Personality); + Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), + 0)); + Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end()); + Builder.CreateStore(Exc, RethrowPtr); + EmitBranchThroughCleanup(FinallyRethrow); + + if (Next) + EmitBlock(Next); + } + if (!HasCatchAll) + EmitBranchThroughCleanup(FinallyRethrow); + + CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock(); + + setInvokeDest(PrevLandingPad); + +#if 0 + EmitBlock(FinallyBlock); + + if (Info.SwitchBlock) + EmitBlock(Info.SwitchBlock); + if (Info.EndBlock) + EmitBlock(Info.EndBlock); + + // Branch around the rethrow code. + EmitBranch(FinallyEnd); +#endif + + EmitBlock(FinallyRethrow); + Builder.CreateCall(getUnwindResumeOrRethrowFn(*this), + Builder.CreateLoad(RethrowPtr)); + Builder.CreateUnreachable(); + + EmitBlock(FinallyEnd); +#endif +} |