Author: baldrick Date: Mon Dec 31 08:05:52 2007 New Revision: 45471 URL: http://llvm.org/viewvc/llvm-project?rev=45471&view=rev Log: Due to gcc inlining, it is possible for resx expressions (i.e. rethrows) to occur inside must-not-throw regions. This is illegal, and can be handled by either executing the code specified by lang_protect_cleanup_actions (since this code should already have been emitted into some basic block, this means locating that basic block and jumping to it), or by marking the call with the nounwind attribute. Because using the nounwind attribute seems to be both simpler and more robust, that is the solution implemented here. This fixes the last known eh problem on x86 linux with llvm-gcc-4.2.
Modified: llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp llvm-gcc-4.2/trunk/gcc/llvm-internal.h Modified: llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp?rev=45471&r1=45470&r2=45471&view=diff ============================================================================== --- llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp (original) +++ llvm-gcc-4.2/trunk/gcc/llvm-convert.cpp Mon Dec 31 08:05:52 2007 @@ -349,7 +349,7 @@ TreeToLLVM::TreeToLLVM(tree fndecl) : TD(getTargetData()) { FnDecl = fndecl; Fn = 0; - ReturnBB = UnwindBB = 0; + ReturnBB = UnwindBB = NoUnwindBB = 0; if (TheDebugInfo) { expanded_location Location = expand_location(DECL_SOURCE_LOCATION (fndecl)); @@ -755,6 +755,7 @@ EmitLandingPads(); EmitPostPads(); EmitUnwindBlock(); + EmitNoUnwindBlock(); // If this function takes the address of a label, emit the indirect goto // block. @@ -1863,7 +1864,7 @@ PointerType::getUnqual(Type::Int8Ty))); // Add selections for each handler. - foreach_reachable_handler (i, false, AddHandler, &Handlers); + foreach_reachable_handler(i, false, AddHandler, &Handlers); for (std::vector<struct eh_region *>::iterator I = Handlers.begin(), E = Handlers.end(); I != E; ++I) { @@ -2023,7 +2024,7 @@ } // Emit a RESX_EXPR which skips handlers with no post landing pad. - foreach_reachable_handler (i, true, AddHandler, &Handlers); + foreach_reachable_handler(i, true, AddHandler, &Handlers); BasicBlock *TargetBB = NULL; @@ -2038,13 +2039,20 @@ break; } - if (!TargetBB) { + if (TargetBB) { + Builder.CreateBr(TargetBB); + } else if (can_throw_external_1(i, true)) { + // Unwinding continues in the caller. if (!UnwindBB) UnwindBB = new BasicBlock("Unwind"); - TargetBB = UnwindBB; + Builder.CreateBr(UnwindBB); + } else { + // Unwinding in a must_not_throw region - notify the runtime. + if (!NoUnwindBB) + NoUnwindBB = new BasicBlock("NoUnwind"); + Builder.CreateBr(NoUnwindBB); } - Builder.CreateBr(TargetBB); Handlers.clear(); } } @@ -2062,6 +2070,22 @@ } } +/// EmitNoUnwindBlock - Emit the lazily created EH illegal-unwind block. +void TreeToLLVM::EmitNoUnwindBlock() { + if (NoUnwindBB) { + CreateExceptionValues(); + EmitBlock(NoUnwindBB); + // Fetch and store exception handler. + Value *Arg = Builder.CreateLoad(ExceptionValue, "eh_ptr"); + assert(llvm_unwind_resume_libfunc && "no unwind resume function!"); + CallInst *Call = + Builder.CreateCall(DECL_LLVM(llvm_unwind_resume_libfunc), Arg); + // Illegal unwind - notify the runtime. + Call->setDoesNotThrow(); + Builder.CreateUnreachable(); + } +} + //===----------------------------------------------------------------------===// // ... Expressions ... //===----------------------------------------------------------------------===// @@ -3267,7 +3291,7 @@ unsigned RegionNo = TREE_INT_CST_LOW(TREE_OPERAND (exp, 0)); std::vector<struct eh_region *> Handlers; - foreach_reachable_handler (RegionNo, true, AddHandler, &Handlers); + foreach_reachable_handler(RegionNo, true, AddHandler, &Handlers); if (!Handlers.empty()) { for (std::vector<struct eh_region *>::iterator I = Handlers.begin(), @@ -3276,10 +3300,16 @@ getPostPad(get_eh_region_number(*I)); Builder.CreateBr(getPostPad(get_eh_region_number(*Handlers.begin()))); - } else { + } else if (can_throw_external_1(RegionNo, true)) { + // Unwinding continues in the caller. if (!UnwindBB) UnwindBB = new BasicBlock("Unwind"); Builder.CreateBr(UnwindBB); + } else { + // Unwinding in a must_not_throw region - notify the runtime. + if (!NoUnwindBB) + NoUnwindBB = new BasicBlock("NoUnwind"); + Builder.CreateBr(NoUnwindBB); } EmitBlock(new BasicBlock("")); Modified: llvm-gcc-4.2/trunk/gcc/llvm-internal.h URL: http://llvm.org/viewvc/llvm-project/llvm-gcc-4.2/trunk/gcc/llvm-internal.h?rev=45471&r1=45470&r2=45471&view=diff ============================================================================== --- llvm-gcc-4.2/trunk/gcc/llvm-internal.h (original) +++ llvm-gcc-4.2/trunk/gcc/llvm-internal.h Mon Dec 31 08:05:52 2007 @@ -267,7 +267,8 @@ Function *Fn; BasicBlock *ReturnBB; BasicBlock *UnwindBB; - + BasicBlock *NoUnwindBB; + // State that changes as the function is emitted. /// Builder - Instruction creator, the location to insert into is always the @@ -421,6 +422,9 @@ /// EmitUnwindBlock - Emit the lazily created EH unwind block. void EmitUnwindBlock(); + /// EmitNoUnwindBlock - Emit the lazily created EH illegal-unwind block. + void EmitNoUnwindBlock(); + private: // Helpers for exception handling. /// CreateExceptionValues - Create values used internally by exception _______________________________________________ llvm-commits mailing list llvm-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits