Revision: 124438 Author: jlaskey Date: 2007-03-01 15:11:13 -0800 (Thu, 01 Mar 2007)
Log Message: ----------- EH support. Modified Paths: -------------- apple-local/branches/llvm/gcc/llvm-convert.cpp apple-local/branches/llvm/gcc/llvm-internal.h Modified: apple-local/branches/llvm/gcc/llvm-convert.cpp =================================================================== --- apple-local/branches/llvm/gcc/llvm-convert.cpp 2007-03-01 10:54:52 UTC (rev 124437) +++ apple-local/branches/llvm/gcc/llvm-convert.cpp 2007-03-01 23:11:13 UTC (rev 124438) @@ -58,10 +58,13 @@ #include "flags.h" #include "target.h" #include "hard-reg-set.h" +#include "except.h" extern bool tree_could_throw_p(tree); // tree-flow.h uses non-C++ C constructs. extern int get_pointer_alignment (tree exp, unsigned int max_align); } +#define ITANIUM_STYLE_EXCEPTIONS + //===----------------------------------------------------------------------===// // Matching LLVM Values with GCC DECL trees //===----------------------------------------------------------------------===// @@ -261,6 +264,16 @@ } AllocaInsertionPoint = 0; + + ExceptionValue = 0; + ExceptionSelectorValue = 0; + FuncEHException = 0; + FuncEHSelector = 0; + FuncEHFilter = 0; + FuncEHGetTypeID = 0; + FuncCPPPersonality = 0; + FuncUnwindResume = 0; + NumAddressTakenBlocks = 0; IndirectGotoBlock = 0; CurrentEHScopes.reserve(16); @@ -596,7 +609,19 @@ // If this function has exceptions, emit the lazily created unwind block. if (UnwindBB) { EmitBlock(UnwindBB); +#ifdef ITANIUM_STYLE_EXCEPTIONS + if (ExceptionValue) { + // Fetch and store exception handler. + std::vector<Value*> Args; + Args.push_back(new LoadInst(ExceptionValue, "eh_ptr", CurBB)); + new CallInst(FuncUnwindResume, + &Args[0], Args.size(), "", + CurBB); + new UnreachableInst(CurBB); + } +#else new UnwindInst(UnwindBB); +#endif } // If this function takes the address of a label, emit the indirect goto @@ -640,15 +665,8 @@ std::cerr << "Unhandled expression!\n"; debug_tree(exp); abort(); - case EH_FILTER_EXPR: - case CATCH_EXPR: { - static bool PrintedWarning = false; - if (!PrintedWarning) std::cerr << "WARNING: EH not supported yet!\n"; - PrintedWarning = true; - return 0; - } - // Basic lists and binding scopes + // Basic lists and binding scopes case BIND_EXPR: Result = EmitBIND_EXPR(exp, DestLoc); break; case STATEMENT_LIST: Result = EmitSTATEMENT_LIST(exp, DestLoc); break; @@ -660,6 +678,9 @@ case SWITCH_EXPR: Result = EmitSWITCH_EXPR(exp); break; case TRY_FINALLY_EXPR: case TRY_CATCH_EXPR: Result = EmitTRY_EXPR(exp); break; + case EXC_PTR_EXPR: Result = EmitEXC_PTR_EXPR(exp); break; + case CATCH_EXPR: Result = EmitCATCH_EXPR(exp); break; + case EH_FILTER_EXPR: Result = EmitEH_FILTER_EXPR(exp); break; // Expressions case VAR_DECL: @@ -1737,6 +1758,132 @@ walk_tree_without_duplicates(&code, StripLLVMTranslationFn, 0); } + +/// GatherTypeInfo - Walk through the expression gathering all the +/// typeinfos that are used. +void TreeToLLVM::GatherTypeInfo(tree exp, + std::vector<Value *> &TypeInfos) { + if (TREE_CODE(exp) == CATCH_EXPR || TREE_CODE(exp) == EH_FILTER_EXPR) { + tree Types = TREE_CODE(exp) == CATCH_EXPR ? CATCH_TYPES(exp) + : EH_FILTER_TYPES(exp); + + if (!Types) { + // Catch all. + TypeInfos.push_back(Constant::getNullValue(Type::Int32Ty)); + } else if (TREE_CODE(Types) != TREE_LIST) { + // Construct typeinfo object. Each call will produce a new expression + // even if duplicate. + tree TypeInfoNopExpr = (*lang_eh_runtime_type)(Types); + // Produce value. Duplicate typeinfo get folded here. + Value *TypeInfo = Emit(TypeInfoNopExpr, 0); + // Capture typeinfo. + TypeInfos.push_back(TypeInfo); + } else { + for (; Types; Types = TREE_CHAIN (Types)) { + // Construct typeinfo object. Each call will produce a new expression + // even if duplicate. + tree TypeInfoNopExpr = (*lang_eh_runtime_type)(TREE_VALUE(Types)); + // Produce value. Duplicate typeinfo get folded here. + Value *TypeInfo = Emit(TypeInfoNopExpr, 0); + // Capture typeinfo. + TypeInfos.push_back(TypeInfo); + } + } + } else { + assert(TREE_CODE(exp) == STATEMENT_LIST && "Need an exp with typeinfo"); + // Each statement in the statement list will be a catch. + for (tree_stmt_iterator I = tsi_start(exp); !tsi_end_p(I); tsi_next(&I)) + GatherTypeInfo(tsi_stmt(I), TypeInfos); + } +} + + +/// AddLandingPad - Insert code to fetch and save the exception and exception +/// selector. +void TreeToLLVM::AddLandingPad() { + tree TryCatch = 0; + for (std::vector<EHScope>::reverse_iterator I = CurrentEHScopes.rbegin(), + E = CurrentEHScopes.rend(); + I != E; ++I) { + if (TREE_CODE(I->TryExpr) == TRY_CATCH_EXPR) { + TryCatch = I->TryExpr; + break; + } + } + + if (!TryCatch) return; + + // Gather the typeinfo. + std::vector<Value *> TypeInfos; + tree Catches = TREE_OPERAND(TryCatch, 1); + GatherTypeInfo(Catches, TypeInfos); + + CreateExceptionValues(); + + // Choose type of landing pad type. + Function *F = FuncEHSelector; + + if (TREE_CODE(Catches) == STATEMENT_LIST && + !tsi_end_p(tsi_start(Catches)) && + TREE_CODE(tsi_stmt(tsi_start(Catches))) == EH_FILTER_EXPR) { + F = FuncEHFilter; + } + + // Fetch and store the exception. + Value *Ex = new CallInst(FuncEHException, "eh_ptr", CurBB); + new StoreInst(Ex, ExceptionValue, CurBB); + + // Fetch and store exception handler. + std::vector<Value*> Args; + Args.push_back(new LoadInst(ExceptionValue, "eh_ptr", CurBB)); + Args.push_back(CastToType(Instruction::BitCast, FuncCPPPersonality, + PointerType::get(Type::Int8Ty))); + for (unsigned i = 0, N = TypeInfos.size(); i < N; ++i) + Args.push_back(TypeInfos[i]); + Value *Select = new CallInst(F, &Args[0], Args.size(), "eh_select", CurBB); + new StoreInst(Select, ExceptionSelectorValue, CurBB); +} + + +/// CreateExceptionValues - Create values used internally by exception handling. +/// +void TreeToLLVM::CreateExceptionValues() { + // Check to see if the exception values have been constructed. + if (ExceptionValue) return; + + ExceptionValue = CreateTemporary(PointerType::get(Type::Int8Ty)); + ExceptionValue->setName("eh_exception"); + + ExceptionSelectorValue = CreateTemporary(Type::Int32Ty); + ExceptionSelectorValue->setName("eh_selector"); + + FuncEHException = Intrinsic::getDeclaration(TheModule, + Intrinsic::eh_exception); + FuncEHSelector = Intrinsic::getDeclaration(TheModule, + Intrinsic::eh_selector); + FuncEHFilter = Intrinsic::getDeclaration(TheModule, + Intrinsic::eh_filter); + FuncEHGetTypeID = Intrinsic::getDeclaration(TheModule, + Intrinsic::eh_typeid_for); + + FuncCPPPersonality = cast<Function>( + TheModule->getOrInsertFunction("__gxx_personality_v0", + Type::getPrimitiveType(Type::VoidTyID), + NULL)); + FuncCPPPersonality->setLinkage(Function::ExternalLinkage); + FuncCPPPersonality->setCallingConv(CallingConv::C); + + FuncUnwindResume = cast<Function>( + TheModule->getOrInsertFunction("_Unwind_Resume", + Type::getPrimitiveType(Type::VoidTyID), + PointerType::get(Type::Int8Ty), + NULL)); + FuncUnwindResume->setLinkage(Function::ExternalLinkage); + FuncUnwindResume->setCallingConv(CallingConv::C); + +} + + /// EmitTRY_EXPR - Handle TRY_FINALLY_EXPR and TRY_CATCH_EXPR. Value *TreeToLLVM::EmitTRY_EXPR(tree exp) { // The C++ front-end produces a lot of TRY_FINALLY_EXPR nodes that have empty @@ -1847,32 +1994,40 @@ // Add a basic block to emit the code into. BasicBlock *CleanupBB = new BasicBlock("cleanup"); EmitBlock(CleanupBB); - + + // Provide exit point for cleanup code. + FinallyStack.push_back(FinallyBlock); + // Emit the code. Emit(CleanupCode, 0); + // Clear exit point for cleanup code. + FinallyStack.pop_back(); + // Because we can emit the same cleanup in more than one context, we must // strip off LLVM information from the decls in the code. Otherwise, the // we will try to insert the same label into multiple places in the code. StripLLVMTranslation(CleanupCode); + - // Because we can emit the same cleanup in more than one context, we must - // strip off LLVM information from the decls in the code. Otherwise, the - // we will try to insert the same label into multiple places in the code. - //StripLLVMTranslation(CleanupCode); + // Catches will supply own terminator. + if (!CurBB->getTerminator()) { + // Emit a branch to the new target. + BranchInst *BI = new BranchInst(FixupBr->getSuccessor(0), CurBB); - // Emit a branch to the new target. - BranchInst *BI = new BranchInst(FixupBr->getSuccessor(0), CurBB); + // The old branch now goes to the cleanup block. + FixupBr->setSuccessor(0, CleanupBB); - // The old branch now goes to the cleanup block. - FixupBr->setSuccessor(0, CleanupBB); - - // Fixup this new branch now. - FixupBr = BI; - - // Add the fixup to the next cleanup scope if there is one. - if (!CurrentEHScopes.empty()) - AddBranchFixup(FixupBr, FixupIsExceptionEdge); + // Fixup this new branch now. + FixupBr = BI; + + // Add the fixup to the next cleanup scope if there is one. + if (!CurrentEHScopes.empty()) + AddBranchFixup(FixupBr, FixupIsExceptionEdge); + } else { + // The old branch now goes to the cleanup block. + FixupBr->setSuccessor(0, CleanupBB); + } } // Move the finally block to the end of the function so we can continue @@ -1895,6 +2050,138 @@ } +/// EmitCATCH_EXPR - Handle CATCH_EXPR. +/// +Value *TreeToLLVM::EmitCATCH_EXPR(tree exp) { +#ifndef ITANIUM_STYLE_EXCEPTIONS + return 0; +#endif + + // Make sure we have all the exception values in place. + CreateExceptionValues(); + + // Break out parts of catch. + tree Types = CATCH_TYPES(exp); + tree Body = CATCH_BODY(exp); + + // Destinations of the catch entry conditions. + BasicBlock *ThenBlock = 0; + BasicBlock *ElseBlock = 0; + + // FiXME - Determine last case so we don't need to emit test. + if (!Types) { + // Catch all - no testing required. + } else if (TREE_CODE(Types) != TREE_LIST) { + // Construct typeinfo object. Each call will produce a new expression + // even if duplicate. + tree TypeInfoNopExpr = (*lang_eh_runtime_type)(Types); + // Produce value. Duplicate typeinfo get folded here. + Value *TypeInfo = Emit(TypeInfoNopExpr, 0); + + // Call get eh type id. + std::vector<Value*> Args; + Args.push_back(TypeInfo); + Value *TypeID = new CallInst(cast<Value>(FuncEHGetTypeID), + &Args[0], Args.size(), "eh_typeid", CurBB); + Value *Select = new LoadInst(ExceptionSelectorValue, "tmp", CurBB); + + // Compare with the exception selector. + Value *Compare = + new ICmpInst(ICmpInst::ICMP_EQ, Select, TypeID, "tmp", CurBB); + ThenBlock = new BasicBlock("eh_then"); + ElseBlock = new BasicBlock("eh_else"); + + // Branch on the compare. + new BranchInst(ThenBlock, ElseBlock, Compare, CurBB); + } else { + ThenBlock = new BasicBlock("eh_then"); + + for (; Types; Types = TREE_CHAIN (Types)) { + if (ElseBlock) EmitBlock(ElseBlock); + + // Construct typeinfo object. Each call will produce a new expression + // even if duplicate. + tree TypeInfoNopExpr = (*lang_eh_runtime_type)(TREE_VALUE(Types)); + // Produce value. Duplicate typeinfo get folded here. + Value *TypeInfo = Emit(TypeInfoNopExpr, 0); + + // Call get eh type id. + std::vector<Value*> Args; + Args.push_back(TypeInfo); + Value *TypeID = new CallInst(cast<Value>(FuncEHGetTypeID), + &Args[0], Args.size(), "eh_typeid", CurBB); + Value *Select = new LoadInst(ExceptionSelectorValue, "tmp", CurBB); + + // Compare with the exception selector. + Value *Compare = + new ICmpInst(ICmpInst::ICMP_EQ, Select, TypeID, "tmp", CurBB); + ElseBlock = new BasicBlock("eh_else"); + + // Branch on the compare. + new BranchInst(ThenBlock, ElseBlock, Compare, CurBB); + } + } + + // Start the then block. + if (ThenBlock) EmitBlock(ThenBlock); + + // Emit the body. + Emit(Body, 0); + + // Branch to the try exit. + assert(!FinallyStack.empty() && "Need an exit point"); + if (!CurBB->getTerminator()) + new BranchInst(FinallyStack.back(), CurBB); + + // Start the else block. + if (ElseBlock) EmitBlock(ElseBlock); + + return 0; +} + +/// EmitEXC_PTR_EXPR - Handle EXC_PTR_EXPR. +/// +Value *TreeToLLVM::EmitEXC_PTR_EXPR(tree exp) { +#ifndef ITANIUM_STYLE_EXCEPTIONS + return 0; +#endif + + // Load exception address. + CreateExceptionValues(); + return new LoadInst(ExceptionValue, "eh_value", CurBB); +} + +/// EmitEH_FILTER_EXPR - Handle EH_FILTER_EXPR. +/// +Value *TreeToLLVM::EmitEH_FILTER_EXPR(tree exp) { +#ifndef ITANIUM_STYLE_EXCEPTIONS + return 0; +#endif + + CreateExceptionValues(); + + // The result of a filter landing pad will be a negative index if there is + // a match. + Value *Select = new LoadInst(ExceptionSelectorValue, "tmp", CurBB); + + // Compare with the filter action value. + Value *Zero = ConstantInt::get(Type::Int32Ty, 0); + Value *Compare = + new ICmpInst(ICmpInst::ICMP_SLT, Select, Zero, "tmp", CurBB); + + // Branch on the compare. + BasicBlock *FilterBB = new BasicBlock("filter"); + BasicBlock *NoFilterBB = new BasicBlock("nofilter"); + new BranchInst(FilterBB, NoFilterBB, Compare, CurBB); + + EmitBlock(FilterBB); + Emit(EH_FILTER_FAILURE(exp), 0); + + EmitBlock(NoFilterBB); + + return 0; +} + //===----------------------------------------------------------------------===// // ... Expressions ... //===----------------------------------------------------------------------===// @@ -2170,13 +2457,6 @@ if (UnwindBB == 0) UnwindBB = new BasicBlock("Unwind"); UnwindBlock = UnwindBB; -FIXME: "Call terminate if needed!"; -#if 0 - if (ThrownExceptionsCallTerminate()) - UnwindBlock = getTerminateBlock(); - else - UnwindBlock = getInvokeDestination(); -#endif } SmallVector<Value*, 16> CallOperands; @@ -2264,10 +2544,16 @@ // branch in. if (CurrentEHScopes.back().UnwindBlock == 0) { EmitBlock(CurrentEHScopes.back().UnwindBlock = new BasicBlock("unwind")); - // This branch to the unwind edge should have exception cleanups inserted - // onto it. + +#ifdef ITANIUM_STYLE_EXCEPTIONS + // Add landing pad entry code. + AddLandingPad(); +#endif + // This branch to the unwind edge should have exception cleanups + // inserted onto it. EmitBranchInternal(UnwindBlock, true); } + cast<InvokeInst>(Call)->setUnwindDest(CurrentEHScopes.back().UnwindBlock); EmitBlock(NextBlock); Modified: apple-local/branches/llvm/gcc/llvm-internal.h =================================================================== --- apple-local/branches/llvm/gcc/llvm-internal.h 2007-03-01 10:54:52 UTC (rev 124437) +++ apple-local/branches/llvm/gcc/llvm-internal.h 2007-03-01 23:11:13 UTC (rev 124438) @@ -242,6 +242,42 @@ /// this map. std::map<BasicBlock*, unsigned> BlockEHScope; + /// ExceptionValue - Is the local to receive the current exception. + /// + Value *ExceptionValue; + + /// ExceptionSelectorValue - Is the local to receive the current exception + /// selector. + Value *ExceptionSelectorValue; + + /// FuncEHException - Function used to receive the exception. + /// + Function *FuncEHException; + + /// FuncEHSelector - Function used to receive the exception selector. + /// + Function *FuncEHSelector; + + /// FuncEHFilter - Function used to handle the exception filtering. + /// + Function *FuncEHFilter; + + /// FuncEHGetTypeID - Function used to return type id for give typeinfo. + /// + Function *FuncEHGetTypeID; + + /// FuncCPPPersonality - Function handling c++ personality. + /// + Function *FuncCPPPersonality; + + /// FuncUnwindResume - Function used to continue exception unwinding. + /// + Function *FuncUnwindResume; + + /// FinallyStack - Stack for nested try exit points. + /// + std::vector<BasicBlock *> FinallyStack; + /// NumAddressTakenBlocks - Count the number of labels whose addresses are /// taken. uint64_t NumAddressTakenBlocks; @@ -368,6 +404,18 @@ void HandleMultiplyDefinedGCCTemp(tree_node *var); private: + /// GatherTypeInfo - Walk through the expression gathering all the + /// typeinfos that are used. + void GatherTypeInfo(tree_node *exp, std::vector<Value *> &TypeInfos); + + /// AddLandingPad - Insert code to fetch and save the exception and exception + /// selector. + void AddLandingPad(); + + /// CreateExceptionValues - Create values used internally by exception handling. + /// + void CreateExceptionValues(); + // Emit* - These are delgates from Emit, and have the same parameter // characteristics. @@ -382,6 +430,9 @@ Value *EmitCOND_EXPR(tree_node *exp); Value *EmitSWITCH_EXPR(tree_node *exp); Value *EmitTRY_EXPR(tree_node *exp); + Value *EmitCATCH_EXPR(tree_node *exp); + Value *EmitEXC_PTR_EXPR(tree_node *exp); + Value *EmitEH_FILTER_EXPR(tree_node *exp); // Expressions. void EmitINTEGER_CST_Aggregate(tree_node *exp, Value *DestLoc); _______________________________________________ llvm-commits mailing list llvm-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits