r234532 - [SEH] Outline finally blocks using the new variable capture support

Reid Kleckner reid at kleckner.net
Thu Apr 9 13:37:24 PDT 2015


Author: rnk
Date: Thu Apr  9 15:37:24 2015
New Revision: 234532

URL: http://llvm.org/viewvc/llvm-project?rev=234532&view=rev
Log:
[SEH] Outline finally blocks using the new variable capture support

WinEHPrepare was going to have to pattern match the control flow merge
and split that the old lowering used, and that wasn't really feasible.

Now we can teach WinEHPrepare to pattern match this, which is much
simpler:
  %fp = call i8* @llvm.frameaddress(i32 0)
  call void @func(iN [01], i8* %fp)

This prototype happens to match the prototype used by the Win64 SEH
personality function, so this is really simple.

Modified:
    cfe/trunk/include/clang/AST/Mangle.h
    cfe/trunk/lib/AST/ItaniumMangle.cpp
    cfe/trunk/lib/AST/MicrosoftMangle.cpp
    cfe/trunk/lib/CodeGen/CGException.cpp
    cfe/trunk/lib/CodeGen/CGStmt.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
    cfe/trunk/lib/CodeGen/CodeGenFunction.h
    cfe/trunk/test/CodeGen/exceptions-seh-finally.c
    cfe/trunk/test/CodeGen/exceptions-seh-leave.c
    cfe/trunk/test/CodeGen/exceptions-seh.c

Modified: cfe/trunk/include/clang/AST/Mangle.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Mangle.h?rev=234532&r1=234531&r2=234532&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Mangle.h (original)
+++ cfe/trunk/include/clang/AST/Mangle.h Thu Apr  9 15:37:24 2015
@@ -135,6 +135,9 @@ public:
   virtual void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
                                          raw_ostream &Out) = 0;
 
+  virtual void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
+                                     raw_ostream &Out) = 0;
+
   /// Generates a unique string for an externally visible type for use with TBAA
   /// or type uniquing.
   /// TODO: Extend this to internal types by generating names that are unique

Modified: cfe/trunk/lib/AST/ItaniumMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ItaniumMangle.cpp?rev=234532&r1=234531&r2=234532&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
+++ cfe/trunk/lib/AST/ItaniumMangle.cpp Thu Apr  9 15:37:24 2015
@@ -166,6 +166,8 @@ public:
                                      raw_ostream &Out) override;
   void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
                                  raw_ostream &Out) override;
+  void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
+                             raw_ostream &Out) override;
   void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) override;
   void mangleItaniumThreadLocalWrapper(const VarDecl *D,
                                        raw_ostream &) override;
@@ -3964,6 +3966,16 @@ void ItaniumMangleContextImpl::mangleSEH
   if (shouldMangleDeclName(EnclosingDecl))
     Mangler.mangle(EnclosingDecl);
   else
+    Mangler.getStream() << EnclosingDecl->getName();
+}
+
+void ItaniumMangleContextImpl::mangleSEHFinallyBlock(
+    const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+  CXXNameMangler Mangler(*this, Out);
+  Mangler.getStream() << "__fin_";
+  if (shouldMangleDeclName(EnclosingDecl))
+    Mangler.mangle(EnclosingDecl);
+  else
     Mangler.getStream() << EnclosingDecl->getName();
 }
 

Modified: cfe/trunk/lib/AST/MicrosoftMangle.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/MicrosoftMangle.cpp?rev=234532&r1=234531&r2=234532&view=diff
==============================================================================
--- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
+++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Thu Apr  9 15:37:24 2015
@@ -94,6 +94,7 @@ class MicrosoftMangleContextImpl : publi
   llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier;
   llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds;
   llvm::DenseMap<const NamedDecl *, unsigned> SEHFilterIds;
+  llvm::DenseMap<const NamedDecl *, unsigned> SEHFinallyIds;
 
 public:
   MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags)
@@ -151,6 +152,8 @@ public:
                                      raw_ostream &Out) override;
   void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl,
                                  raw_ostream &Out) override;
+  void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl,
+                             raw_ostream &Out) override;
   void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override;
   void mangleCXXVTableBitSet(const CXXRecordDecl *RD,
                              raw_ostream &Out) override;
@@ -2469,6 +2472,17 @@ void MicrosoftMangleContextImpl::mangleS
   Mangler.mangleName(EnclosingDecl);
 }
 
+void MicrosoftMangleContextImpl::mangleSEHFinallyBlock(
+    const NamedDecl *EnclosingDecl, raw_ostream &Out) {
+  MicrosoftCXXNameMangler Mangler(*this, Out);
+  // The function body is in the same comdat as the function with the handler,
+  // so the numbering here doesn't have to be the same across TUs.
+  //
+  // <mangled-name> ::= ?fin$ <filter-number> @0
+  Mangler.getStream() << "\01?fin$" << SEHFinallyIds[EnclosingDecl]++ << "@0@";
+  Mangler.mangleName(EnclosingDecl);
+}
+
 void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) {
   // This is just a made up unique string for the purposes of tbaa.  undname
   // does *not* know how to demangle it.

Modified: cfe/trunk/lib/CodeGen/CGException.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=234532&r1=234531&r2=234532&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Thu Apr  9 15:37:24 2015
@@ -23,6 +23,7 @@
 #include "llvm/IR/CallSite.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/IntrinsicInst.h"
+#include "llvm/Support/SaveAndRestore.h"
 
 using namespace clang;
 using namespace CodeGen;
@@ -408,13 +409,6 @@ llvm::Value *CodeGenFunction::getSelecto
   return Builder.CreateLoad(getEHSelectorSlot(), "sel");
 }
 
-llvm::Value *CodeGenFunction::getAbnormalTerminationSlot() {
-  if (!AbnormalTerminationSlot)
-    AbnormalTerminationSlot =
-        CreateTempAlloca(Int8Ty, "abnormal.termination.slot");
-  return AbnormalTerminationSlot;
-}
-
 void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E,
                                        bool KeepInsertionPoint) {
   if (const Expr *SubExpr = E->getSubExpr()) {
@@ -1287,8 +1281,7 @@ void CodeGenFunction::EmitSEHTryStmt(con
     return;
   }
 
-  SEHFinallyInfo FI;
-  EnterSEHTryStmt(S, FI);
+  EnterSEHTryStmt(S);
   {
     JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave");
 
@@ -1301,42 +1294,36 @@ void CodeGenFunction::EmitSEHTryStmt(con
     else
       delete TryExit.getBlock();
   }
-  ExitSEHTryStmt(S, FI);
+  ExitSEHTryStmt(S);
 }
 
 namespace {
-struct PerformSEHFinally : EHScopeStack::Cleanup  {
-  CodeGenFunction::SEHFinallyInfo *FI;
-  PerformSEHFinally(CodeGenFunction::SEHFinallyInfo *FI) : FI(FI) {}
+struct PerformSEHFinally : EHScopeStack::Cleanup {
+  llvm::Function *OutlinedFinally;
+  PerformSEHFinally(llvm::Function *OutlinedFinally)
+      : OutlinedFinally(OutlinedFinally) {}
 
   void Emit(CodeGenFunction &CGF, Flags F) override {
-    // Cleanups are emitted at most twice: once for normal control flow and once
-    // for exception control flow. Branch into the finally block, and remember
-    // the continuation block so we can branch out later.
-    if (!FI->FinallyBB) {
-      FI->FinallyBB = CGF.createBasicBlock("__finally");
-      FI->FinallyBB->insertInto(CGF.CurFn);
-      FI->FinallyBB->moveAfter(CGF.Builder.GetInsertBlock());
-    }
-
-    // Set the termination status and branch in.
-    CGF.Builder.CreateStore(
-        llvm::ConstantInt::get(CGF.Int8Ty, F.isForEHCleanup()),
-        CGF.getAbnormalTerminationSlot());
-    CGF.Builder.CreateBr(FI->FinallyBB);
-
-    // Create a continuation block for normal or exceptional control.
-    if (F.isForEHCleanup()) {
-      assert(!FI->ResumeBB && "double emission for EH");
-      FI->ResumeBB = CGF.createBasicBlock("__finally.resume");
-      CGF.EmitBlock(FI->ResumeBB);
-    } else {
-      assert(F.isForNormalCleanup() && !FI->ContBB && "double normal emission");
-      FI->ContBB = CGF.createBasicBlock("__finally.cont");
-      CGF.EmitBlock(FI->ContBB);
-      // Try to keep source order.
-      FI->ContBB->moveAfter(FI->FinallyBB);
-    }
+    ASTContext &Context = CGF.getContext();
+    QualType ArgTys[2] = {Context.BoolTy, Context.VoidPtrTy};
+    FunctionProtoType::ExtProtoInfo EPI;
+    const auto *FTP = cast<FunctionType>(
+        Context.getFunctionType(Context.VoidTy, ArgTys, EPI));
+
+    CallArgList Args;
+    llvm::Value *IsForEH =
+        llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]), F.isForEHCleanup());
+    Args.add(RValue::get(IsForEH), ArgTys[0]);
+
+    CodeGenModule &CGM = CGF.CGM;
+    llvm::Value *Zero = llvm::ConstantInt::get(CGM.Int32Ty, 0);
+    llvm::Value *FrameAddr = CGM.getIntrinsic(llvm::Intrinsic::frameaddress);
+    llvm::Value *FP = CGF.Builder.CreateCall(FrameAddr, Zero);
+    Args.add(RValue::get(FP), ArgTys[1]);
+
+    const CGFunctionInfo &FnInfo =
+        CGM.getTypes().arrangeFreeFunctionCall(Args, FTP, /*chainCall=*/false);
+    CGF.EmitCall(FnInfo, OutlinedFinally, ReturnValueSlot(), Args);
   }
 };
 }
@@ -1354,7 +1341,8 @@ struct CaptureFinder : ConstStmtVisitor<
     // See if this is a capture, then recurse.
     ConstStmtVisitor<CaptureFinder>::Visit(S);
     for (const Stmt *Child : S->children())
-      Visit(Child);
+      if (Child)
+        Visit(Child);
   }
 
   void VisitDeclRefExpr(const DeclRefExpr *E) {
@@ -1403,12 +1391,16 @@ void CodeGenFunction::EmitCapturedLocals
       CGM.ErrorUnsupported(VD, "VLA captured by SEH");
       continue;
     }
-
     assert((isa<ImplicitParamDecl>(VD) || VD->isLocalVarDeclOrParm()) &&
            "captured non-local variable");
 
-    llvm::Value *ParentVar = ParentCGF.LocalDeclMap[VD];
-    assert(ParentVar && "capture was not a local decl");
+    // If this decl hasn't been declared yet, it will be declared in the
+    // OutlinedStmt.
+    auto I = ParentCGF.LocalDeclMap.find(VD);
+    if (I == ParentCGF.LocalDeclMap.end())
+      continue;
+    llvm::Value *ParentVar = I->second;
+
     llvm::CallInst *RecoverCall = nullptr;
     CGBuilderTy Builder(AllocaInsertPt);
     if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(ParentVar)) {
@@ -1445,39 +1437,17 @@ void CodeGenFunction::EmitCapturedLocals
   }
 }
 
-/// Create a stub filter function that will ultimately hold the code of the
-/// filter expression. The EH preparation passes in LLVM will outline the code
-/// from the main function body into this stub.
-llvm::Function *
-CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
-                                           const SEHExceptStmt &Except) {
-  const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
+/// Arrange a function prototype that can be called by Windows exception
+/// handling personalities. On Win64, the prototype looks like:
+/// RetTy func(void *EHPtrs, void *ParentFP);
+void CodeGenFunction::startOutlinedSEHHelper(CodeGenFunction &ParentCGF,
+                                             StringRef Name, QualType RetTy,
+                                             FunctionArgList &Args,
+                                             const Stmt *OutlinedStmt) {
   llvm::Function *ParentFn = ParentCGF.CurFn;
-
-  Expr *FilterExpr = Except.getFilterExpr();
-
-  // Get the mangled function name.
-  SmallString<128> Name;
-  {
-    llvm::raw_svector_ostream OS(Name);
-    const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);
-    assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");
-    CGM.getCXXABI().getMangleContext().mangleSEHFilterExpression(Parent, OS);
-  }
-
-  // Arrange a function with the declaration:
-  // int filt(EXCEPTION_POINTERS *exception_pointers, void *frame_pointer)
-  QualType RetTy = getContext().IntTy;
-  FunctionArgList Args;
-  SEHPointersDecl = ImplicitParamDecl::Create(
-      getContext(), nullptr, FilterExpr->getLocStart(),
-      &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);
-  Args.push_back(SEHPointersDecl);
-  Args.push_back(ImplicitParamDecl::Create(
-      getContext(), nullptr, FilterExpr->getLocStart(),
-      &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
   const CGFunctionInfo &FnInfo = CGM.getTypes().arrangeFreeFunctionDeclaration(
       RetTy, Args, FunctionType::ExtInfo(), /*isVariadic=*/false);
+
   llvm::FunctionType *FnTy = CGM.getTypes().GetFunctionType(FnInfo);
   llvm::Function *Fn = llvm::Function::Create(FnTy, ParentFn->getLinkage(),
                                               Name.str(), &CGM.getModule());
@@ -1485,7 +1455,6 @@ CodeGenFunction::GenerateSEHFilterFuncti
   if (llvm::Comdat *C = ParentFn->getComdat()) {
     Fn->setComdat(C);
   } else if (ParentFn->hasWeakLinkage() || ParentFn->hasLinkOnceLinkage()) {
-    // FIXME: Unreachable with Rafael's changes?
     llvm::Comdat *C = CGM.getModule().getOrInsertComdat(ParentFn->getName());
     ParentFn->setComdat(C);
     Fn->setComdat(C);
@@ -1493,14 +1462,55 @@ CodeGenFunction::GenerateSEHFilterFuncti
     Fn->setLinkage(llvm::GlobalValue::InternalLinkage);
   }
 
+  IsOutlinedSEHHelper = true;
+
   StartFunction(GlobalDecl(), RetTy, Fn, FnInfo, Args,
-                FilterExpr->getLocStart(), FilterExpr->getLocStart());
+                OutlinedStmt->getLocStart(), OutlinedStmt->getLocStart());
 
-  EmitSEHExceptionCodeSave();
+  CGM.SetLLVMFunctionAttributes(nullptr, FnInfo, CurFn);
 
   auto AI = Fn->arg_begin();
   ++AI;
-  EmitCapturedLocals(ParentCGF, FilterExpr, &*AI);
+  EmitCapturedLocals(ParentCGF, OutlinedStmt, &*AI);
+}
+
+/// Create a stub filter function that will ultimately hold the code of the
+/// filter expression. The EH preparation passes in LLVM will outline the code
+/// from the main function body into this stub.
+llvm::Function *
+CodeGenFunction::GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
+                                           const SEHExceptStmt &Except) {
+  const Expr *FilterExpr = Except.getFilterExpr();
+  SourceLocation StartLoc = FilterExpr->getLocStart();
+
+  SEHPointersDecl = ImplicitParamDecl::Create(
+      getContext(), nullptr, StartLoc,
+      &getContext().Idents.get("exception_pointers"), getContext().VoidPtrTy);
+  FunctionArgList Args;
+  Args.push_back(SEHPointersDecl);
+  Args.push_back(ImplicitParamDecl::Create(
+      getContext(), nullptr, StartLoc,
+      &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
+
+  // Get the mangled function name.
+  SmallString<128> Name;
+  {
+    llvm::raw_svector_ostream OS(Name);
+    const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
+    const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);
+    assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");
+    CGM.getCXXABI().getMangleContext().mangleSEHFilterExpression(Parent, OS);
+  }
+
+  startOutlinedSEHHelper(ParentCGF, Name, getContext().IntTy, Args, FilterExpr);
+
+  // Mark finally block calls as nounwind and noinline to make LLVM's job a
+  // little easier.
+  // FIXME: Remove these restrictions in the future.
+  CurFn->addFnAttr(llvm::Attribute::NoUnwind);
+  CurFn->addFnAttr(llvm::Attribute::NoInline);
+
+  EmitSEHExceptionCodeSave();
 
   // Emit the original filter expression, convert to i32, and return.
   llvm::Value *R = EmitScalarExpr(FilterExpr);
@@ -1510,7 +1520,42 @@ CodeGenFunction::GenerateSEHFilterFuncti
 
   FinishFunction(FilterExpr->getLocEnd());
 
-  return Fn;
+  return CurFn;
+}
+
+llvm::Function *
+CodeGenFunction::GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,
+                                            const SEHFinallyStmt &Finally) {
+  const Stmt *FinallyBlock = Finally.getBlock();
+  SourceLocation StartLoc = FinallyBlock->getLocStart();
+
+  FunctionArgList Args;
+  Args.push_back(ImplicitParamDecl::Create(
+      getContext(), nullptr, StartLoc,
+      &getContext().Idents.get("abnormal_termination"), getContext().BoolTy));
+  Args.push_back(ImplicitParamDecl::Create(
+      getContext(), nullptr, StartLoc,
+      &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
+
+  // Get the mangled function name.
+  SmallString<128> Name;
+  {
+    llvm::raw_svector_ostream OS(Name);
+    const Decl *ParentCodeDecl = ParentCGF.CurCodeDecl;
+    const NamedDecl *Parent = dyn_cast_or_null<NamedDecl>(ParentCodeDecl);
+    assert(Parent && "FIXME: handle unnamed decls (lambdas, blocks) with SEH");
+    CGM.getCXXABI().getMangleContext().mangleSEHFinallyBlock(Parent, OS);
+  }
+
+  startOutlinedSEHHelper(ParentCGF, Name, getContext().VoidTy, Args,
+                         FinallyBlock);
+
+  // Emit the original filter expression, convert to i32, and return.
+  EmitStmt(FinallyBlock);
+
+  FinishFunction(FinallyBlock->getLocEnd());
+
+  return CurFn;
 }
 
 void CodeGenFunction::EmitSEHExceptionCodeSave() {
@@ -1554,21 +1599,24 @@ llvm::Value *CodeGenFunction::EmitSEHExc
 }
 
 llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {
-  // Load from the abnormal termination slot. It will be uninitialized outside
-  // of __finally blocks, which we should warn or error on.
-  llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot());
-  return Builder.CreateZExt(IsEH, Int32Ty);
+  // Abnormal termination is just the first parameter to the outlined finally
+  // helper.
+  auto AI = CurFn->arg_begin();
+  return Builder.CreateZExt(&*AI, Int32Ty);
 }
 
-void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {
-  if (S.getFinallyHandler()) {
+void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
+  CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
+  if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
     // Push a cleanup for __finally blocks.
-    EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, &FI);
+    llvm::Function *FinallyFunc =
+        HelperCGF.GenerateSEHFinallyFunction(*this, *Finally);
+    EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup, FinallyFunc);
     return;
   }
 
   // Otherwise, we must have an __except block.
-  SEHExceptStmt *Except = S.getExceptHandler();
+  const SEHExceptStmt *Except = S.getExceptHandler();
   assert(Except);
   EHCatchScope *CatchScope = EHStack.pushCatch(1);
 
@@ -1583,40 +1631,17 @@ void CodeGenFunction::EnterSEHTryStmt(co
 
   // In general, we have to emit an outlined filter function. Use the function
   // in place of the RTTI typeinfo global that C++ EH uses.
-  CodeGenFunction FilterCGF(CGM, /*suppressNewContext=*/true);
   llvm::Function *FilterFunc =
-      FilterCGF.GenerateSEHFilterFunction(*this, *Except);
+      HelperCGF.GenerateSEHFilterFunction(*this, *Except);
   llvm::Constant *OpaqueFunc =
       llvm::ConstantExpr::getBitCast(FilterFunc, Int8PtrTy);
   CatchScope->setHandler(0, OpaqueFunc, createBasicBlock("__except"));
 }
 
-void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI) {
+void CodeGenFunction::ExitSEHTryStmt(const SEHTryStmt &S) {
   // Just pop the cleanup if it's a __finally block.
-  if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
+  if (S.getFinallyHandler()) {
     PopCleanupBlock();
-    assert(FI.ContBB && "did not emit normal cleanup");
-
-    // Emit the code into FinallyBB.
-    CGBuilderTy::InsertPoint SavedIP = Builder.saveIP();
-    Builder.SetInsertPoint(FI.FinallyBB);
-    EmitStmt(Finally->getBlock());
-
-    if (HaveInsertPoint()) {
-      if (FI.ResumeBB) {
-        llvm::Value *IsEH = Builder.CreateLoad(getAbnormalTerminationSlot(),
-                                               "abnormal.termination");
-        IsEH = Builder.CreateICmpEQ(IsEH, llvm::ConstantInt::get(Int8Ty, 0));
-        Builder.CreateCondBr(IsEH, FI.ContBB, FI.ResumeBB);
-      } else {
-        // There was nothing exceptional in the try body, so we only have normal
-        // control flow.
-        Builder.CreateBr(FI.ContBB);
-      }
-    }
-
-    Builder.restoreIP(SavedIP);
-
     return;
   }
 
@@ -1666,7 +1691,13 @@ void CodeGenFunction::EmitSEHLeaveStmt(c
   if (HaveInsertPoint())
     EmitStopPoint(&S);
 
-  assert(!SEHTryEpilogueStack.empty() &&
-         "sema should have rejected this __leave");
+  // This must be a __leave from a __finally block, which we warn on and is UB.
+  // Just emit unreachable.
+  if (!isSEHTryScope()) {
+    Builder.CreateUnreachable();
+    Builder.ClearInsertionPoint();
+    return;
+  }
+
   EmitBranchThroughCleanup(*SEHTryEpilogueStack.back());
 }

Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=234532&r1=234531&r2=234532&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Thu Apr  9 15:37:24 2015
@@ -1021,6 +1021,12 @@ void CodeGenFunction::EmitReturnOfRValue
 /// if the function returns void, or may be missing one if the function returns
 /// non-void.  Fun stuff :).
 void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
+  // Returning from an outlined SEH helper is UB, and we already warn on it.
+  if (IsOutlinedSEHHelper) {
+    Builder.CreateUnreachable();
+    Builder.ClearInsertionPoint();
+  }
+
   // Emit the result value, even if unused, to evalute the side effects.
   const Expr *RV = S.getRetValue();
 

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=234532&r1=234531&r2=234532&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Thu Apr  9 15:37:24 2015
@@ -40,7 +40,7 @@ CodeGenFunction::CodeGenFunction(CodeGen
       CurFn(nullptr), CapturedStmtInfo(nullptr),
       SanOpts(CGM.getLangOpts().Sanitize), IsSanitizerScope(false),
       CurFuncIsThunk(false), AutoreleaseResult(false), SawAsmBlock(false),
-      BlockInfo(nullptr), BlockPointer(nullptr),
+      IsOutlinedSEHHelper(false), BlockInfo(nullptr), BlockPointer(nullptr),
       LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr),
       NextCleanupDestIndex(1), FirstBlockInfo(nullptr), EHResumeBlock(nullptr),
       ExceptionSlot(nullptr), EHSelectorSlot(nullptr),

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=234532&r1=234531&r2=234532&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Thu Apr  9 15:37:24 2015
@@ -263,6 +263,10 @@ public:
   /// potentially set the return value.
   bool SawAsmBlock;
 
+  /// True if the current function is an outlined SEH helper. This can be a
+  /// finally block or filter expression.
+  bool IsOutlinedSEHHelper;
+
   const CodeGen::CGBlockInfo *BlockInfo;
   llvm::Value *BlockPointer;
 
@@ -351,17 +355,6 @@ public:
     void exit(CodeGenFunction &CGF);
   };
 
-  /// Cleanups can be emitted for two reasons: normal control leaving a region
-  /// exceptional control flow leaving a region.
-  struct SEHFinallyInfo {
-    SEHFinallyInfo()
-        : FinallyBB(nullptr), ContBB(nullptr), ResumeBB(nullptr) {}
-
-    llvm::BasicBlock *FinallyBB;
-    llvm::BasicBlock *ContBB;
-    llvm::BasicBlock *ResumeBB;
-  };
-
   /// Returns true inside SEH __try blocks.
   bool isSEHTryScope() const { return !SEHTryEpilogueStack.empty(); }
 
@@ -1052,10 +1045,6 @@ public:
   llvm::Value *getExceptionSlot();
   llvm::Value *getEHSelectorSlot();
 
-  /// Stack slot that contains whether a __finally block is being executed as an
-  /// EH cleanup or as a normal cleanup.
-  llvm::Value *getAbnormalTerminationSlot();
-
   /// Returns the contents of the function's exception object and selector
   /// slots.
   llvm::Value *getExceptionFromSlot();
@@ -2000,12 +1989,19 @@ public:
   void EmitCXXTryStmt(const CXXTryStmt &S);
   void EmitSEHTryStmt(const SEHTryStmt &S);
   void EmitSEHLeaveStmt(const SEHLeaveStmt &S);
-  void EnterSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI);
-  void ExitSEHTryStmt(const SEHTryStmt &S, SEHFinallyInfo &FI);
+  void EnterSEHTryStmt(const SEHTryStmt &S);
+  void ExitSEHTryStmt(const SEHTryStmt &S);
+
+  void startOutlinedSEHHelper(CodeGenFunction &ParentCGF, StringRef Name,
+                              QualType RetTy, FunctionArgList &Args,
+                              const Stmt *OutlinedStmt);
 
   llvm::Function *GenerateSEHFilterFunction(CodeGenFunction &ParentCGF,
                                             const SEHExceptStmt &Except);
 
+  llvm::Function *GenerateSEHFinallyFunction(CodeGenFunction &ParentCGF,
+                                             const SEHFinallyStmt &Finally);
+
   void EmitSEHExceptionCodeSave();
   llvm::Value *EmitSEHExceptionCode();
   llvm::Value *EmitSEHExceptionInfo();

Modified: cfe/trunk/test/CodeGen/exceptions-seh-finally.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh-finally.c?rev=234532&r1=234531&r2=234532&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/exceptions-seh-finally.c (original)
+++ cfe/trunk/test/CodeGen/exceptions-seh-finally.c Thu Apr  9 15:37:24 2015
@@ -17,30 +17,20 @@ void basic_finally(void) {
 // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
 //
 // CHECK: [[invoke_cont]]
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
-// CHECK: call void @cleanup()
-// CHECK: load i8, i8* %[[abnormal]]
-// CHECK: icmp eq
-// CHECK: br i1 %{{.*}}, label %[[finallycont:[^ ]*]], label %[[resumecont:[^ ]*]]
-//
-// CHECK: [[finallycont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@basic_finally@@"(i1 zeroext false, i8* %[[fp]])
 // CHECK-NEXT: ret void
 //
 // CHECK: [[lpad]]
 // CHECK-NEXT: landingpad
 // CHECK-NEXT: cleanup
-// CHECK: store i8 1, i8* %[[abnormal]]
-// CHECK: br label %[[finally]]
-//
-// CHECK: [[resumecont]]
-// CHECK: br label %[[ehresume:[^ ]*]]
-//
-// CHECK: [[ehresume]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@basic_finally@@"(i1 zeroext true, i8* %[[fp]])
 // CHECK: resume { i8*, i32 }
 
+// CHECK: define internal void @"\01?fin$0 at 0@basic_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: call void @cleanup()
+
 // Mostly check that we don't double emit 'r' which would crash.
 void decl_in_finally(void) {
   __try {
@@ -67,10 +57,11 @@ l:
 // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
 //
 // CHECK: [[invoke_cont]]
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@label_in_finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: ret void
+
+// CHECK: define internal void @"\01?fin$0 at 0@label_in_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
 // CHECK: br label %[[l:[^ ]*]]
 //
 // CHECK: [[l]]
@@ -93,32 +84,22 @@ void use_abnormal_termination(void) {
 // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
 //
 // CHECK: [[invoke_cont]]
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
-// CHECK: load i8, i8* %[[abnormal]]
-// CHECK: zext i8 %{{.*}} to i32
-// CHECK: store i32 %{{.*}}, i32* @crashed
-// CHECK: load i8, i8* %[[abnormal]]
-// CHECK: icmp eq
-// CHECK: br i1 %{{.*}}, label %[[finallycont:[^ ]*]], label %[[resumecont:[^ ]*]]
-//
-// CHECK: [[finallycont]]
-// CHECK-NEXT: ret void
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@use_abnormal_termination@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: ret void
 //
 // CHECK: [[lpad]]
 // CHECK-NEXT: landingpad
 // CHECK-NEXT: cleanup
-// CHECK: store i8 1, i8* %[[abnormal]]
-// CHECK: br label %[[finally]]
-//
-// CHECK: [[resumecont]]
-// CHECK: br label %[[ehresume:[^ ]*]]
-//
-// CHECK: [[ehresume]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@use_abnormal_termination@@"(i1 zeroext true, i8* %[[fp]])
 // CHECK: resume { i8*, i32 }
 
+// CHECK: define internal void @"\01?fin$0 at 0@use_abnormal_termination@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: %[[abnormal_zext:[^ ]*]] = zext i1 %abnormal_termination to i32
+// CHECK: store i32 %[[abnormal_zext]], i32* @crashed
+// CHECK-NEXT: ret void
+
 void noreturn_noop_finally() {
   __try {
     __noop();
@@ -128,12 +109,13 @@ void noreturn_noop_finally() {
 }
 
 // CHECK-LABEL: define void @noreturn_noop_finally()
-// CHECK: store i8 0, i8* %
-// CHECK: br label %[[finally:[^ ]*]]
-// CHECK: [[finally]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@noreturn_noop_finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: ret void
+
+// CHECK: define internal void @"\01?fin$0 at 0@noreturn_noop_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
 // CHECK: call void @abort()
-// CHECK-NEXT: unreachable
-// CHECK-NOT: load
+// CHECK: unreachable
 
 void noreturn_finally() {
   __try {
@@ -148,18 +130,20 @@ void noreturn_finally() {
 // CHECK:     to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
 //
 // CHECK: [[cont]]
-// CHECK: store i8 0, i8* %
-// CHECK: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
-// CHECK: call void @abort()
-// CHECK-NEXT: unreachable
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@noreturn_finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK: ret void
 //
 // CHECK: [[lpad]]
 // CHECK: landingpad
 // CHECK-NEXT: cleanup
-// CHECK: store i8 1, i8* %
-// CHECK: br label %[[finally]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@noreturn_finally@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK: resume { i8*, i32 }
+
+// CHECK: define internal void @"\01?fin$0 at 0@noreturn_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: call void @abort()
+// CHECK: unreachable
 
 int finally_with_return() {
   __try {
@@ -168,15 +152,17 @@ int finally_with_return() {
   }
 }
 // CHECK-LABEL: define i32 @finally_with_return()
-// CHECK: store i8 0, i8* %
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
-// CHECK-NEXT: br label %[[finallycont:[^ ]*]]
-//
-// CHECK: [[finallycont]]
+// CHECK: alloca i32
+// CHECK-NEXT: store i32
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@finally_with_return@@"(i1 zeroext false, i8* %[[fp]])
 // CHECK-NEXT: ret i32 42
 
+// CHECK: define internal void @"\01?fin$0 at 0@finally_with_return@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK-NOT: br i1
+// CHECK-NOT: br label
+// CHECK: ret void
+
 int nested___finally___finally() {
   __try {
     __try {
@@ -188,38 +174,28 @@ int nested___finally___finally() {
   }
   return 0;
 }
+
 // CHECK-LABEL: define i32 @nested___finally___finally
-// CHECK: store i8 0, i8* %
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: invoke void @"\01?fin$1 at 0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK:          to label %[[outercont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
+//
+// CHECK: [[outercont]]
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK-NEXT: ret i32 0
 //
-// CHECK: [[finally]]
-// CHECK-NEXT: store i32 1, i32* %
-// CHECK-NEXT: store i32 1, i32* %
-// CHECK-NEXT: br label %[[cleanup:[^ ]*]]
-//
-// The finally's unreachable continuation block:
-// CHECK: store i32 0, i32* %
-// CHECK-NEXT: br label %[[cleanup]]
-//
-// CHECK: [[cleanup]]
-// CHECK-NEXT: store i8 0, i8* %
-// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]
-//
-// CHECK: [[outerfinally]]
-// CHECK-NEXT: br label %[[finallycont:[^ ]*]]
-//
-// CHECK: [[finallycont]]
-// CHECK-NEXT: %[[dest:[^ ]*]] = load i32, i32* %
-// CHECK-NEXT: switch i32 %[[dest]]
-// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]]
-//
-// CHECK: [[cleanupcont]]
-// CHECK-NEXT: store i32 0, i32* %
-// CHECK-NEXT: br label %[[return:[^ ]*]]
-//
-// CHECK: [[return]]
-// CHECK-NEXT: %[[reg:[^ ]*]] = load i32, i32* %
-// CHECK-NEXT: ret i32 %[[reg]]
+// CHECK: [[lpad]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]])
+
+// CHECK-LABEL: define internal void @"\01?fin$0 at 0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: ret void
+
+// CHECK-LABEL: define internal void @"\01?fin$1 at 0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: unreachable
 
 int nested___finally___finally_with_eh_edge() {
   __try {
@@ -234,58 +210,35 @@ int nested___finally___finally_with_eh_e
   return 912;
 }
 // CHECK-LABEL: define i32 @nested___finally___finally_with_eh_edge
-// CHECK: invoke void @might_crash() #3
-// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
-//
-// CHECK: [[invokecont]]
-// CHECK-NEXT: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
-
-// CHECK: [[finally]]
-// CHECK-NEXT: store i32 899, i32* %
-// CHECK-NEXT: store i32 1, i32* %
-// CHECK-NEXT: br label %[[cleanup:[^ ]*]]
-//
-// The inner finally's unreachable continuation block:
-// CHECK: store i32 0, i32* %
-// CHECK-NEXT: br label %[[cleanup]]
-//
-// CHECK: [[cleanup]]
-// CHECK-NEXT: store i8 0, i8* %
-// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]
-//
-// CHECK: [[outerfinally]]
-// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8, i8* %[[abnormal]]
-// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0
-// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]]
-//
-// CHECK: [[finallycont]]
-// CHECK-NEXT: %[[dest:[^ ]*]] = load i32, i32* %
-// CHECK-NEXT: switch i32 %[[dest]]
-// CHECK-NEXT: i32 0, label %[[cleanupcont:[^ ]*]]
-//
-// CHECK: [[cleanupcont]]
-// CHECK-NEXT: store i32 912, i32* %
-// CHECK-NEXT: br label %[[return:[^ ]*]]
+// CHECK: invoke void @might_crash()
+// CHECK-NEXT: to label %[[invokecont:[^ ]*]] unwind label %[[lpad1:[^ ]*]]
 //
+// [[invokecont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: invoke void @"\01?fin$1 at 0@nested___finally___finally_with_eh_edge@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK:          to label %[[outercont:[^ ]*]] unwind label %[[lpad2:[^ ]*]]
+//
+// CHECK: [[outercont]]
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@nested___finally___finally_with_eh_edge@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK-NEXT: ret i32 912
 //
-// CHECK: [[lpad]]
+// CHECK: [[lpad1]]
 // CHECK-NEXT: landingpad
 // CHECK-NEXT: cleanup
-// CHECK: store i8 1, i8* %[[abnormal]]
-// CHECK: br label %[[finally]]
-//
-// The inner finally's unreachable resume block:
-// CHECK: store i8 1, i8* %[[abnormal]]
-// CHECK-NEXT: br label %[[outerfinally]]
-//
-// CHECK: [[finallyresume]]
-// CHECK-NEXT: br label %[[ehresume:[^ ]*]]
-//
-// CHECK: [[return]]
-// CHECK-NEXT: %[[reg:[^ ]*]] = load i32, i32* %
-// CHECK-NEXT: ret i32 %[[reg]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: invoke void @"\01?fin$1 at 0@nested___finally___finally_with_eh_edge@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK:          to label %[[outercont:[^ ]*]] unwind label %[[lpad2]]
 //
-// The ehresume block, not reachable either.
-// CHECK: [[ehresume]]
+// CHECK: [[lpad2]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@nested___finally___finally_with_eh_edge@@"(i1 zeroext true, i8* %[[fp]])
 // CHECK: resume
+
+// CHECK-LABEL: define internal void @"\01?fin$0 at 0@nested___finally___finally_with_eh_edge@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: ret void
+
+// CHECK-LABEL: define internal void @"\01?fin$1 at 0@nested___finally___finally_with_eh_edge@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: unreachable

Modified: cfe/trunk/test/CodeGen/exceptions-seh-leave.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh-leave.c?rev=234532&r1=234531&r2=234532&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/exceptions-seh-leave.c (original)
+++ cfe/trunk/test/CodeGen/exceptions-seh-leave.c Thu Apr  9 15:37:24 2015
@@ -1,6 +1,6 @@
 // RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm -o - | FileCheck %s
 
-void g();
+void g(void);
 
 //////////////////////////////////////////////////////////////////////////////
 // __leave with __except
@@ -38,7 +38,7 @@ int __leave_with___except() {
   return 1;
 }
 // CHECK-LABEL: define i32 @__leave_with___except()
-// CHECK: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK: invoke void @g()
 // CHECK-NEXT:       to label %[[cont:.*]] unwind label %{{.*}}
 // For __excepts, instead of an explicit __try.__leave label, we could use
 // use invoke.cont as __leave jump target instead.  However, not doing this
@@ -74,8 +74,8 @@ int __leave_with___finally_simple() {
 // CHECK-NEXT: br label %[[tryleave:[^ ]*]]
 // CHECK-NOT: store i32 23
 // CHECK: [[tryleave]]
-// CHECK-NEXT: store i8 0, i8* %
-// CHECK-NEXT: br label %
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@__leave_with___finally_simple@@"(i1 zeroext false, i8* %[[fp]])
 
 // __finally block doesn't return, __finally.cont doesn't exist.
 int __leave_with___finally_noreturn() {
@@ -94,8 +94,8 @@ int __leave_with___finally_noreturn() {
 // CHECK-NEXT: br label %[[tryleave:[^ ]*]]
 // CHECK-NOT: store i32 23
 // CHECK: [[tryleave]]
-// CHECK-NEXT: store i8 0, i8* %
-// CHECK-NEXT: br label %
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@__leave_with___finally_noreturn@@"(i1 zeroext false, i8* %[[fp]])
 
 // The "normal" case.
 int __leave_with___finally() {
@@ -110,7 +110,7 @@ int __leave_with___finally() {
   return 1;
 }
 // CHECK-LABEL: define i32 @__leave_with___finally()
-// CHECK: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK: invoke void @g()
 // CHECK-NEXT:       to label %[[cont:.*]] unwind label %{{.*}}
 // For __finally, there needs to be an explicit __try.__leave, because
 // abnormal.termination.slot needs to be set there.
@@ -118,8 +118,8 @@ int __leave_with___finally() {
 // CHECK-NEXT: br label %[[tryleave:[^ ]*]]
 // CHECK-NOT: store i32 23
 // CHECK: [[tryleave]]
-// CHECK-NEXT: store i8 0, i8* %
-// CHECK-NEXT: br label %
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@__leave_with___finally@@"(i1 zeroext false, i8* %[[fp]])
 
 
 //////////////////////////////////////////////////////////////////////////////
@@ -142,45 +142,37 @@ int nested___except___finally() {
   }
   return 1;
 }
-// The order of basic blocks in the below doesn't matter.
 // CHECK-LABEL: define i32 @nested___except___finally()
 
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()
-// CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
-
-// CHECK: [[g1_cont]]
-// CHECK-NEXT: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
+// CHECK-LABEL: invoke void @g()
+// CHECK-NEXT:       to label %[[g1_cont1:.*]] unwind label %[[g1_lpad:.*]]
 
-// CHECK: [[finally]]
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)()
-// CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
-
-// CHECK: [[g2_cont]]
-// CHECK-NEXT: br label %[[tryleave:[^ ]*]]
-// CHECK-NOT: store i32 23
+// CHECK: [[g1_cont1]]
+// CHECK-NEXT: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: invoke void @"\01?fin$0 at 0@nested___except___finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK-NEXT:       to label %[[fin_cont:.*]] unwind label %[[g2_lpad:.*]]
 
-// Unused __finally continuation block
+// CHECK: [[fin_cont]]
 // CHECK: store i32 51, i32* %
-// CHECK-NEXT: br label %[[tryleave]]
-
-// CHECK: [[tryleave]]
 // CHECK-NEXT: br label %[[trycont:[^ ]*]]
 
 // CHECK: [[g1_lpad]]
-// CHECK: store i8 1, i8* %
-// CHECK-NEXT:  br label %[[finally]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: catch i8* null
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: invoke void @"\01?fin$0 at 0@nested___except___finally@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK-NEXT:       to label %[[g1_resume:.*]] unwind label %[[g2_lpad]]
 
 // CHECK: [[g2_lpad]]
-// CHECK-NOT: %[[abnormal]]
-// CHECK: br label %[[except:[^ ]*]]
-
-// CHECK: [[except]]
-// CHECK-NEXT: br label %[[trycont]]
+// CHECK: br label %[[trycont]]
 
 // CHECK: [[trycont]]
 // CHECK-NEXT: ret i32 1
 
+// CHECK-LABEL: define internal void @"\01?fin$0 at 0@nested___except___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: call void @g()
+// CHECK: unreachable
+
 int nested___except___except() {
   int myres = 0;
   __try {
@@ -202,7 +194,7 @@ int nested___except___except() {
 // The order of basic blocks in the below doesn't matter.
 // CHECK-LABEL: define i32 @nested___except___except()
 
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-LABEL: invoke void @g()
 // CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
 
 // CHECK: [[g1_cont]]
@@ -213,7 +205,7 @@ int nested___except___except() {
 // CHECK:  br label %[[except:[^ ]*]]
 
 // CHECK: [[except]]
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() #3
+// CHECK-NEXT: invoke void @g()
 // CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
 
 // CHECK: [[g2_cont]]
@@ -256,7 +248,7 @@ int nested___finally___except() {
 // The order of basic blocks in the below doesn't matter.
 // CHECK-LABEL: define i32 @nested___finally___except()
 
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-LABEL: invoke void @g()
 // CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
 
 // CHECK: [[g1_cont]]
@@ -266,7 +258,7 @@ int nested___finally___except() {
 // CHECK:  br label %[[except:[^ ]*]]
 
 // CHECK: [[except]]
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-NEXT: invoke void @g()
 // CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
 
 // CHECK: [[g2_cont]]
@@ -274,31 +266,25 @@ int nested___finally___except() {
 // CHECK-NOT: 23
 
 // CHECK: [[g2_lpad]]
-// CHECK: store i8 1, i8* %[[abnormal:[^ ]*]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@nested___finally___except@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK-NEXT: br label %[[ehresume:[^ ]*]]
 
 // CHECK: [[trycont]]
 // CHECK: store i32 51, i32* %
 // CHECK-NEXT: br label %[[tryleave]]
 
 // CHECK: [[tryleave]]
-// CHECK-NEXT: store i8 0, i8* %[[abnormal]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
-
-// CHECK: [[finally]]
-// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8, i8* %[[abnormal]]
-// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0
-// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]]
-
-// CHECK: [[finallycont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@nested___finally___except@@"(i1 zeroext false, i8* %[[fp]])
 // CHECK-NEXT: ret i32 1
 
-// CHECK: [[finallyresume]]
-// CHECK-NEXT: br label %[[ehresume:[^ ]*]]
-
 // CHECK: [[ehresume]]
 // CHECK: resume
 
+// CHECK-LABEL: define internal void @"\01?fin$0 at 0@nested___finally___except@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: ret void
+
 int nested___finally___finally() {
   int myres = 0;
   __try {
@@ -320,51 +306,44 @@ int nested___finally___finally() {
 // The order of basic blocks in the below doesn't matter.
 // CHECK-LABEL: define i32 @nested___finally___finally()
 
-// CHECK-LABEL: invoke void bitcast (void (...)* @g to void ()*)()
+// CHECK-LABEL: invoke void @g()
 // CHECK-NEXT:       to label %[[g1_cont:.*]] unwind label %[[g1_lpad:.*]]
 
 // CHECK: [[g1_cont]]
 // CHECK: store i32 16, i32* %[[myres:[^ ]*]],
-// CHECK: store i8 0, i8* %[[abnormal:[^ ]*]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
-
-// CHECK: [[finally]]
-// CHECK-NEXT: invoke void bitcast (void (...)* @g to void ()*)() #3
-// CHECK-NEXT:       to label %[[g2_cont:.*]] unwind label %[[g2_lpad:.*]]
-
-// CHECK: [[g2_cont]]
-// CHECK-NEXT: br label %[[tryleave:[^ ]*]]
-// CHECK-NOT: store i32 23
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: invoke void @"\01?fin$1 at 0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])
+// CHECK-NEXT:       to label %[[finally_cont:.*]] unwind label %[[g2_lpad:.*]]
 
-// There's an unreachable block for the skipped `myres = 51`.
+// CHECK: [[finally_cont]]
 // CHECK: store i32 51, i32* %[[myres]]
-// CHECK-NEXT: br label %[[tryleave]]
-
-// CHECK: [[tryleave]]
-// CHECK-NEXT: store i8 0, i8* %[[abnormal]]
-// CHECK-NEXT: br label %[[outerfinally:[^ ]*]]
-
-// CHECK: [[outerfinally]]
-// CHECK-NEXT: %[[abnormallocal:[^ ]*]] = load i8, i8* %[[abnormal]]
-// CHECK-NEXT: %[[reg:[^ ]*]] = icmp eq i8 %[[abnormallocal]], 0
-// CHECK-NEXT: br i1 %[[reg]], label %[[finallycont:[^ ]*]], label %[[finallyresume:[^ ]*]]
-
-// CHECK: [[finallycont]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@nested___finally___finally@@"(i1 zeroext false, i8* %[[fp]])
 // CHECK-NEXT: ret i32 1
 
 // CHECK: [[g1_lpad]]
-// CHECK: store i8 1, i8* %[[abnormal]]
-// CHECK-NEXT: br label %[[finally:[^ ]*]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: invoke void @"\01?fin$1 at 0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK-NEXT:       to label %[[finally_cont2:.*]] unwind label %[[g2_lpad]]
 
 // CHECK: [[g2_lpad]]
-// CHECK: br label %[[ehcleanup:[^ ]*]]
+// CHECK-NEXT: landingpad
+// CHECK-NEXT: cleanup
+// CHECK: br label %[[ehcleanup:.*]]
+
+// CHECK: [[finally_cont2]]
+// CHECK: br label %[[ehcleanup]]
 
 // CHECK: [[ehcleanup]]
-// CHECK-NEXT: store i8 1, i8* %[[abnormal]]
-// CHECK-NEXT: br label %[[outerfinally]]
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK-NEXT: call void @"\01?fin$0 at 0@nested___finally___finally@@"(i1 zeroext true, i8* %[[fp]])
+// CHECK: resume
 
-// CHECK: [[finallyresume]]
-// CHECK-NEXT: br label %[[ehresume:[^ ]*]]
+// CHECK-LABEL: define internal void @"\01?fin$0 at 0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: ret void
 
-// CHECK: [[ehresume]]
-// CHECK: resume
+// CHECK-LABEL: define internal void @"\01?fin$1 at 0@nested___finally___finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK: call void @g()
+// CHECK: unreachable

Modified: cfe/trunk/test/CodeGen/exceptions-seh.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/exceptions-seh.c?rev=234532&r1=234531&r2=234532&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/exceptions-seh.c (original)
+++ cfe/trunk/test/CodeGen/exceptions-seh.c Thu Apr  9 15:37:24 2015
@@ -118,8 +118,6 @@ int nested_try(void) {
 // CHECK: [[inner_try_cont]]
 // CHECK: br label %[[outer_try_cont]]
 
-// FIXME: This lowering of __finally can't actually work, it will have to
-// change.
 static unsigned g = 0;
 void basic_finally(void) {
   ++g;
@@ -138,24 +136,23 @@ void basic_finally(void) {
 // CHECK:       to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
 //
 // CHECK: [[cont]]
-// CHECK: br label %[[finally:[^ ]*]]
-//
-// CHECK: [[finally]]
-// CHECK: load i32, i32* @g
-// CHECK: add i32 %{{.*}}, -1
-// CHECK: store i32 %{{.*}}, i32* @g
-// CHECK: icmp eq
-// CHECK: br i1 %{{.*}}, label
-//
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@basic_finally@@"(i1 zeroext false, i8* %[[fp]])
 // CHECK: ret void
 //
 // CHECK: [[lpad]]
 // CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*)
 // CHECK-NEXT: cleanup
-// CHECK: br label %[[finally]]
-//
+// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
+// CHECK: call void @"\01?fin$0 at 0@basic_finally@@"(i1 zeroext true, i8* %[[fp]])
 // CHECK: resume
 
+// CHECK: define internal void @"\01?fin$0 at 0@basic_finally@@"(i1 zeroext %abnormal_termination, i8* %frame_pointer)
+// CHECK:   load i32, i32* @g, align 4
+// CHECK:   add i32 %{{.*}}, -1
+// CHECK:   store i32 %{{.*}}, i32* @g, align 4
+// CHECK:   ret void
+
 int returns_int(void);
 int except_return(void) {
   __try {





More information about the cfe-commits mailing list