<div dir="ltr">I re-reverted this (and follow-ups 234614, 234616, 234618) in 234789 as it caused PR23216.</div><div class="gmail_extra"><br><div class="gmail_quote">On Fri, Apr 10, 2015 at 10:34 AM, Reid Kleckner <span dir="ltr"><<a href="mailto:reid@kleckner.net" target="_blank">reid@kleckner.net</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: rnk<br>
Date: Fri Apr 10 12:34:52 2015<br>
New Revision: 234613<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=234613&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=234613&view=rev</a><br>
Log:<br>
[SEH] Re-land r234532, but use internal linkage for all SEH helpers<br>
<br>
Even though these symbols are in a comdat group, the Microsoft linker<br>
really wants them to have internal linkage.<br>
<br>
I'm planning to tweak the mangling in a follow-up change. This is a<br>
straight revert with a 1-line fix.<br>
<br>
Modified:<br>
    cfe/trunk/include/clang/AST/Mangle.h<br>
    cfe/trunk/lib/AST/ItaniumMangle.cpp<br>
    cfe/trunk/lib/AST/MicrosoftMangle.cpp<br>
    cfe/trunk/lib/CodeGen/CGException.cpp<br>
    cfe/trunk/lib/CodeGen/CGStmt.cpp<br>
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp<br>
    cfe/trunk/lib/CodeGen/CodeGenFunction.h<br>
    cfe/trunk/test/CodeGen/exceptions-seh-finally.c<br>
    cfe/trunk/test/CodeGen/exceptions-seh-leave.c<br>
    cfe/trunk/test/CodeGen/exceptions-seh.c<br>
<br>
Modified: cfe/trunk/include/clang/AST/Mangle.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Mangle.h?rev=234613&r1=234612&r2=234613&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Mangle.h?rev=234613&r1=234612&r2=234613&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/include/clang/AST/Mangle.h (original)<br>
+++ cfe/trunk/include/clang/AST/Mangle.h Fri Apr 10 12:34:52 2015<br>
@@ -135,6 +135,9 @@ public:<br>
   virtual void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,<br>
                                          raw_ostream &Out) = 0;<br>
<br>
+  virtual void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,<br>
+                                     raw_ostream &Out) = 0;<br>
+<br>
   /// Generates a unique string for an externally visible type for use with TBAA<br>
   /// or type uniquing.<br>
   /// TODO: Extend this to internal types by generating names that are unique<br>
<br>
Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=234613&r1=234612&r2=234613&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=234613&r1=234612&r2=234613&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)<br>
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Fri Apr 10 12:34:52 2015<br>
@@ -166,6 +166,8 @@ public:<br>
                                      raw_ostream &Out) override;<br>
   void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,<br>
                                  raw_ostream &Out) override;<br>
+  void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,<br>
+                             raw_ostream &Out) override;<br>
   void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) override;<br>
   void mangleItaniumThreadLocalWrapper(const VarDecl *D,<br>
                                        raw_ostream &) override;<br>
@@ -3964,6 +3966,16 @@ void ItaniumMangleContextImpl::mangleSEH<br>
   if (shouldMangleDeclName(EnclosingDecl))<br>
     Mangler.mangle(EnclosingDecl);<br>
   else<br>
+    Mangler.getStream() << EnclosingDecl->getName();<br>
+}<br>
+<br>
+void ItaniumMangleContextImpl::mangleSEHFinallyBlock(<br>
+    const NamedDecl *EnclosingDecl, raw_ostream &Out) {<br>
+  CXXNameMangler Mangler(*this, Out);<br>
+  Mangler.getStream() << "__fin_";<br>
+  if (shouldMangleDeclName(EnclosingDecl))<br>
+    Mangler.mangle(EnclosingDecl);<br>
+  else<br>
     Mangler.getStream() << EnclosingDecl->getName();<br>
 }<br>
<br>
<br>
Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=234613&r1=234612&r2=234613&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=234613&r1=234612&r2=234613&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)<br>
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Fri Apr 10 12:34:52 2015<br>
@@ -94,6 +94,7 @@ class MicrosoftMangleContextImpl : publi<br>
   llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier;<br>
   llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds;<br>
   llvm::DenseMap<const NamedDecl *, unsigned> SEHFilterIds;<br>
+  llvm::DenseMap<const NamedDecl *, unsigned> SEHFinallyIds;<br>
<br>
 public:<br>
   MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags)<br>
@@ -151,6 +152,8 @@ public:<br>
                                      raw_ostream &Out) override;<br>
   void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,<br>
                                  raw_ostream &Out) override;<br>
+  void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,<br>
+                             raw_ostream &Out) override;<br>
   void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;<br>
   void mangleCXXVTableBitSet(const CXXRecordDecl *RD,<br>
                              raw_ostream &Out) override;<br>
@@ -2469,6 +2472,17 @@ void MicrosoftMangleContextImpl::mangleS<br>
   Mangler.mangleName(EnclosingDecl);<br>
 }<br>
<br>
+void MicrosoftMangleContextImpl::mangleSEHFinallyBlock(<br>
+    const NamedDecl *EnclosingDecl, raw_ostream &Out) {<br>
+  MicrosoftCXXNameMangler Mangler(*this, Out);<br>
+  // The function body is in the same comdat as the function with the handler,<br>
+  // so the numbering here doesn't have to be the same across TUs.<br>
+  //<br>
+  // <mangled-name> ::= ?fin$ <filter-number> @0<br>
+  Mangler.getStream() << "\01?fin$" << SEHFinallyIds[EnclosingDecl]++ << "@0@";<br>
+  Mangler.mangleName(EnclosingDecl);<br>
+}<br>
+<br>
 void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) {<br>
   // This is just a made up unique string for the purposes of tbaa.  undname<br>
   // does *not* know how to demangle it.<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGException.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=234613&r1=234612&r2=234613&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=234613&r1=234612&r2=234613&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGException.cpp Fri Apr 10 12:34:52 2015<br>
@@ -23,6 +23,7 @@<br>
 #include "llvm/IR/CallSite.h"<br>
 #include "llvm/IR/Intrinsics.h"<br>
 #include "llvm/IR/IntrinsicInst.h"<br>
+#include "llvm/Support/SaveAndRestore.h"<br>
<br>
 using namespace clang;<br>
 using namespace CodeGen;<br>
@@ -408,13 +409,6 @@ llvm::Value *CodeGenFunction::getSelecto<br>
   return Builder.CreateLoad(getEHSelectorSlot(), "sel");<br>
 }<br>
<br>
-llvm::Value *CodeGenFunction::getAbnormalTerminationSlot() {<br>
-  if (!AbnormalTerminationSlot)<br>
-    AbnormalTerminationSlot =<br>
-        CreateTempAlloca(Int8Ty, "abnormal.termination.slot");<br>
-  return AbnormalTerminationSlot;<br>
-}<br>
-<br>
 void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E,<br>
                                        bool KeepInsertionPoint) {<br>
   if (const Expr *SubExpr = E->getSubExpr()) {<br>
@@ -1287,8 +1281,7 @@ void CodeGenFunction::EmitSEHTryStmt(con<br>
     return;<br>
   }<br>
<br>
-  SEHFinallyInfo FI;<br>
-  EnterSEHTryStmt(S, FI);<br>
+  EnterSEHTryStmt(S);<br>
   {<br>
     JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave");<br>
<br>
@@ -1301,42 +1294,36 @@ void CodeGenFunction::EmitSEHTryStmt(con<br>
     else<br>
       delete TryExit.getBlock();<br>
   }<br>
-  ExitSEHTryStmt(S, FI);<br>
+  ExitSEHTryStmt(S);<br>
 }<br>
<br>
 namespace {<br>
-struct PerformSEHFinally : EHScopeStack::Cleanup  {<br>
-  CodeGenFunction::SEHFinallyInfo *FI;<br>
-  PerformSEHFinally(CodeGenFunction::SEHFinallyInfo *FI) : FI(FI) {}<br>
+struct PerformSEHFinally : EHScopeStack::Cleanup {<br>
+  llvm::Function *OutlinedFinally;<br>
+  PerformSEHFinally(llvm::Function *OutlinedFinally)<br>
+      : OutlinedFinally(OutlinedFinally) {}<br>
<br>
   void Emit(CodeGenFunction &CGF, Flags F) override {<br>
-    // Cleanups are emitted at most twice: once for normal control flow and once<br>
-    // for exception control flow. Branch into the finally block, and remember<br>
-    // the continuation block so we can branch out later.<br>
-    if (!FI->FinallyBB) {<br>
-      FI->FinallyBB = CGF.createBasicBlock("__finally");<br>
-      FI->FinallyBB->insertInto(CGF.CurFn);<br>
-      FI->FinallyBB->moveAfter(CGF.Builder.GetInsertBlock());<br>
-    }<br>
-<br>
-    // Set the termination status and branch in.<br>
-    CGF.Builder.CreateStore(<br>
-        llvm::ConstantInt::get(CGF.Int8Ty, F.isForEHCleanup()),<br>
-        CGF.getAbnormalTerminationSlot());<br>
-    CGF.Builder.CreateBr(FI->FinallyBB);<br>
-<br>
-    // Create a continuation block for normal or exceptional control.<br>
-    if (F.isForEHCleanup()) {<br>
-      assert(!FI->ResumeBB && "double emission for EH");<br>
-      FI->ResumeBB = CGF.createBasicBlock("__finally.resume");<br>
-      CGF.EmitBlock(FI->ResumeBB);<br>
-    } else {<br>
-      assert(F.isForNormalCleanup() && !FI->ContBB && "double normal emission");<br>
-      FI->ContBB = CGF.createBasicBlock("__finally.cont");<br>
-      CGF.EmitBlock(FI->ContBB);<br>
-      // Try to keep source order.<br>
-      FI->ContBB->moveAfter(FI->FinallyBB);<br>
-    }<br>
+    ASTContext &Context = CGF.getContext();<br>
+    QualType ArgTys[2] = {Context.BoolTy, Context.VoidPtrTy};<br>
+    FunctionProtoType::ExtProtoInfo EPI;<br>
+    const auto *FTP = cast<FunctionType>(<br>
+        Context.getFunctionType(Context.VoidTy, ArgTys, EPI));<br>
+<br>
+    CallArgList Args;<br>
+    llvm::Value *IsForEH =<br>
+        llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup());<br>
+    Args.add(RValue::get(IsForEH), ArgTys[0]);<br>
+<br>
+    CodeGenModule &CGM = CGF.CGM;<br>
+    llvm::Value *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0);<br>
+    llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress);<br>
+    llvm::Value *FP = CGF.Builder.CreateCall(FrameAddr, Zero);<br>
+    Args.add(RValue::get(FP), ArgTys[1]);<br>
+<br>
+    const CGFunctionInfo &FnInfo =<br>
+        CGM.getTypes().arrangeFreeFunctionCall(Args, FTP, /*chainCall=*/false);<br>
+    CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args);<br>
   }<br>
 };<br>
 }<br>
@@ -1354,7 +1341,8 @@ struct CaptureFinder : ConstStmtVisitor<<br>
     // See if this is a capture, then recurse.<br>
     ConstStmtVisitor<CaptureFinder>::Visit(S);<br>
     for (const Stmt *Child : S->children())<br>
-      Visit(Child);<br>
+      if (Child)<br>
+        Visit(Child);<br>
   }<br>
<br>
   void VisitDeclRefExpr(const DeclRefExpr *E) {<br>
@@ -1403,12 +1391,16 @@ void CodeGenFunction::EmitCapturedLocals<br>
       CGM.ErrorUnsupported(VD, "VLA captured by SEH");<br>
       continue;<br>
     }<br>
-<br>
     assert((isa<ImplicitParamDecl>(VD) || VD->isLocalVarDeclOrParm()) &&<br>
            "captured non-local variable");<br>
<br>
-    llvm::Value *ParentVar = ParentCGF.LocalDeclMap[VD];<br>
-    assert(ParentVar && "capture was not a local decl");<br>
+    // If this decl hasn't been declared yet, it will be declared in the<br>
+    // OutlinedStmt.<br>
+    auto I = ParentCGF.LocalDeclMap.find(VD);<br>
+    if (I == ParentCGF.LocalDeclMap.end())<br>
+      continue;<br>
+    llvm::Value *ParentVar = I->second;<br>
+<br>
     llvm::CallInst *RecoverCall = nullptr;<br>
     CGBuilderTy Builder(AllocaInsertPt);<br>
     if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(ParentVar)) {<br>
@@ -1445,47 +1437,24 @@ void CodeGenFunction::EmitCapturedLocals<br>
   }<br>
 }<br>
<br>
-/// Create a stub filter function that will ultimately hold the code of the<br>
-/// filter expression. The EH preparation passes in LLVM will outline the code<br>
-/// from the main function body into this stub.<br>
-llvm::Function *<br>
-CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,<br>
-                                           const SEHExceptStmt &Except) {<br>
-  const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;<br>
+/// Arrange a function prototype that can be called by Windows exception<br>
+/// handling personalities. On Win64, the prototype looks like:<br>
+/// RetTy func(void *EHPtrs, void *ParentFP);<br>
+void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,<br>
+                                             StringRef Name, QualType RetTy,<br>
+                                             FunctionArgList &Args,<br>
+                                             const Stmt *OutlinedStmt) {<br>
   llvm::Function *ParentFn = ParentCGF.CurFn;<br>
-<br>
-  Expr *FilterExpr = Except.getFilterExpr();<br>
-<br>
-  // Get the mangled function name.<br>
-  SmallString<128> Name;<br>
-  {<br>
-    llvm::raw_svector_ostream OS(Name);<br>
-    const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);<br>
-    assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");<br>
-    CGM.getCXXABI().getMangleContext().mangleSEHFilterExpression(Parent, OS);<br>
-  }<br>
-<br>
-  // Arrange a function with the declaration:<br>
-  // int filt(EXCEPTION_POINTERS *exception_pointers, void *frame_pointer)<br>
-  QualType RetTy = getContext().IntTy;<br>
-  FunctionArgList Args;<br>
-  SEHPointersDecl = ImplicitParamDecl::Create(<br>
-      getContext(), nullptr, FilterExpr->getLocStart(),<br>
-      &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);<br>
-  Args.push_back(SEHPointersDecl);<br>
-  Args.push_back(ImplicitParamDecl::Create(<br>
-      getContext(), nullptr, FilterExpr->getLocStart(),<br>
-      &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));<br>
   const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionDeclaration(<br>
       RetTy, Args, FunctionType::ExtInfo(), /*isVariadic=*/false);<br>
+<br>
   llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);<br>
-  llvm::Function *Fn = llvm::Function::Create(FnTy, ParentFn->getLinkage(),<br>
-                                              Name.str(), &CGM.getModule());<br>
+  llvm::Function *Fn = llvm::Function::Create(<br>
+      FnTy, llvm::GlobalValue::InternalLinkage, Name.str(), &CGM.getModule());<br>
   // The filter is either in the same comdat as the function, or it's internal.<br>
   if (llvm::Comdat *C = ParentFn->getComdat()) {<br>
     Fn->setComdat(C);<br>
   } else if (ParentFn->hasWeakLinkage() || ParentFn->hasLinkOnceLinkage()) {<br>
-    // FIXME: Unreachable with Rafael's changes?<br>
     llvm::Comdat *C = CGM.getModule().getOrInsertComdat(ParentFn->getName());<br>
     ParentFn->setComdat(C);<br>
     Fn->setComdat(C);<br>
@@ -1493,14 +1462,55 @@ CodeGenFunction::GenerateSEHFilterFuncti<br>
     Fn->setLinkage(llvm::GlobalValue::InternalLinkage);<br>
   }<br>
<br>
+  IsOutlinedSEHHelper = true;<br>
+<br>
   StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args,<br>
-                FilterExpr->getLocStart(), FilterExpr->getLocStart());<br>
+                OutlinedStmt->getLocStart(), OutlinedStmt->getLocStart());<br>
<br>
-  EmitSEHExceptionCodeSave();<br>
+  CGM.SetLLVMFunctionAttributes(nullptr, FnInfo, CurFn);<br>
<br>
   auto AI = Fn->arg_begin();<br>
   ++AI;<br>
-  EmitCapturedLocals(ParentCGF, FilterExpr, &*AI);<br>
+  EmitCapturedLocals(ParentCGF, OutlinedStmt, &*AI);<br>
+}<br>
+<br>
+/// Create a stub filter function that will ultimately hold the code of the<br>
+/// filter expression. The EH preparation passes in LLVM will outline the code<br>
+/// from the main function body into this stub.<br>
+llvm::Function *<br>
+CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,<br>
+                                           const SEHExceptStmt &Except) {<br>
+  const Expr *FilterExpr = Except.getFilterExpr();<br>
+  SourceLocation StartLoc = FilterExpr->getLocStart();<br>
+<br>
+  SEHPointersDecl = ImplicitParamDecl::Create(<br>
+      getContext(), nullptr, StartLoc,<br>
+      &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);<br>
+  FunctionArgList Args;<br>
+  Args.push_back(SEHPointersDecl);<br>
+  Args.push_back(ImplicitParamDecl::Create(<br>
+      getContext(), nullptr, StartLoc,<br>
+      &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));<br>
+<br>
+  // Get the mangled function name.<br>
+  SmallString<128> Name;<br>
+  {<br>
+    llvm::raw_svector_ostream OS(Name);<br>
+    const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;<br>
+    const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);<br>
+    assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");<br>
+    CGM.getCXXABI().getMangleContext().mangleSEHFilterExpression(Parent, OS);<br>
+  }<br>
+<br>
+  startOutlinedSEHHelper(ParentCGF, Name, getContext().IntTy, Args, FilterExpr);<br>
+<br>
+  // Mark finally block calls as nounwind and noinline to make LLVM's job a<br>
+  // little easier.<br>
+  // FIXME: Remove these restrictions in the future.<br>
+  CurFn->addFnAttr(llvm::Attribute::NoUnwind);<br>
+  CurFn->addFnAttr(llvm::Attribute::NoInline);<br>
+<br>
+  EmitSEHExceptionCodeSave();<br>
<br>
   // Emit the original filter expression, convert to i32, and return.<br>
   llvm::Value *R = EmitScalarExpr(FilterExpr);<br>
@@ -1510,7 +1520,42 @@ CodeGenFunction::GenerateSEHFilterFuncti<br>
<br>
   FinishFunction(FilterExpr->getLocEnd());<br>
<br>
-  return Fn;<br>
+  return CurFn;<br>
+}<br>
+<br>
+llvm::Function *<br>
+CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,<br>
+                                            const SEHFinallyStmt &Finally) {<br>
+  const Stmt *FinallyBlock = Finally.getBlock();<br>
+  SourceLocation StartLoc = FinallyBlock->getLocStart();<br>
+<br>
+  FunctionArgList Args;<br>
+  Args.push_back(ImplicitParamDecl::Create(<br>
+      getContext(), nullptr, StartLoc,<br>
+      &getContext().Idents.get("abnormal_termination"), getContext().BoolTy));<br>
+  Args.push_back(ImplicitParamDecl::Create(<br>
+      getContext(), nullptr, StartLoc,<br>
+      &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));<br>
+<br>
+  // Get the mangled function name.<br>
+  SmallString<128> Name;<br>
+  {<br>
+    llvm::raw_svector_ostream OS(Name);<br>
+    const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;<br>
+    const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);<br>
+    assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");<br>
+    CGM.getCXXABI().getMangleContext().mangleSEHFinallyBlock(Parent, OS);<br>
+  }<br>
+<br>
+  startOutlinedSEHHelper(ParentCGF, Name, getContext().VoidTy, Args,<br>
+                         FinallyBlock);<br>
+<br>
+  // Emit the original filter expression, convert to i32, and return.<br>
+  EmitStmt(FinallyBlock);<br>
+<br>
+  FinishFunction(FinallyBlock->getLocEnd());<br>
+<br>
+  return CurFn;<br>
 }<br>
<br>
 void CodeGenFunction::EmitSEHExceptionCodeSave() {<br>
@@ -1554,21 +1599,24 @@ llvm::Value *CodeGenFunction::EmitSEHExc<br>
 }<br>
<br>
 llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {<br>
-  // Load from the abnormal termination slot. It will be uninitialized outside<br>
-  // of __finally blocks, which we should warn or error on.<br>
-  llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot());<br>
-  return Builder.CreateZExt(IsEH, Int32Ty);<br>
+  // Abnormal termination is just the first parameter to the outlined finally<br>
+  // helper.<br>
+  auto AI = CurFn->arg_begin();<br>
+  return Builder.CreateZExt(&*AI, Int32Ty);<br>
 }<br>
<br>
-void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {<br>
-  if (S.getFinallyHandler()) {<br>
+void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {<br>
+  CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);<br>
+  if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {<br>
     // Push a cleanup for __finally blocks.<br>
-    EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, &FI);<br>
+    llvm::Function *FinallyFunc =<br>
+        HelperCGF.GenerateSEHFinallyFunction(*this, *Finally);<br>
+    EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc);<br>
     return;<br>
   }<br>
<br>
   // Otherwise, we must have an __except block.<br>
-  SEHExceptStmt *Except = S.getExceptHandler();<br>
+  const SEHExceptStmt *Except = S.getExceptHandler();<br>
   assert(Except);<br>
   EHCatchScope *CatchScope = EHStack.pushCatch(1);<br>
<br>
@@ -1583,40 +1631,17 @@ void CodeGenFunction::EnterSEHTryStmt(co<br>
<br>
   // In general, we have to emit an outlined filter function. Use the function<br>
   // in place of the RTTI typeinfo global that C++ EH uses.<br>
-  CodeGenFunction FilterCGF(CGM, /*suppressNewContext=*/true);<br>
   llvm::Function *FilterFunc =<br>
-      FilterCGF.GenerateSEHFilterFunction(*this, *Except);<br>
+      HelperCGF.GenerateSEHFilterFunction(*this, *Except);<br>
   llvm::Constant *OpaqueFunc =<br>
       llvm::ConstantExpr::getBitCast(FilterFunc, Int8PtrTy);<br>
   CatchScope->setHandler(0, OpaqueFunc, createBasicBlock("__except"));<br>
 }<br>
<br>
-void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {<br>
+void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {<br>
   // Just pop the cleanup if it's a __finally block.<br>
-  if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {<br>
+  if (S.getFinallyHandler()) {<br>
     PopCleanupBlock();<br>
-    assert(FI.ContBB && "did not emit normal cleanup");<br>
-<br>
-    // Emit the code into FinallyBB.<br>
-    CGBuilderTy::InsertPoint SavedIP = Builder.saveIP();<br>
-    Builder.SetInsertPoint(FI.FinallyBB);<br>
-    EmitStmt(Finally->getBlock());<br>
-<br>
-    if (HaveInsertPoint()) {<br>
-      if (FI.ResumeBB) {<br>
-        llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot(),<br>
-                                               "abnormal.termination");<br>
-        IsEH = Builder.CreateICmpEQ(IsEH, llvm::ConstantInt::get(Int8Ty, 0));<br>
-        Builder.CreateCondBr(IsEH, FI.ContBB, FI.ResumeBB);<br>
-      } else {<br>
-        // There was nothing exceptional in the try body, so we only have normal<br>
-        // control flow.<br>
-        Builder.CreateBr(FI.ContBB);<br>
-      }<br>
-    }<br>
-<br>
-    Builder.restoreIP(SavedIP);<br>
-<br>
     return;<br>
   }<br>
<br>
@@ -1666,7 +1691,13 @@ void CodeGenFunction::EmitSEHLeaveStmt(c<br>
   if (HaveInsertPoint())<br>
     EmitStopPoint(&S);<br>
<br>
-  assert(!SEHTryEpilogueStack.empty() &&<br>
-         "sema should have rejected this __leave");<br>
+  // This must be a __leave from a __finally block, which we warn on and is UB.<br>
+  // Just emit unreachable.<br>
+  if (!isSEHTryScope()) {<br>
+    Builder.CreateUnreachable();<br>
+    Builder.ClearInsertionPoint();<br>
+    return;<br>
+  }<br>
+<br>
   EmitBranchThroughCleanup(*SEHTryEpilogueStack.back());<br>
 }<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=234613&r1=234612&r2=234613&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=234613&r1=234612&r2=234613&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Fri Apr 10 12:34:52 2015<br>
@@ -1021,6 +1021,12 @@ void CodeGenFunction::EmitReturnOfRValue<br>
 /// if the function returns void, or may be missing one if the function returns<br>
 /// non-void.  Fun stuff :).<br>
 void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {<br>
+  // Returning from an outlined SEH helper is UB, and we already warn on it.<br>
+  if (IsOutlinedSEHHelper) {<br>
+    Builder.CreateUnreachable();<br>
+    Builder.ClearInsertionPoint();<br>
+  }<br>
+<br>
   // Emit the result value, even if unused, to evalute the side effects.<br>
   const Expr *RV = S.getRetValue();<br>
<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=234613&r1=234612&r2=234613&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=234613&r1=234612&r2=234613&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Fri Apr 10 12:34:52 2015<br>
@@ -41,7 +41,7 @@ CodeGenFunction::CodeGenFunction(CodeGen<br>
       CurFn(nullptr), CapturedStmtInfo(nullptr),<br>
       SanOpts(CGM.getLangOpts().Sanitize), IsSanitizerScope(false),<br>
       CurFuncIsThunk(false), AutoreleaseResult(false), SawAsmBlock(false),<br>
-      BlockInfo(nullptr), BlockPointer(nullptr),<br>
+      IsOutlinedSEHHelper(false), BlockInfo(nullptr), BlockPointer(nullptr),<br>
       LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr),<br>
       NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr),<br>
       ExceptionSlot(nullptr), EHSelectorSlot(nullptr),<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=234613&r1=234612&r2=234613&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=234613&r1=234612&r2=234613&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)<br>
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Fri Apr 10 12:34:52 2015<br>
@@ -263,6 +263,10 @@ public:<br>
   /// potentially set the return value.<br>
   bool SawAsmBlock;<br>
<br>
+  /// True if the current function is an outlined SEH helper. This can be a<br>
+  /// finally block or filter expression.<br>
+  bool IsOutlinedSEHHelper;<br>
+<br>
   const CodeGen::CGBlockInfo *BlockInfo;<br>
   llvm::Value *BlockPointer;<br>
<br>
@@ -351,17 +355,6 @@ public:<br>
     void exit(CodeGenFunction &CGF);<br>
   };<br>
<br>
-  /// Cleanups can be emitted for two reasons: normal control leaving a region<br>
-  /// exceptional control flow leaving a region.<br>
-  struct SEHFinallyInfo {<br>
-    SEHFinallyInfo()<br>
-        : FinallyBB(nullptr), ContBB(nullptr), ResumeBB(nullptr) {}<br>
-<br>
-    llvm::BasicBlock *FinallyBB;<br>
-    llvm::BasicBlock *ContBB;<br>
-    llvm::BasicBlock *ResumeBB;<br>
-  };<br>
-<br>
   /// Returns true inside SEH __try blocks.<br>
   bool isSEHTryScope() const { return !SEHTryEpilogueStack.empty(); }<br>
<br>
@@ -1052,10 +1045,6 @@ public:<br>
   llvm::Value *getExceptionSlot();<br>
   llvm::Value *getEHSelectorSlot();<br>
<br>
-  /// Stack slot that contains whether a __finally block is being executed as an<br>
-  /// EH cleanup or as a normal cleanup.<br>
-  llvm::Value *getAbnormalTerminationSlot();<br>
-<br>
   /// Returns the contents of the function's exception object and selector<br>
   /// slots.<br>
   llvm::Value *getExceptionFromSlot();<br>
@@ -2003,12 +1992,19 @@ public:<br>
   void EmitCXXTryStmt(const CXXTryStmt &S);<br>
   void EmitSEHTryStmt(const SEHTryStmt &S);<br>
   void EmitSEHLeaveStmt(const SEHLeaveStmt &S);<br>
-  void EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI);<br>
-  void ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI);<br>
+  void EnterSEHTryStmt(const SEHTryStmt &S);<br>
+  void ExitSEHTryStmt(const SEHTryStmt &S);<br>
+<br>
+  void startOutlinedSEHHelper(CodeGenFunction &ParentCGF, StringRef Name,<br>
+                              QualType RetTy, FunctionArgList &Args,<br>
+                              const Stmt *OutlinedStmt);<br>
<br>
   llvm::Function *GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,<br>
                                             const SEHExceptStmt &Except);<br>
<br>
+  llvm::Function *GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,<br>
+                                             const SEHFinallyStmt &Finally);<br>
+<br>
   void EmitSEHExceptionCodeSave();<br>
   llvm::Value *EmitSEHExceptionCode();<br>
   llvm::Value *EmitSEHExceptionInfo();<br>
<br>
Modified: cfe/trunk/test/CodeGen/exceptions-seh-finally.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh-finally.c?rev=234613&r1=234612&r2=234613&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh-finally.c?rev=234613&r1=234612&r2=234613&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGen/exceptions-seh-finally.c (original)<br>
+++ cfe/trunk/test/CodeGen/exceptions-seh-finally.c Fri Apr 10 12:34:52 2015<br>
@@ -17,30 +17,20 @@ void basic_finally(void) {<br>
 // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]<br>
 //<br>
 // CHECK: [[invoke_cont]]<br>
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]<br>
-// CHECK: br label %[[finally:[^ ]*]]<br>
-//<br>
-// CHECK: [[finally]]<br>
-// CHECK: call void @cleanup()<br>
-// CHECK: load i8, i8* %[[abnormal]]<br>
-// CHECK: icmp eq<br>
-// CHECK: br i1 %{{.*}}, label %[[finallycont:[^ ]*]], label %[[resumecont:[^ ]*]]<br>
-//<br>
-// CHECK: [[finallycont]]<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext false, i8* %[[fp]])<br>
 // CHECK-NEXT: ret void<br>
 //<br>
 // CHECK: [[lpad]]<br>
 // CHECK-NEXT: landingpad<br>
 // CHECK-NEXT: cleanup<br>
-// CHECK: store i8 1, i8* %[[abnormal]]<br>
-// CHECK: br label %[[finally]]<br>
-//<br>
-// CHECK: [[resumecont]]<br>
-// CHECK: br label %[[ehresume:[^ ]*]]<br>
-//<br>
-// CHECK: [[ehresume]]<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext true, i8* %[[fp]])<br>
 // CHECK: resume { i8*, i32 }<br>
<br>
+// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)<br>
+// CHECK: call void @cleanup()<br>
+<br>
 // Mostly check that we don't double emit 'r' which would crash.<br>
 void decl_in_finally(void) {<br>
   __try {<br>
@@ -67,10 +57,11 @@ l:<br>
 // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]<br>
 //<br>
 // CHECK: [[invoke_cont]]<br>
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]<br>
-// CHECK: br label %[[finally:[^ ]*]]<br>
-//<br>
-// CHECK: [[finally]]<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK: call void @"\01?fin$0@0@label_in_finally@@"(i1 zeroext false, i8* %[[fp]])<br>
+// CHECK: ret void<br>
+<br>
+// CHECK: define internal void @"\01?fin$0@0@label_in_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)<br>
 // CHECK: br label %[[l:[^ ]*]]<br>
 //<br>
 // CHECK: [[l]]<br>
@@ -93,32 +84,22 @@ void use_abnormal_termination(void) {<br>
 // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]<br>
 //<br>
 // CHECK: [[invoke_cont]]<br>
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]<br>
-// CHECK: br label %[[finally:[^ ]*]]<br>
-//<br>
-// CHECK: [[finally]]<br>
-// CHECK: load i8, i8* %[[abnormal]]<br>
-// CHECK: zext i8 %{{.*}} to i32<br>
-// CHECK: store i32 %{{.*}}, i32* @crashed<br>
-// CHECK: load i8, i8* %[[abnormal]]<br>
-// CHECK: icmp eq<br>
-// CHECK: br i1 %{{.*}}, label %[[finallycont:[^ ]*]], label %[[resumecont:[^ ]*]]<br>
-//<br>
-// CHECK: [[finallycont]]<br>
-// CHECK-NEXT: ret void<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i1 zeroext false, i8* %[[fp]])<br>
+// CHECK: ret void<br>
 //<br>
 // CHECK: [[lpad]]<br>
 // CHECK-NEXT: landingpad<br>
 // CHECK-NEXT: cleanup<br>
-// CHECK: store i8 1, i8* %[[abnormal]]<br>
-// CHECK: br label %[[finally]]<br>
-//<br>
-// CHECK: [[resumecont]]<br>
-// CHECK: br label %[[ehresume:[^ ]*]]<br>
-//<br>
-// CHECK: [[ehresume]]<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK: call void @"\01?fin$0@0@use_abnormal_termination@@"(i1 zeroext true, i8* %[[fp]])<br>
 // CHECK: resume { i8*, i32 }<br>
<br>
+// CHECK: define internal void @"\01?fin$0@0@use_abnormal_termination@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)<br>
+// CHECK: %[[abnormal_zext:[^ ]*]] = zext i1 %abnormal_termination to i32<br>
+// CHECK: store i32 %[[abnormal_zext]], i32* @crashed<br>
+// CHECK-NEXT: ret void<br>
+<br>
 void noreturn_noop_finally() {<br>
   __try {<br>
     __noop();<br>
@@ -128,12 +109,13 @@ void noreturn_noop_finally() {<br>
 }<br>
<br>
 // CHECK-LABEL: define void @noreturn_noop_finally()<br>
-// CHECK: store i8 0, i8* %<br>
-// CHECK: br label %[[finally:[^ ]*]]<br>
-// CHECK: [[finally]]<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK: call void @"\01?fin$0@0@noreturn_noop_finally@@"(i1 zeroext false, i8* %[[fp]])<br>
+// CHECK: ret void<br>
+<br>
+// CHECK: define internal void @"\01?fin$0@0@noreturn_noop_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)<br>
 // CHECK: call void @abort()<br>
-// CHECK-NEXT: unreachable<br>
-// CHECK-NOT: load<br>
+// CHECK: unreachable<br>
<br>
 void noreturn_finally() {<br>
   __try {<br>
@@ -148,18 +130,20 @@ void noreturn_finally() {<br>
 // CHECK:     to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]<br>
 //<br>
 // CHECK: [[cont]]<br>
-// CHECK: store i8 0, i8* %<br>
-// CHECK: br label %[[finally:[^ ]*]]<br>
-//<br>
-// CHECK: [[finally]]<br>
-// CHECK: call void @abort()<br>
-// CHECK-NEXT: unreachable<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i1 zeroext false, i8* %[[fp]])<br>
+// CHECK: ret void<br>
 //<br>
 // CHECK: [[lpad]]<br>
 // CHECK: landingpad<br>
 // CHECK-NEXT: cleanup<br>
-// CHECK: store i8 1, i8* %<br>
-// CHECK: br label %[[finally]]<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK: call void @"\01?fin$0@0@noreturn_finally@@"(i1 zeroext true, i8* %[[fp]])<br>
+// CHECK: resume { i8*, i32 }<br>
+<br>
+// CHECK: define internal void @"\01?fin$0@0@noreturn_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)<br>
+// CHECK: call void @abort()<br>
+// CHECK: unreachable<br>
<br>
 int finally_with_return() {<br>
   __try {<br>
@@ -168,15 +152,17 @@ int finally_with_return() {<br>
   }<br>
 }<br>
 // CHECK-LABEL: define i32 @finally_with_return()<br>
-// CHECK: store i8 0, i8* %<br>
-// CHECK-NEXT: br label %[[finally:[^ ]*]]<br>
-//<br>
-// CHECK: [[finally]]<br>
-// CHECK-NEXT: br label %[[finallycont:[^ ]*]]<br>
-//<br>
-// CHECK: [[finallycont]]<br>
+// CHECK: alloca i32<br>
+// CHECK-NEXT: store i32<br>
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK-NEXT: call void @"\01?fin$0@0@finally_with_return@@"(i1 zeroext false, i8* %[[fp]])<br>
 // CHECK-NEXT: ret i32 42<br>
<br>
+// CHECK: define internal void @"\01?fin$0@0@finally_with_return@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)<br>
+// CHECK-NOT: br i1<br>
+// CHECK-NOT: br label<br>
+// CHECK: ret void<br>
+<br>
 int nested___finally___finally() {<br>
   __try {<br>
     __try {<br>
@@ -188,38 +174,28 @@ int nested___finally___finally() {<br>
   }<br>
   return 0;<br>
 }<br>
+<br>
 // CHECK-LABEL: define i32 @nested___finally___finally<br>
-// CHECK: store i8 0, i8* %<br>
-// CHECK-NEXT: br label %[[finally:[^ ]*]]<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])<br>
+// CHECK:          to label %[[outercont:[^ ]*]] unwind label %[[lpad:[^ ]*]]<br>
+//<br>
+// CHECK: [[outercont]]<br>
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])<br>
+// CHECK-NEXT: ret i32 0<br>
 //<br>
-// CHECK: [[finally]]<br>
-// CHECK-NEXT: store i32 1, i32* %<br>
-// CHECK-NEXT: store i32 1, i32* %<br>
-// CHECK-NEXT: br label %[[cleanup:[^ ]*]]<br>
-//<br>
-// The finally's unreachable continuation block:<br>
-// CHECK: store i32 0, i32* %<br>
-// CHECK-NEXT: br label %[[cleanup]]<br>
-//<br>
-// CHECK: [[cleanup]]<br>
-// CHECK-NEXT: store i8 0, i8* %<br>
-// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]<br>
-//<br>
-// CHECK: [[outerfinally]]<br>
-// CHECK-NEXT: br label %[[finallycont:[^ ]*]]<br>
-//<br>
-// CHECK: [[finallycont]]<br>
-// CHECK-NEXT: %[[dest:[^ ]*]] = load i32, i32* %<br>
-// CHECK-NEXT: switch i32 %[[dest]]<br>
-// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]]<br>
-//<br>
-// CHECK: [[cleanupcont]]<br>
-// CHECK-NEXT: store i32 0, i32* %<br>
-// CHECK-NEXT: br label %[[return:[^ ]*]]<br>
-//<br>
-// CHECK: [[return]]<br>
-// CHECK-NEXT: %[[reg:[^ ]*]] = load i32, i32* %<br>
-// CHECK-NEXT: ret i32 %[[reg]]<br>
+// CHECK: [[lpad]]<br>
+// CHECK-NEXT: landingpad<br>
+// CHECK-NEXT: cleanup<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]])<br>
+<br>
+// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)<br>
+// CHECK: ret void<br>
+<br>
+// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)<br>
+// CHECK: unreachable<br>
<br>
 int nested___finally___finally_with_eh_edge() {<br>
   __try {<br>
@@ -234,58 +210,35 @@ int nested___finally___finally_with_eh_e<br>
   return 912;<br>
 }<br>
 // CHECK-LABEL: define i32 @nested___finally___finally_with_eh_edge<br>
-// CHECK: invoke void @might_crash() #3<br>
-// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad:[^ ]*]]<br>
-//<br>
-// CHECK: [[invokecont]]<br>
-// CHECK-NEXT: store i8 0, i8* %[[abnormal:[^ ]*]]<br>
-// CHECK-NEXT: br label %[[finally:[^ ]*]]<br>
-<br>
-// CHECK: [[finally]]<br>
-// CHECK-NEXT: store i32 899, i32* %<br>
-// CHECK-NEXT: store i32 1, i32* %<br>
-// CHECK-NEXT: br label %[[cleanup:[^ ]*]]<br>
-//<br>
-// The inner finally's unreachable continuation block:<br>
-// CHECK: store i32 0, i32* %<br>
-// CHECK-NEXT: br label %[[cleanup]]<br>
-//<br>
-// CHECK: [[cleanup]]<br>
-// CHECK-NEXT: store i8 0, i8* %<br>
-// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]<br>
-//<br>
-// CHECK: [[outerfinally]]<br>
-// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8, i8* %[[abnormal]]<br>
-// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0<br>
-// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]]<br>
-//<br>
-// CHECK: [[finallycont]]<br>
-// CHECK-NEXT: %[[dest:[^ ]*]] = load i32, i32* %<br>
-// CHECK-NEXT: switch i32 %[[dest]]<br>
-// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]]<br>
-//<br>
-// CHECK: [[cleanupcont]]<br>
-// CHECK-NEXT: store i32 912, i32* %<br>
-// CHECK-NEXT: br label %[[return:[^ ]*]]<br>
+// CHECK: invoke void @might_crash()<br>
+// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad1:[^ ]*]]<br>
 //<br>
+// [[invokecont]]<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext false, i8* %[[fp]])<br>
+// CHECK:          to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]]<br>
+//<br>
+// CHECK: [[outercont]]<br>
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext false, i8* %[[fp]])<br>
+// CHECK-NEXT: ret i32 912<br>
 //<br>
-// CHECK: [[lpad]]<br>
+// CHECK: [[lpad1]]<br>
 // CHECK-NEXT: landingpad<br>
 // CHECK-NEXT: cleanup<br>
-// CHECK: store i8 1, i8* %[[abnormal]]<br>
-// CHECK: br label %[[finally]]<br>
-//<br>
-// The inner finally's unreachable resume block:<br>
-// CHECK: store i8 1, i8* %[[abnormal]]<br>
-// CHECK-NEXT: br label %[[outerfinally]]<br>
-//<br>
-// CHECK: [[finallyresume]]<br>
-// CHECK-NEXT: br label %[[ehresume:[^ ]*]]<br>
-//<br>
-// CHECK: [[return]]<br>
-// CHECK-NEXT: %[[reg:[^ ]*]] = load i32, i32* %<br>
-// CHECK-NEXT: ret i32 %[[reg]]<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK: invoke void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext true, i8* %[[fp]])<br>
+// CHECK:          to label %[[outercont:[^ ]*]] unwind label %[[lpad2]]<br>
 //<br>
-// The ehresume block, not reachable either.<br>
-// CHECK: [[ehresume]]<br>
+// CHECK: [[lpad2]]<br>
+// CHECK-NEXT: landingpad<br>
+// CHECK-NEXT: cleanup<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK: call void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext true, i8* %[[fp]])<br>
 // CHECK: resume<br>
+<br>
+// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)<br>
+// CHECK: ret void<br>
+<br>
+// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally_with_eh_edge@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)<br>
+// CHECK: unreachable<br>
<br>
Modified: cfe/trunk/test/CodeGen/exceptions-seh-leave.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh-leave.c?rev=234613&r1=234612&r2=234613&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh-leave.c?rev=234613&r1=234612&r2=234613&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGen/exceptions-seh-leave.c (original)<br>
+++ cfe/trunk/test/CodeGen/exceptions-seh-leave.c Fri Apr 10 12:34:52 2015<br>
@@ -1,6 +1,6 @@<br>
 // RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s<br>
<br>
-void g();<br>
+void g(void);<br>
<br>
 //////////////////////////////////////////////////////////////////////////////<br>
 // __leave with __except<br>
@@ -38,7 +38,7 @@ int __leave_with___except() {<br>
   return 1;<br>
 }<br>
 // CHECK-LABEL: define i32 @__leave_with___except()<br>
-// CHECK: invoke void bitcast (void (...)* @g to void ()*)()<br>
+// CHECK: invoke void @g()<br>
 // CHECK-NEXT:       to label %[[cont:.*]] unwind label %{{.*}}<br>
 // For __excepts, instead of an explicit __try.__leave label, we could use<br>
 // use invoke.cont as __leave jump target instead.  However, not doing this<br>
@@ -74,8 +74,8 @@ int __leave_with___finally_simple() {<br>
 // CHECK-NEXT: br label %[[tryleave:[^ ]*]]<br>
 // CHECK-NOT: store i32 23<br>
 // CHECK: [[tryleave]]<br>
-// CHECK-NEXT: store i8 0, i8* %<br>
-// CHECK-NEXT: br label %<br>
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_simple@@"(i1 zeroext false, i8* %[[fp]])<br>
<br>
 // __finally block doesn't return, __finally.cont doesn't exist.<br>
 int __leave_with___finally_noreturn() {<br>
@@ -94,8 +94,8 @@ int __leave_with___finally_noreturn() {<br>
 // CHECK-NEXT: br label %[[tryleave:[^ ]*]]<br>
 // CHECK-NOT: store i32 23<br>
 // CHECK: [[tryleave]]<br>
-// CHECK-NEXT: store i8 0, i8* %<br>
-// CHECK-NEXT: br label %<br>
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally_noreturn@@"(i1 zeroext false, i8* %[[fp]])<br>
<br>
 // The "normal" case.<br>
 int __leave_with___finally() {<br>
@@ -110,7 +110,7 @@ int __leave_with___finally() {<br>
   return 1;<br>
 }<br>
 // CHECK-LABEL: define i32 @__leave_with___finally()<br>
-// CHECK: invoke void bitcast (void (...)* @g to void ()*)()<br>
+// CHECK: invoke void @g()<br>
 // CHECK-NEXT:       to label %[[cont:.*]] unwind label %{{.*}}<br>
 // For __finally, there needs to be an explicit __try.__leave, because<br>
 // abnormal.termination.slot needs to be set there.<br>
@@ -118,8 +118,8 @@ int __leave_with___finally() {<br>
 // CHECK-NEXT: br label %[[tryleave:[^ ]*]]<br>
 // CHECK-NOT: store i32 23<br>
 // CHECK: [[tryleave]]<br>
-// CHECK-NEXT: store i8 0, i8* %<br>
-// CHECK-NEXT: br label %<br>
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK-NEXT: call void @"\01?fin$0@0@__leave_with___finally@@"(i1 zeroext false, i8* %[[fp]])<br>
<br>
<br>
 //////////////////////////////////////////////////////////////////////////////<br>
@@ -142,45 +142,37 @@ int nested___except___finally() {<br>
   }<br>
   return 1;<br>
 }<br>
-// The order of basic blocks in the below doesn't matter.<br>
 // CHECK-LABEL: define i32 @nested___except___finally()<br>
<br>
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()<br>
-// CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]<br>
-<br>
-// CHECK: [[g1_cont]]<br>
-// CHECK-NEXT: store i8 0, i8* %[[abnormal:[^ ]*]]<br>
-// CHECK-NEXT: br label %[[finally:[^ ]*]]<br>
+// CHECK-LABEL: invoke void @g()<br>
+// CHECK-NEXT:       to label %[[g1_cont1:.*]] unwind label %[[g1_lpad:.*]]<br>
<br>
-// CHECK: [[finally]]<br>
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)()<br>
-// CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]<br>
-<br>
-// CHECK: [[g2_cont]]<br>
-// CHECK-NEXT: br label %[[tryleave:[^ ]*]]<br>
-// CHECK-NOT: store i32 23<br>
+// CHECK: [[g1_cont1]]<br>
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i1 zeroext false, i8* %[[fp]])<br>
+// CHECK-NEXT:       to label %[[fin_cont:.*]] unwind label %[[g2_lpad:.*]]<br>
<br>
-// Unused __finally continuation block<br>
+// CHECK: [[fin_cont]]<br>
 // CHECK: store i32 51, i32* %<br>
-// CHECK-NEXT: br label %[[tryleave]]<br>
-<br>
-// CHECK: [[tryleave]]<br>
 // CHECK-NEXT: br label %[[trycont:[^ ]*]]<br>
<br>
 // CHECK: [[g1_lpad]]<br>
-// CHECK: store i8 1, i8* %<br>
-// CHECK-NEXT:  br label %[[finally]]<br>
+// CHECK-NEXT: landingpad<br>
+// CHECK-NEXT: catch i8* null<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK-NEXT: invoke void @"\01?fin$0@0@nested___except___finally@@"(i1 zeroext true, i8* %[[fp]])<br>
+// CHECK-NEXT:       to label %[[g1_resume:.*]] unwind label %[[g2_lpad]]<br>
<br>
 // CHECK: [[g2_lpad]]<br>
-// CHECK-NOT: %[[abnormal]]<br>
-// CHECK: br label %[[except:[^ ]*]]<br>
-<br>
-// CHECK: [[except]]<br>
-// CHECK-NEXT: br label %[[trycont]]<br>
+// CHECK: br label %[[trycont]]<br>
<br>
 // CHECK: [[trycont]]<br>
 // CHECK-NEXT: ret i32 1<br>
<br>
+// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___except___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)<br>
+// CHECK: call void @g()<br>
+// CHECK: unreachable<br>
+<br>
 int nested___except___except() {<br>
   int myres = 0;<br>
   __try {<br>
@@ -202,7 +194,7 @@ int nested___except___except() {<br>
 // The order of basic blocks in the below doesn't matter.<br>
 // CHECK-LABEL: define i32 @nested___except___except()<br>
<br>
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()<br>
+// CHECK-LABEL: invoke void @g()<br>
 // CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]<br>
<br>
 // CHECK: [[g1_cont]]<br>
@@ -213,7 +205,7 @@ int nested___except___except() {<br>
 // CHECK:  br label %[[except:[^ ]*]]<br>
<br>
 // CHECK: [[except]]<br>
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() #3<br>
+// CHECK-NEXT: invoke void @g()<br>
 // CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]<br>
<br>
 // CHECK: [[g2_cont]]<br>
@@ -256,7 +248,7 @@ int nested___finally___except() {<br>
 // The order of basic blocks in the below doesn't matter.<br>
 // CHECK-LABEL: define i32 @nested___finally___except()<br>
<br>
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()<br>
+// CHECK-LABEL: invoke void @g()<br>
 // CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]<br>
<br>
 // CHECK: [[g1_cont]]<br>
@@ -266,7 +258,7 @@ int nested___finally___except() {<br>
 // CHECK:  br label %[[except:[^ ]*]]<br>
<br>
 // CHECK: [[except]]<br>
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)()<br>
+// CHECK-NEXT: invoke void @g()<br>
 // CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]<br>
<br>
 // CHECK: [[g2_cont]]<br>
@@ -274,31 +266,25 @@ int nested___finally___except() {<br>
 // CHECK-NOT: 23<br>
<br>
 // CHECK: [[g2_lpad]]<br>
-// CHECK: store i8 1, i8* %[[abnormal:[^ ]*]]<br>
-// CHECK-NEXT: br label %[[finally:[^ ]*]]<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i1 zeroext true, i8* %[[fp]])<br>
+// CHECK-NEXT: br label %[[ehresume:[^ ]*]]<br>
<br>
 // CHECK: [[trycont]]<br>
 // CHECK: store i32 51, i32* %<br>
 // CHECK-NEXT: br label %[[tryleave]]<br>
<br>
 // CHECK: [[tryleave]]<br>
-// CHECK-NEXT: store i8 0, i8* %[[abnormal]]<br>
-// CHECK-NEXT: br label %[[finally:[^ ]*]]<br>
-<br>
-// CHECK: [[finally]]<br>
-// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8, i8* %[[abnormal]]<br>
-// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0<br>
-// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]]<br>
-<br>
-// CHECK: [[finallycont]]<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___except@@"(i1 zeroext false, i8* %[[fp]])<br>
 // CHECK-NEXT: ret i32 1<br>
<br>
-// CHECK: [[finallyresume]]<br>
-// CHECK-NEXT: br label %[[ehresume:[^ ]*]]<br>
-<br>
 // CHECK: [[ehresume]]<br>
 // CHECK: resume<br>
<br>
+// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___except@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)<br>
+// CHECK: ret void<br>
+<br>
 int nested___finally___finally() {<br>
   int myres = 0;<br>
   __try {<br>
@@ -320,51 +306,44 @@ int nested___finally___finally() {<br>
 // The order of basic blocks in the below doesn't matter.<br>
 // CHECK-LABEL: define i32 @nested___finally___finally()<br>
<br>
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()<br>
+// CHECK-LABEL: invoke void @g()<br>
 // CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]<br>
<br>
 // CHECK: [[g1_cont]]<br>
 // CHECK: store i32 16, i32* %[[myres:[^ ]*]],<br>
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]<br>
-// CHECK-NEXT: br label %[[finally:[^ ]*]]<br>
-<br>
-// CHECK: [[finally]]<br>
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() #3<br>
-// CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]<br>
-<br>
-// CHECK: [[g2_cont]]<br>
-// CHECK-NEXT: br label %[[tryleave:[^ ]*]]<br>
-// CHECK-NOT: store i32 23<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])<br>
+// CHECK-NEXT:       to label %[[finally_cont:.*]] unwind label %[[g2_lpad:.*]]<br>
<br>
-// There's an unreachable block for the skipped `myres = 51`.<br>
+// CHECK: [[finally_cont]]<br>
 // CHECK: store i32 51, i32* %[[myres]]<br>
-// CHECK-NEXT: br label %[[tryleave]]<br>
-<br>
-// CHECK: [[tryleave]]<br>
-// CHECK-NEXT: store i8 0, i8* %[[abnormal]]<br>
-// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]<br>
-<br>
-// CHECK: [[outerfinally]]<br>
-// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8, i8* %[[abnormal]]<br>
-// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0<br>
-// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]]<br>
-<br>
-// CHECK: [[finallycont]]<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])<br>
 // CHECK-NEXT: ret i32 1<br>
<br>
 // CHECK: [[g1_lpad]]<br>
-// CHECK: store i8 1, i8* %[[abnormal]]<br>
-// CHECK-NEXT: br label %[[finally:[^ ]*]]<br>
+// CHECK-NEXT: landingpad<br>
+// CHECK-NEXT: cleanup<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK-NEXT: invoke void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]])<br>
+// CHECK-NEXT:       to label %[[finally_cont2:.*]] unwind label %[[g2_lpad]]<br>
<br>
 // CHECK: [[g2_lpad]]<br>
-// CHECK: br label %[[ehcleanup:[^ ]*]]<br>
+// CHECK-NEXT: landingpad<br>
+// CHECK-NEXT: cleanup<br>
+// CHECK: br label %[[ehcleanup:.*]]<br>
+<br>
+// CHECK: [[finally_cont2]]<br>
+// CHECK: br label %[[ehcleanup]]<br>
<br>
 // CHECK: [[ehcleanup]]<br>
-// CHECK-NEXT: store i8 1, i8* %[[abnormal]]<br>
-// CHECK-NEXT: br label %[[outerfinally]]<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK-NEXT: call void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]])<br>
+// CHECK: resume<br>
<br>
-// CHECK: [[finallyresume]]<br>
-// CHECK-NEXT: br label %[[ehresume:[^ ]*]]<br>
+// CHECK-LABEL: define internal void @"\01?fin$0@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)<br>
+// CHECK: ret void<br>
<br>
-// CHECK: [[ehresume]]<br>
-// CHECK: resume<br>
+// CHECK-LABEL: define internal void @"\01?fin$1@0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)<br>
+// CHECK: call void @g()<br>
+// CHECK: unreachable<br>
<br>
Modified: cfe/trunk/test/CodeGen/exceptions-seh.c<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh.c?rev=234613&r1=234612&r2=234613&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh.c?rev=234613&r1=234612&r2=234613&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/CodeGen/exceptions-seh.c (original)<br>
+++ cfe/trunk/test/CodeGen/exceptions-seh.c Fri Apr 10 12:34:52 2015<br>
@@ -118,8 +118,6 @@ int nested_try(void) {<br>
 // CHECK: [[inner_try_cont]]<br>
 // CHECK: br label %[[outer_try_cont]]<br>
<br>
-// FIXME: This lowering of __finally can't actually work, it will have to<br>
-// change.<br>
 static unsigned g = 0;<br>
 void basic_finally(void) {<br>
   ++g;<br>
@@ -138,24 +136,23 @@ void basic_finally(void) {<br>
 // CHECK:       to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]<br>
 //<br>
 // CHECK: [[cont]]<br>
-// CHECK: br label %[[finally:[^ ]*]]<br>
-//<br>
-// CHECK: [[finally]]<br>
-// CHECK: load i32, i32* @g<br>
-// CHECK: add i32 %{{.*}}, -1<br>
-// CHECK: store i32 %{{.*}}, i32* @g<br>
-// CHECK: icmp eq<br>
-// CHECK: br i1 %{{.*}}, label<br>
-//<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext false, i8* %[[fp]])<br>
 // CHECK: ret void<br>
 //<br>
 // CHECK: [[lpad]]<br>
 // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)<br>
 // CHECK-NEXT: cleanup<br>
-// CHECK: br label %[[finally]]<br>
-//<br>
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)<br>
+// CHECK: call void @"\01?fin$0@0@basic_finally@@"(i1 zeroext true, i8* %[[fp]])<br>
 // CHECK: resume<br>
<br>
+// CHECK: define internal void @"\01?fin$0@0@basic_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)<br>
+// CHECK:   load i32, i32* @g, align 4<br>
+// CHECK:   add i32 %{{.*}}, -1<br>
+// CHECK:   store i32 %{{.*}}, i32* @g, align 4<br>
+// CHECK:   ret void<br>
+<br>
 int returns_int(void);<br>
 int except_return(void) {<br>
   __try {<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>