r234613 - [SEH] Re-land r234532, but use internal linkage for all SEH helpers

Nico Weber thakis at chromium.org
Mon Apr 13 13:08:28 PDT 2015


I re-reverted this (and follow-ups 234614, 234616, 234618) in 234789 as it
caused PR23216.

On Fri, Apr 10, 2015 at 10:34 AM, Reid Kleckner <reid at kleckner.net> wrote:

> Author: rnk
> Date: Fri Apr 10 12:34:52 2015
> New Revision: 234613
>
> URL: http://llvm.org/viewvc/llvm-project?rev=234613&view=rev
> Log:
> [SEH] Re-land r234532, but use internal linkage for all SEH helpers
>
> Even though these symbols are in a comdat group, the Microsoft linker
> really wants them to have internal linkage.
>
> I'm planning to tweak the mangling in a follow-up change. This is a
> straight revert with a 1-line fix.
>
> 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=234613&r1=234612&r2=234613&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Mangle.h (original)
> +++ cfe/trunk/include/clang/AST/Mangle.h Fri Apr 10 12:34:52 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=234613&r1=234612&r2=234613&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/ItaniumMangle.cpp (original)
> +++ cfe/trunk/lib/AST/ItaniumMangle.cpp Fri Apr 10 12:34:52 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=234613&r1=234612&r2=234613&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/AST/MicrosoftMangle.cpp (original)
> +++ cfe/trunk/lib/AST/MicrosoftMangle.cpp Fri Apr 10 12:34:52 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=234613&r1=234612&r2=234613&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGException.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGException.cpp Fri Apr 10 12:34:52 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,47 +1437,24 @@ 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());
> +  llvm::Function *Fn = llvm::Function::Create(
> +      FnTy, llvm::GlobalValue::InternalLinkage, Name.str(),
> &CGM.getModule());
>    // The filter is either in the same comdat as the function, or it's
> internal.
>    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=234613&r1=234612&r2=234613&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGStmt.cpp Fri Apr 10 12:34:52 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=234613&r1=234612&r2=234613&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Fri Apr 10 12:34:52 2015
> @@ -41,7 +41,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=234613&r1=234612&r2=234613&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Fri Apr 10 12:34:52 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();
> @@ -2003,12 +1992,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=234613&r1=234612&r2=234613&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/exceptions-seh-finally.c (original)
> +++ cfe/trunk/test/CodeGen/exceptions-seh-finally.c Fri Apr 10 12:34:52
> 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=234613&r1=234612&r2=234613&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/exceptions-seh-leave.c (original)
> +++ cfe/trunk/test/CodeGen/exceptions-seh-leave.c Fri Apr 10 12:34:52 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=234613&r1=234612&r2=234613&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/exceptions-seh.c (original)
> +++ cfe/trunk/test/CodeGen/exceptions-seh.c Fri Apr 10 12:34:52 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 {
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150413/b7f83d8a/attachment.html>


More information about the cfe-commits mailing list