From d7c10862016939c9850cadfe5e1c35513c0adf28 Mon Sep 17 00:00:00 2001 From: John McCall Date: Sat, 28 May 2011 07:45:59 +0000 Subject: [PATCH] Implement and document the llvm.eh.resume intrinsic, which is transformed by the inliner into a branch to the enclosing landing pad (when inlined through an invoke). If not so optimized, it is lowered DWARF EH preparation into a call to _Unwind_Resume (or _Unwind_SjLj_Resume as appropriate). Its chief advantage is that it takes both the exception value and the selector value as arguments, meaning that there is zero effort in recovering these; however, the frontend is required to pass these down, which is not actually particularly difficult. Also document the behavior of landing pads a bit better, and make it clearer that it's okay that personality functions don't always land at landing pads. This is just a fact of life. Don't write optimizations that rely on pushing things over an unwind edge. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@132253 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/ExceptionHandling.html | 136 +++++++++---- lib/CodeGen/DwarfEHPrepare.cpp | 67 ++++--- lib/Transforms/Utils/InlineFunction.cpp | 243 ++++++++++++++++++------ test/Transforms/Inline/inline_invoke.ll | 31 +-- 4 files changed, 338 insertions(+), 139 deletions(-) diff --git a/docs/ExceptionHandling.html b/docs/ExceptionHandling.html index 0d3ea1b6240..247448d2554 100644 --- a/docs/ExceptionHandling.html +++ b/docs/ExceptionHandling.html @@ -35,6 +35,7 @@
  1. llvm.eh.exception
  2. llvm.eh.selector
  3. +
  4. llvm.eh.resume
  5. llvm.eh.typeid.for
  6. llvm.eh.sjlj.setjmp
  7. llvm.eh.sjlj.longjmp
  8. @@ -317,15 +318,28 @@
    -

    To handle destructors and cleanups in try code, control may not run - directly from a landing pad to the first catch. Control may actually flow - from the landing pad to clean up code and then to the first catch. Since the - required clean up for each invoke in a try may be different - (e.g. intervening constructor), there may be several landing pads for a given - try. If cleanups need to be run, an i32 0 should be passed as the - last llvm.eh.selector argument. - However, when using DWARF exception handling with C++, a i8* null - must be passed instead.

    +

    A cleanup is extra code which needs to be run as part of unwinding + a scope. C++ destructors are a prominent example, but other + languages and language extensions provide a variety of different + kinds of cleanup. In general, a landing pad may need to run + arbitrary amounts of cleanup code before actually entering a catch + block. To indicate the presence of cleanups, a landing pad's call + to llvm.eh.selector should + end with the argument i32 0; otherwise, the unwinder will + not stop at the landing pad if there are no catches or filters that + require it to.

    + +

    Do not allow a new exception to propagate out of the execution of a + cleanup. This can corrupt the internal state of the unwinder. + Different languages describe different high-level semantics for + these situations: for example, C++ requires that the process be + terminated, whereas Ada cancels both exceptions and throws a third.

    + +

    When all cleanups have completed, if the exception is not handled + by the current function, resume unwinding by calling the + llvm.eh.resume intrinsic, + passing in the results of llvm.eh.exception and + llvm.eh.selector for the original landing pad.

    @@ -363,22 +377,29 @@
    -

    The semantics of the invoke instruction require that any exception that - unwinds through an invoke call should result in a branch to the invoke's - unwind label. However such a branch will only happen if the - llvm.eh.selector matches. Thus in - order to ensure correct operation, the front-end must only generate - llvm.eh.selector calls that are - guaranteed to always match whatever exception unwinds through the invoke. - For most languages it is enough to pass zero, indicating the presence of - a cleanup, as the - last llvm.eh.selector argument. - However for C++ this is not sufficient, because the C++ personality function - will terminate the program if it detects that unwinding the exception only - results in matches with cleanups. For C++ a null i8* should be - passed as the last llvm.eh.selector - argument instead. This is interpreted as a catch-all by the C++ personality - function, and will always match.

    +

    The unwinder delegates the decision of whether to stop in a call + frame to that call frame's language-specific personality function. + Not all personalities functions guarantee that they will stop to + perform cleanups: for example, the GNU C++ personality doesn't do + so unless the exception is actually caught somewhere further up the + stack. When using this personality to implement EH for a language + that guarantees that cleanups will always be run, be sure to + indicate a catch-all in the + llvm.eh.selector call + rather than just cleanups.

    + +

    In order for inlining to behave correctly, landing pads must be + prepared to handle selector results that they did not originally + advertise. Suppose that a function catches exceptions of + type A, and it's inlined into a function that catches + exceptions of type B. The inliner will update the + selector for the inlined landing pad to include the fact + that B is caught. If that landing pad assumes that it + will only be entered to catch an A, it's in for a rude + surprise. Consequently, landing pads must test for the selector + results they understand and then resume exception propagation + with the llvm.eh.resume + intrinsic if none of the conditions match.

    @@ -424,22 +445,32 @@

    This intrinsic is used to compare the exception with the given type infos, filters and cleanups.

    -

    llvm.eh.selector takes a minimum of - three arguments. The first argument is the reference to the exception - structure. The second argument is a reference to the personality function to - be used for this try catch sequence. Each of the remaining arguments is - either a reference to the type info for a catch statement, - a filter expression, or the number zero - representing a cleanup. The exception is tested - against the arguments sequentially from first to last. The result of - the llvm.eh.selector is a positive - number if the exception matched a type info, a negative number if it matched - a filter, and zero if it matched a cleanup. If nothing is matched, the - behaviour of the program is undefined. If a type - info matched then the selector value is the index of the type info in the - exception table, which can be obtained using the +

    llvm.eh.selector takes a + minimum of three arguments. The first argument is the reference to + the exception structure. The second argument is a reference to the + personality function to be used for this try catch sequence. Each + of the remaining arguments is either a reference to the type info + for a catch statement, a filter + expression, or the number zero representing + a cleanup. The exception is tested against + the arguments sequentially from first to last. The result of + the llvm.eh.selector is a + positive number if the exception matched a type info, a negative + number if it matched a filter, and zero if it matched a cleanup. + If nothing is matched, or if only a cleanup is matched, different + personality functions may or may not cause control to stop at the + landing pad; see the restrictions for + more information. If a type info matched then the selector value + is the index of the type info in the exception table, which can be + obtained using the llvm.eh.typeid.for intrinsic.

    +

    If a landing pad containing a call to llvm.eh.selector is + inlined into an invoke instruction, the selector arguments + for the outer landing pad are appended to those of the inlined + landing pad. Consequently, landing pads must be written to ignore + selector values that they did not originally advertise.

    + @@ -460,6 +491,33 @@ + +

    + llvm.eh.resume +

    + +
    + +
    +  void %llvm.eh.resume(i8*, i32) noreturn
    +
    + +

    This intrinsic is used to resume propagation of an exception after + landing at a landing pad. The first argument should be the result + of llvm.eh.exception for that + landing pad, and the second argument should be the result of + llvm.eh.selector. When a call to + this intrinsic is inlined into an invoke, the call is transformed + into a branch to the invoke's unwind destination, using its + arguments in place of the calls + to llvm.eh.exception and + llvm.eh.selector there.

    + +

    This intrinsic is not implicitly nounwind; calls to it + will always throw. It may not be invoked.

    + +
    +

    llvm.eh.sjlj.setjmp diff --git a/lib/CodeGen/DwarfEHPrepare.cpp b/lib/CodeGen/DwarfEHPrepare.cpp index 34b1a396bb7..6a53e693370 100644 --- a/lib/CodeGen/DwarfEHPrepare.cpp +++ b/lib/CodeGen/DwarfEHPrepare.cpp @@ -30,6 +30,7 @@ using namespace llvm; STATISTIC(NumLandingPadsSplit, "Number of landing pads split"); STATISTIC(NumUnwindsLowered, "Number of unwind instructions lowered"); +STATISTIC(NumResumesLowered, "Number of eh.resume calls lowered"); STATISTIC(NumExceptionValuesMoved, "Number of eh.exception calls moved"); namespace { @@ -63,7 +64,7 @@ namespace { BBSet LandingPads; bool NormalizeLandingPads(); - bool LowerUnwinds(); + bool LowerUnwindsAndResumes(); bool MoveExceptionValueCalls(); Instruction *CreateExceptionValueCall(BasicBlock *BB); @@ -480,20 +481,25 @@ bool DwarfEHPrepare::NormalizeLandingPads() { /// rethrowing any previously caught exception. This will crash horribly /// at runtime if there is no such exception: using unwind to throw a new /// exception is currently not supported. -bool DwarfEHPrepare::LowerUnwinds() { - SmallVector UnwindInsts; - - for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) { - TerminatorInst *TI = I->getTerminator(); - if (isa(TI)) - UnwindInsts.push_back(TI); +bool DwarfEHPrepare::LowerUnwindsAndResumes() { + SmallVector ResumeInsts; + + for (Function::iterator fi = F->begin(), fe = F->end(); fi != fe; ++fi) { + for (BasicBlock::iterator bi = fi->begin(), be = fi->end(); bi != be; ++bi){ + if (isa(bi)) + ResumeInsts.push_back(bi); + else if (CallInst *call = dyn_cast(bi)) + if (Function *fn = dyn_cast(call->getCalledValue())) + if (fn->getName() == "llvm.eh.resume") + ResumeInsts.push_back(bi); + } } - if (UnwindInsts.empty()) return false; + if (ResumeInsts.empty()) return false; // Find the rewind function if we didn't already. if (!RewindFunction) { - LLVMContext &Ctx = UnwindInsts[0]->getContext(); + LLVMContext &Ctx = ResumeInsts[0]->getContext(); std::vector Params(1, Type::getInt8PtrTy(Ctx)); FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx), @@ -504,24 +510,35 @@ bool DwarfEHPrepare::LowerUnwinds() { bool Changed = false; - for (SmallVectorImpl::iterator - I = UnwindInsts.begin(), E = UnwindInsts.end(); I != E; ++I) { - TerminatorInst *TI = *I; + for (SmallVectorImpl::iterator + I = ResumeInsts.begin(), E = ResumeInsts.end(); I != E; ++I) { + Instruction *RI = *I; - // Replace the unwind instruction with a call to _Unwind_Resume (or the - // appropriate target equivalent) followed by an UnreachableInst. + // Replace the resuming instruction with a call to _Unwind_Resume (or the + // appropriate target equivalent). + + llvm::Value *ExnValue; + if (isa(RI)) + ExnValue = CreateExceptionValueCall(RI->getParent()); + else + ExnValue = cast(RI)->getArgOperand(0); // Create the call... - CallInst *CI = CallInst::Create(RewindFunction, - CreateExceptionValueCall(TI->getParent()), - "", TI); + CallInst *CI = CallInst::Create(RewindFunction, ExnValue, "", RI); CI->setCallingConv(TLI->getLibcallCallingConv(RTLIB::UNWIND_RESUME)); - // ...followed by an UnreachableInst. - new UnreachableInst(TI->getContext(), TI); - // Nuke the unwind instruction. - TI->eraseFromParent(); - ++NumUnwindsLowered; + // ...followed by an UnreachableInst, if it was an unwind. + // Calls to llvm.eh.resume are typically already followed by this. + if (isa(RI)) + new UnreachableInst(RI->getContext(), RI); + + // Nuke the resume instruction. + RI->eraseFromParent(); + + if (isa(RI)) + ++NumUnwindsLowered; + else + ++NumResumesLowered; Changed = true; } @@ -657,8 +674,8 @@ bool DwarfEHPrepare::runOnFunction(Function &Fn) { // basic block where an invoke unwind edge ends). Changed |= NormalizeLandingPads(); - // Turn unwind instructions into libcalls. - Changed |= LowerUnwinds(); + // Turn unwind instructions and eh.resume calls into libcalls. + Changed |= LowerUnwindsAndResumes(); // TODO: Move eh.selector calls to landing pads and combine them. diff --git a/lib/Transforms/Utils/InlineFunction.cpp b/lib/Transforms/Utils/InlineFunction.cpp index 69793ab8361..2f3c045ea5a 100644 --- a/lib/Transforms/Utils/InlineFunction.cpp +++ b/lib/Transforms/Utils/InlineFunction.cpp @@ -45,66 +45,192 @@ bool llvm::InlineFunction(InvokeInst *II, InlineFunctionInfo &IFI) { return InlineFunction(CallSite(II), IFI); } +/// [LIBUNWIND] Find the (possibly absent) call to @llvm.eh.selector in +/// the given landing pad. +static EHSelectorInst *findSelectorForLandingPad(BasicBlock *lpad) { + // The llvm.eh.exception call is required to be in the landing pad. + for (BasicBlock::iterator i = lpad->begin(), e = lpad->end(); i != e; i++) { + EHExceptionInst *exn = dyn_cast(i); + if (!exn) continue; + + EHSelectorInst *selector = 0; + for (Instruction::use_iterator + ui = exn->use_begin(), ue = exn->use_end(); ui != ue; ++ui) { + EHSelectorInst *sel = dyn_cast(*ui); + if (!sel) continue; + + // Immediately accept an eh.selector in the landing pad. + if (sel->getParent() == lpad) return sel; + + // Otherwise, use the first selector we see. + if (!selector) selector = sel; + } + + return selector; + } + + return 0; +} + namespace { /// A class for recording information about inlining through an invoke. class InvokeInliningInfo { - BasicBlock *UnwindDest; + BasicBlock *OuterUnwindDest; + EHSelectorInst *OuterSelector; + BasicBlock *InnerUnwindDest; + PHINode *InnerExceptionPHI; + PHINode *InnerSelectorPHI; SmallVector UnwindDestPHIValues; public: - InvokeInliningInfo(InvokeInst *II) : UnwindDest(II->getUnwindDest()) { + InvokeInliningInfo(InvokeInst *II) : + OuterUnwindDest(II->getUnwindDest()), OuterSelector(0), + InnerUnwindDest(0), InnerExceptionPHI(0), InnerSelectorPHI(0) { + // If there are PHI nodes in the unwind destination block, we // need to keep track of which values came into them from the // invoke before removing the edge from this block. - llvm::BasicBlock *InvokeBlock = II->getParent(); - for (BasicBlock::iterator I = UnwindDest->begin(); isa(I); ++I) { - PHINode *PN = cast(I); + llvm::BasicBlock *invokeBB = II->getParent(); + for (BasicBlock::iterator I = OuterUnwindDest->begin(); + isa(I); ++I) { // Save the value to use for this edge. - llvm::Value *Incoming = PN->getIncomingValueForBlock(InvokeBlock); - UnwindDestPHIValues.push_back(Incoming); + PHINode *phi = cast(I); + UnwindDestPHIValues.push_back(phi->getIncomingValueForBlock(invokeBB)); } } - BasicBlock *getUnwindDest() const { - return UnwindDest; + /// The outer unwind destination is the target of unwind edges + /// introduced for calls within the inlined function. + BasicBlock *getOuterUnwindDest() const { + return OuterUnwindDest; } + EHSelectorInst *getOuterSelector() { + if (!OuterSelector) + OuterSelector = findSelectorForLandingPad(OuterUnwindDest); + return OuterSelector; + } + + BasicBlock *getInnerUnwindDest(); + + bool forwardEHResume(CallInst *call, BasicBlock *src); + /// Add incoming-PHI values to the unwind destination block for /// the given basic block, using the values for the original /// invoke's source block. void addIncomingPHIValuesFor(BasicBlock *BB) const { - BasicBlock::iterator I = UnwindDest->begin(); + addIncomingPHIValuesForInto(BB, OuterUnwindDest); + } + + void addIncomingPHIValuesForInto(BasicBlock *src, BasicBlock *dest) const { + BasicBlock::iterator I = dest->begin(); for (unsigned i = 0, e = UnwindDestPHIValues.size(); i != e; ++i, ++I) { - PHINode *PN = cast(I); - PN->addIncoming(UnwindDestPHIValues[i], BB); + PHINode *phi = cast(I); + phi->addIncoming(UnwindDestPHIValues[i], src); } } }; } -/// [LIBUNWIND] Check whether the given value is the _Unwind_Resume -/// function specified by the Itanium EH ABI. -static bool isUnwindResume(Value *value) { - Function *fn = dyn_cast(value); - if (!fn) return false; - - // declare void @_Unwind_Resume(i8*) - if (fn->getName() != "_Unwind_Resume") return false; - const FunctionType *fnType = fn->getFunctionType(); - if (!fnType->getReturnType()->isVoidTy()) return false; - if (fnType->isVarArg()) return false; - if (fnType->getNumParams() != 1) return false; - const PointerType *paramType = dyn_cast(fnType->getParamType(0)); - return (paramType && paramType->getElementType()->isIntegerTy(8)); +/// Replace all the instruction uses of a value with a different value. +/// This has the advantage of not screwing up the CallGraph. +static void replaceAllInsnUsesWith(Instruction *insn, Value *replacement) { + for (Value::use_iterator i = insn->use_begin(), e = insn->use_end(); + i != e; ) { + Use &use = i.getUse(); + ++i; + if (isa(use.getUser())) + use.set(replacement); + } } -/// [LIBUNWIND] Find the (possibly absent) call to @llvm.eh.selector in -/// the given landing pad. -static EHSelectorInst *findSelectorForLandingPad(BasicBlock *lpad) { - for (BasicBlock::iterator i = lpad->begin(), e = lpad->end(); i != e; i++) - if (EHSelectorInst *selector = dyn_cast(i)) - return selector; - return 0; +/// Get or create a target for the branch out of rewritten calls to +/// llvm.eh.resume. +BasicBlock *InvokeInliningInfo::getInnerUnwindDest() { + if (InnerUnwindDest) return InnerUnwindDest; + + // Find and hoist the llvm.eh.exception and llvm.eh.selector calls + // in the outer landing pad to immediately following the phis. + EHSelectorInst *selector = getOuterSelector(); + if (!selector) return 0; + + // The call to llvm.eh.exception *must* be in the landing pad. + Instruction *exn = cast(selector->getArgOperand(0)); + assert(exn->getParent() == OuterUnwindDest); + + // TODO: recognize when we've already done this, so that we don't + // get a linear number of these when inlining calls into lots of + // invokes with the same landing pad. + + // Do the hoisting. + Instruction *splitPoint = exn->getParent()->getFirstNonPHI(); + assert(splitPoint != selector && "selector-on-exception dominance broken!"); + if (splitPoint == exn) { + selector->removeFromParent(); + selector->insertAfter(exn); + splitPoint = selector->getNextNode(); + } else { + exn->moveBefore(splitPoint); + selector->moveBefore(splitPoint); + } + + // Split the landing pad. + InnerUnwindDest = OuterUnwindDest->splitBasicBlock(splitPoint, + OuterUnwindDest->getName() + ".body"); + + // The number of incoming edges we expect to the inner landing pad. + const unsigned phiCapacity = 2; + + // Create corresponding new phis for all the phis in the outer landing pad. + BasicBlock::iterator insertPoint = InnerUnwindDest->begin(); + BasicBlock::iterator I = OuterUnwindDest->begin(); + for (unsigned i = 0, e = UnwindDestPHIValues.size(); i != e; ++i, ++I) { + PHINode *outerPhi = cast(I); + PHINode *innerPhi = PHINode::Create(outerPhi->getType(), phiCapacity, + outerPhi->getName() + ".lpad-body", + insertPoint); + innerPhi->addIncoming(outerPhi, OuterUnwindDest); + } + + // Create a phi for the exception value... + InnerExceptionPHI = PHINode::Create(exn->getType(), phiCapacity, + "exn.lpad-body", insertPoint); + replaceAllInsnUsesWith(exn, InnerExceptionPHI); + selector->setArgOperand(0, exn); // restore this use + InnerExceptionPHI->addIncoming(exn, OuterUnwindDest); + + // ...and the selector. + InnerSelectorPHI = PHINode::Create(selector->getType(), phiCapacity, + "selector.lpad-body", insertPoint); + replaceAllInsnUsesWith(selector, InnerSelectorPHI); + InnerSelectorPHI->addIncoming(selector, OuterUnwindDest); + + // All done. + return InnerUnwindDest; +} + +/// [LIBUNWIND] Try to forward the given call, which logically occurs +/// at the end of the given block, as a branch to the inner unwind +/// block. Returns true if the call was forwarded. +bool InvokeInliningInfo::forwardEHResume(CallInst *call, BasicBlock *src) { + Function *fn = dyn_cast(call->getCalledValue()); + if (!fn || fn->getName() != "llvm.eh.resume") + return false; + + // If this fails, maybe it should be a fatal error. + BasicBlock *dest = getInnerUnwindDest(); + if (!dest) return false; + + // Make a branch. + BranchInst::Create(dest, src); + + // Update the phis in the destination. They were inserted in an + // order which makes this work. + addIncomingPHIValuesForInto(src, dest); + InnerExceptionPHI->addIncoming(call->getArgOperand(0), src); + InnerSelectorPHI->addIncoming(call->getArgOperand(1), src); + + return true; } /// [LIBUNWIND] Check whether this selector is "only cleanups": @@ -134,7 +260,7 @@ static bool HandleCallsInBlockInlinedThroughInvoke(BasicBlock *BB, // LIBUNWIND: merge selector instructions. if (EHSelectorInst *Inner = dyn_cast(CI)) { - EHSelectorInst *Outer = findSelectorForLandingPad(Invoke.getUnwindDest()); + EHSelectorInst *Outer = Invoke.getOuterSelector(); if (!Outer) continue; bool innerIsOnlyCleanup = isCleanupOnlySelector(Inner); @@ -172,48 +298,41 @@ static bool HandleCallsInBlockInlinedThroughInvoke(BasicBlock *BB, // First, split the basic block. BasicBlock *Split = BB->splitBasicBlock(CI, CI->getName()+".noexc"); - bool skipNextBlock = false; + // Delete the unconditional branch inserted by splitBasicBlock + BB->getInstList().pop_back(); - // LIBUNWIND: If this is a call to @_Unwind_Resume, just branch + // LIBUNWIND: If this is a call to @llvm.eh.resume, just branch // directly to the new landing pad. - if (isUnwindResume(CI->getCalledValue())) { - BranchInst::Create(Invoke.getUnwindDest(), BB->getTerminator()); - + if (Invoke.forwardEHResume(CI, BB)) { // TODO: 'Split' is now unreachable; clean it up. // We want to leave the original call intact so that the call // graph and other structures won't get misled. We also have to // avoid processing the next block, or we'll iterate here forever. - skipNextBlock = true; + return true; + } // Otherwise, create the new invoke instruction. - } else { - ImmutableCallSite CS(CI); - SmallVector InvokeArgs(CS.arg_begin(), CS.arg_end()); - InvokeInst *II = - InvokeInst::Create(CI->getCalledValue(), Split, Invoke.getUnwindDest(), - InvokeArgs.begin(), InvokeArgs.end(), - CI->getName(), BB->getTerminator()); - II->setCallingConv(CI->getCallingConv()); - II->setAttributes(CI->getAttributes()); + ImmutableCallSite CS(CI); + SmallVector InvokeArgs(CS.arg_begin(), CS.arg_end()); + InvokeInst *II = + InvokeInst::Create(CI->getCalledValue(), Split, + Invoke.getOuterUnwindDest(), + InvokeArgs.begin(), InvokeArgs.end(), + CI->getName(), BB); + II->setCallingConv(CI->getCallingConv()); + II->setAttributes(CI->getAttributes()); - // Make sure that anything using the call now uses the invoke! This also - // updates the CallGraph if present, because it uses a WeakVH. - CI->replaceAllUsesWith(II); + // Make sure that anything using the call now uses the invoke! This also + // updates the CallGraph if present, because it uses a WeakVH. + CI->replaceAllUsesWith(II); + + Split->getInstList().pop_front(); // Delete the original call - Split->getInstList().pop_front(); // Delete the original call - } - - // Delete the unconditional branch inserted by splitBasicBlock - BB->getInstList().pop_back(); - // Update any PHI nodes in the exceptional block to indicate that // there is now a new entry in them. Invoke.addIncomingPHIValuesFor(BB); - - // This basic block is now complete, the caller will continue scanning the - // next one. - return skipNextBlock; + return false; } return false; diff --git a/test/Transforms/Inline/inline_invoke.ll b/test/Transforms/Inline/inline_invoke.ll index bd955e3bc95..93d4ef346c2 100644 --- a/test/Transforms/Inline/inline_invoke.ll +++ b/test/Transforms/Inline/inline_invoke.ll @@ -18,7 +18,7 @@ declare i32 @llvm.eh.selector(i8*, i8*, ...) nounwind declare i32 @llvm.eh.typeid.for(i8*) nounwind -declare void @_Unwind_Resume(i8*) +declare void @llvm.eh.resume(i8*, i32) declare i32 @__gxx_personality_v0(...) @@ -51,7 +51,7 @@ lpad: to label %invoke.cont2 unwind label %terminate.lpad invoke.cont2: - call void @_Unwind_Resume(i8* %exn) noreturn + call void @llvm.eh.resume(i8* %exn, i32 %eh.selector) noreturn unreachable terminate.lpad: @@ -82,22 +82,27 @@ catch: br label %ret eh.resume: - call void @_Unwind_Resume(i8* %exn) noreturn + call void @llvm.eh.resume(i8* %exn, i32 %eh.selector) noreturn unreachable } -; CHECK: define void @test0_out() -; CHECK: [[A:%.*]] = alloca %struct.A, -; CHECK: [[B:%.*]] = alloca %struct.A, -; CHECK: invoke void @_ZN1AC1Ev(%struct.A* [[A]]) -; CHECK: invoke void @_ZN1AC1Ev(%struct.A* [[B]]) -; CHECK: invoke void @_ZN1AD1Ev(%struct.A* [[B]]) -; CHECK: invoke void @_ZN1AD1Ev(%struct.A* [[A]]) -; CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{%.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i32 0, i8* bitcast (i8** @_ZTIi to i8*)) +; CHECK: define void @test0_out() +; CHECK: [[A:%.*]] = alloca %struct.A, +; CHECK: [[B:%.*]] = alloca %struct.A, +; CHECK: invoke void @_ZN1AC1Ev(%struct.A* [[A]]) +; CHECK: invoke void @_ZN1AC1Ev(%struct.A* [[B]]) +; CHECK: invoke void @_ZN1AD1Ev(%struct.A* [[B]]) +; CHECK: invoke void @_ZN1AD1Ev(%struct.A* [[A]]) +; CHECK: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{%.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i32 0, i8* bitcast (i8** @_ZTIi to i8*)) ; CHECK-NEXT: invoke void @_ZN1AD1Ev(%struct.A* [[A]]) ; CHECK-NEXT: to label %[[LBL:[^\s]+]] unwind ; CHECK: [[LBL]]: ; CHECK-NEXT: br label %[[LPAD:[^\s]+]] -; CHECK: [[LPAD]]: -; CHECK-NEXT: call i8* @llvm.eh.exception() +; CHECK: ret void +; CHECK: call i8* @llvm.eh.exception() ; CHECK-NEXT: call i32 (i8*, i8*, ...)* @llvm.eh.selector(i8* {{%.*}}, i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*), i8* bitcast (i8** @_ZTIi to i8*)) +; CHECK-NEXT: br label %[[LPAD]] +; CHECK: [[LPAD]]: +; CHECK-NEXT: phi i8* [ +; CHECK-NEXT: phi i32 [ +; CHECK-NEXT: call i32 @llvm.eh.typeid.for( \ No newline at end of file -- 2.34.1