Revision: 129185 Author: clattner Date: 2007-07-04 13:50:11 -0700 (Wed, 04 Jul 2007)
Log Message: ----------- Handle nested try-catch statements: From Duncan These patches, to LLVM and llvm-gcc, add support for nested try-catch statements. Previously, only the inner most catch or filter was being taken into account. Thanks to inlining it is possible for a function to contain any number of filters and catches nested within each other (without inlining filters only occur outermost). To support this I've junked the eh.filter intrinsic and extended the eh.selector intrinsic so it can simultaneously contain catches and filters. To indicate a filter, the number of typeinfos in the filter is given as an argument, followed by the typeinfos themselves. For example, %s = eh.selector(exception,personality,t1,2,t2,t3,t4); has a catch (typeinfo t1) followed by a filter of length 2 (typeinfos t2 and t3) followed by another catch (typeinfo t4). This is not very beautiful but it is simple, effective and unambiguous. An alternative would have been to keep eh.filter and output multiple filter/selector intrinsics like this: %s1 = eh.selector(exception,personality,t4); %s2 = eh.filter(exception,personality,t2,t3); %s3 = eh.selector(exception,personality,t1); (yes, in reverse order). Then %s1 and %s2 would never be used, and %s3 would be tested against the various typeinfos, even if they were never mentioned in the %s3 selector itself (eg t4). It also requires extra mucking around with the live-in markings for the exception and selector registers produced during codegen. I decided it was better to enhance eh.selector and get rid of eh.filter. Note that this means that eh.selector now corresponds directly to the action sequence in the dwarf eh table. The testcase shows the difference before and after (I've simplified the output a bit): Before: %eh_select = call @llvm.eh.filter(%eh_ptr, @__gxx_personality_v0, null) ; "empty" filter [the "null" should not be here - also fixed in this patch] After: %eh_select = call @llvm.eh.selector(%eh_ptr, @__gxx_personality_v0, i32 0, ; empty filter @_ZTI3One, ; catch i32 1, @_ZTI3Two, ; filter of length 1 @_ZTI5Three, @_ZTI4Four, ; two catches i32 2, @_ZTI4Five, @_ZTI3Six, ; filter of length 2 null) ; catch-all 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-07-04 11:25:32 UTC (rev 129184) +++ apple-local/branches/llvm/gcc/llvm-convert.cpp 2007-07-04 20:50:11 UTC (rev 129185) @@ -350,7 +350,6 @@ ExceptionSelectorValue = 0; FuncEHException = 0; FuncEHSelector = 0; - FuncEHFilter = 0; FuncEHGetTypeID = 0; FuncCPPPersonality = 0; FuncUnwindResume = 0; @@ -1965,16 +1964,18 @@ /// GatherTypeInfo - Walk through the expression gathering all the /// typeinfos that are used. void TreeToLLVM::GatherTypeInfo(tree exp, - std::vector<Value *> &TypeInfos) { + std::vector<Constant *> &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(PointerType::get(Type::Int8Ty)) - ); + // Catch all or empty filter. + if (TREE_CODE(exp) == CATCH_EXPR) + // Catch all. + TypeInfos.push_back( + Constant::getNullValue(PointerType::get(Type::Int8Ty)) + ); } else if (TREE_CODE(Types) != TREE_LIST) { // Construct typeinfo object. Each call will produce a new expression // even if duplicate. @@ -1982,7 +1983,7 @@ // Produce value. Duplicate typeinfo get folded here. Value *TypeInfo = Emit(TypeInfoNopExpr, 0); // Capture typeinfo. - TypeInfos.push_back(TypeInfo); + TypeInfos.push_back(cast<Constant>(TypeInfo)); } else { for (; Types; Types = TREE_CHAIN (Types)) { // Construct typeinfo object. Each call will produce a new expression @@ -1991,7 +1992,7 @@ // Produce value. Duplicate typeinfo get folded here. Value *TypeInfo = Emit(TypeInfoNopExpr, 0); // Capture typeinfo. - TypeInfos.push_back(TypeInfo); + TypeInfos.push_back(cast<Constant>(TypeInfo)); } } } else if (TREE_CODE(exp) == STATEMENT_LIST) { @@ -2007,47 +2008,53 @@ /// 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; - } - } - CreateExceptionValues(); // Fetch and store the exception. Value *Ex = Builder.CreateCall(FuncEHException, "eh_ptr"); Builder.CreateStore(Ex, ExceptionValue); - if (!TryCatch) return; - - // Gather the typeinfo. - std::vector<Value *> TypeInfos; - tree Catches = TREE_OPERAND(TryCatch, 1); - GatherTypeInfo(Catches, TypeInfos); - - // 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 selector. + std::vector<Value*> Args; + + for (std::vector<EHScope>::reverse_iterator I = CurrentEHScopes.rbegin(), + E = CurrentEHScopes.rend(); I != E; ++I) { + if (TREE_CODE(I->TryExpr) == TRY_CATCH_EXPR) { + if (I->InfosType == Unknown) { + // Gather the type info and determine the catch type. + tree Catches = TREE_OPERAND(I->TryExpr, 1); + GatherTypeInfo(Catches, I->TypeInfos); + I->InfosType = (TREE_CODE(Catches) == STATEMENT_LIST && + !tsi_end_p(tsi_start(Catches)) && + TREE_CODE(tsi_stmt(tsi_start(Catches))) == + EH_FILTER_EXPR) ? FilterExpr : CatchList; + } + + if (I->InfosType == CatchList && !I->TypeInfos.size()) + continue; + + // Lazily add the exception and the personality function. + if (!Args.size()) { + Args.push_back(Builder.CreateLoad(ExceptionValue, "eh_ptr")); + Args.push_back(CastToType(Instruction::BitCast, FuncCPPPersonality, + PointerType::get(Type::Int8Ty))); + } + + if (I->InfosType == FilterExpr) + // Filter - note the size. + Args.push_back(ConstantInt::get(Type::Int32Ty, I->TypeInfos.size())); + + Args.reserve(Args.size() + I->TypeInfos.size()); + for (unsigned j = 0, N = I->TypeInfos.size(); j < N; ++j) + Args.push_back(I->TypeInfos[j]); + } } - - // Fetch and store exception handler. - std::vector<Value*> Args; - Args.push_back(Builder.CreateLoad(ExceptionValue, "eh_ptr")); - 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 = Builder.CreateCall(F, &Args[0], Args.size(), "eh_select"); - Builder.CreateStore(Select, ExceptionSelectorValue); + + if (Args.size()) { + Value *Select = Builder.CreateCall(FuncEHSelector, &Args[0], Args.size(), + "eh_select"); + Builder.CreateStore(Select, ExceptionSelectorValue); + } } @@ -2067,8 +2074,6 @@ 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); Modified: apple-local/branches/llvm/gcc/llvm-internal.h =================================================================== --- apple-local/branches/llvm/gcc/llvm-internal.h 2007-07-04 11:25:32 UTC (rev 129184) +++ apple-local/branches/llvm/gcc/llvm-internal.h 2007-07-04 20:50:11 UTC (rev 129185) @@ -258,25 +258,38 @@ BranchFixup(BranchInst *srcBranch, bool IsExceptionEdge) : SrcBranch(srcBranch), isExceptionEdge(IsExceptionEdge) {} }; - + + enum CatchTypes { Unknown = 0, CatchList, FilterExpr }; + /// EHScope - One of these scopes is maintained for each TRY_CATCH_EXPR and /// TRY_FINALLY_EXPR blocks that we are currently in. struct EHScope { /// TryExpr - This is the actual TRY_CATCH_EXPR or TRY_FINALLY_EXPR. tree_node *TryExpr; - + /// UnwindBlock - A basic block in this scope that branches to the unwind /// destination. This is lazily created by the first invoke in this scope. BasicBlock *UnwindBlock; - + // The basic blocks that are directly in this region. std::vector<BasicBlock*> Blocks; - + /// BranchFixups - This is a list of fixups we need to process in this scope /// or in a parent scope. std::vector<BranchFixup> BranchFixups; - - EHScope(tree_node *expr) : TryExpr(expr), UnwindBlock(0) {} + + /// InfosType - The nature of the type infos TryExpr contains: a list of + /// CATCH_EXPR (-> CatchList) or an EH_FILTER_EXPR (-> FilterExpr). Equal + /// to Unknown if type info information has not yet been gathered. + CatchTypes InfosType; + + /// TypeInfos - The type infos corresponding to the catches or filter in + /// TryExpr. If InfosType is Unknown then this information has not yet + /// been gathered. + std::vector<Constant *> TypeInfos; + + EHScope(tree_node *expr) : + TryExpr(expr), UnwindBlock(0), InfosType(Unknown) {} }; /// CurrentEHScopes - The current stack of exception scopes we are @@ -305,10 +318,6 @@ /// Function *FuncEHSelector; - /// FuncEHFilter - Function used to handle the exception filtering. - /// - Function *FuncEHFilter; - /// FuncEHGetTypeID - Function used to return type id for give typeinfo. /// Function *FuncEHGetTypeID; @@ -457,7 +466,7 @@ private: /// GatherTypeInfo - Walk through the expression gathering all the /// typeinfos that are used. - void GatherTypeInfo(tree_node *exp, std::vector<Value *> &TypeInfos); + void GatherTypeInfo(tree_node *exp, std::vector<Constant *> &TypeInfos); /// AddLandingPad - Insert code to fetch and save the exception and exception /// selector. _______________________________________________ llvm-commits mailing list llvm-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits