r236052 - [SEH] Add 32-bit lowering code for __try

Nico Weber thakis at chromium.org
Tue Apr 28 20:12:33 PDT 2015


It looks like this causes linker errors when building 32-bit Windows apps (
crbug.com/482292). I reverted this in r236082.

On Tue, Apr 28, 2015 at 3:19 PM, Reid Kleckner <reid at kleckner.net> wrote:

> Author: rnk
> Date: Tue Apr 28 17:19:32 2015
> New Revision: 236052
>
> URL: http://llvm.org/viewvc/llvm-project?rev=236052&view=rev
> Log:
> [SEH] Add 32-bit lowering code for __try
>
> This is just the clang-side of 32-bit SEH. LLVM still needs work, and it
> will determinstically fail to compile until it's feature complete.
>
> On x86, all outlined handlers have no parameters, but they do implicitly
> take the EBP value passed in and use it to address locals of the parent
> frame. We model this with llvm.frameaddress(1).
>
> This works (mostly), but __finally block inlining can break it. For now,
> we apply the 'noinline' attribute. If we really want to inline __finally
> blocks on 32-bit x86, we should teach the inliner how to untangle
> frameescape and framerecover.
>
> Promote the error diagnostic from codegen to sema. It now rejects SEH on
> non-Windows platforms. LLVM doesn't implement SEH on non-x86 Windows
> platforms, but there's nothing preventing it.
>
> Modified:
>     cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>     cfe/trunk/include/clang/Basic/TargetInfo.h
>     cfe/trunk/lib/CodeGen/CGException.cpp
>     cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
>     cfe/trunk/lib/CodeGen/CodeGenFunction.h
>     cfe/trunk/lib/Sema/SemaStmt.cpp
>     cfe/trunk/test/CodeGen/exceptions-seh-finally.c
>     cfe/trunk/test/CodeGen/exceptions-seh.c
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=236052&r1=236051&r2=236052&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Apr 28
> 17:19:32 2015
> @@ -5535,6 +5535,8 @@ def err_seh_try_outside_functions : Erro
>    "cannot use SEH '__try' in blocks, captured regions, or Obj-C method
> decls">;
>  def err_mixing_cxx_try_seh_try : Error<
>    "cannot use C++ 'try' in the same function as SEH '__try'">;
> +def err_seh_try_unsupported : Error<
> +  "SEH '__try' is not supported on this target">;
>  def note_conflicting_try_here : Note<
>    "conflicting %0 here">;
>  def warn_jump_out_of_seh_finally : Warning<
>
> Modified: cfe/trunk/include/clang/Basic/TargetInfo.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TargetInfo.h?rev=236052&r1=236051&r2=236052&view=diff
>
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/TargetInfo.h (original)
> +++ cfe/trunk/include/clang/Basic/TargetInfo.h Tue Apr 28 17:19:32 2015
> @@ -807,6 +807,11 @@ public:
>      return TLSSupported;
>    }
>
> +  /// \brief Whether the target supports SEH __try.
> +  bool isSEHTrySupported() const {
> +    return getTriple().isOSWindows();
> +  }
> +
>    /// \brief Return true if {|} are normal characters in the asm string.
>    ///
>    /// If this returns false (the default), then {abc|xyz} is syntax
>
> Modified: cfe/trunk/lib/CodeGen/CGException.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGException.cpp?rev=236052&r1=236051&r2=236052&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGException.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGException.cpp Tue Apr 28 17:19:32 2015
> @@ -20,6 +20,7 @@
>  #include "clang/AST/StmtCXX.h"
>  #include "clang/AST/StmtObjC.h"
>  #include "clang/AST/StmtVisitor.h"
> +#include "clang/Basic/TargetBuiltins.h"
>  #include "llvm/IR/CallSite.h"
>  #include "llvm/IR/Intrinsics.h"
>  #include "llvm/IR/IntrinsicInst.h"
> @@ -1271,14 +1272,6 @@ llvm::BasicBlock *CodeGenFunction::getEH
>  }
>
>  void CodeGenFunction::EmitSEHTryStmt(const SEHTryStmt &S) {
> -  // FIXME: Implement SEH on other architectures.
> -  const llvm::Triple &T = CGM.getTarget().getTriple();
> -  if (T.getArch() != llvm::Triple::x86_64 ||
> -      !T.isKnownWindowsMSVCEnvironment()) {
> -    ErrorUnsupported(&S, "__try statement");
> -    return;
> -  }
> -
>    EnterSEHTryStmt(S);
>    {
>      JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave");
> @@ -1303,25 +1296,39 @@ struct PerformSEHFinally : EHScopeStack:
>
>    void Emit(CodeGenFunction &CGF, Flags F) override {
>      ASTContext &Context = CGF.getContext();
> -    QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy};
> -    FunctionProtoType::ExtProtoInfo EPI;
> -    const auto *FTP = cast<FunctionType>(
> -        Context.getFunctionType(Context.VoidTy, ArgTys, EPI));
> +    CodeGenModule &CGM = CGF.CGM;
>
> +    // In 64-bit, we call the child function with arguments. In 32-bit,
> we store
> +    // zero in the parent frame and use framerecover to check the value.
> +    const CGFunctionInfo *FnInfo;
>      CallArgList Args;
> -    llvm::Value *IsForEH =
> -        llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]),
> F.isForEHCleanup());
> -    Args.add(RValue::get(IsForEH), ArgTys[0]);
> +    if (CGF.getTarget().getTriple().getArch() == llvm::Triple::x86_64) {
> +      // Compute the two argument values.
> +      QualType ArgTys[2] = {Context.UnsignedCharTy, Context.VoidPtrTy};
> +      llvm::Value *FrameAddr =
> CGM.getIntrinsic(llvm::Intrinsic::frameaddress);
> +      llvm::Value *FP =
> +          CGF.Builder.CreateCall(FrameAddr, CGF.Builder.getInt32(0));
> +      llvm::Value *IsForEH =
> +          llvm::ConstantInt::get(CGF.ConvertType(ArgTys[0]),
> F.isForEHCleanup());
> +      Args.add(RValue::get(IsForEH), ArgTys[0]);
> +      Args.add(RValue::get(FP), ArgTys[1]);
> +
> +      // Arrange a two-arg function info and type.
> +      FunctionProtoType::ExtProtoInfo EPI;
> +      const auto *FPT = cast<FunctionProtoType>(
> +          Context.getFunctionType(Context.VoidTy, ArgTys, EPI));
> +      FnInfo = &CGM.getTypes().arrangeFreeFunctionCall(Args, FPT,
> +
>  /*chainCall=*/false);
> +    } else {
> +      // Emit the zero store if this is normal control flow. There are no
> +      // explicit arguments.
> +      if (F.isForNormalCleanup() && CGF.ChildAbnormalTerminationSlot)
> +        CGF.Builder.CreateStore(CGF.Builder.getInt32(0),
> +                                CGF.ChildAbnormalTerminationSlot);
> +      FnInfo = &CGM.getTypes().arrangeNullaryFunction();
> +    }
>
> -    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);
> +    CGF.EmitCall(*FnInfo, OutlinedFinally, ReturnValueSlot(), Args);
>    }
>  };
>  }
> @@ -1332,6 +1339,7 @@ struct CaptureFinder : ConstStmtVisitor<
>    CodeGenFunction &ParentCGF;
>    const VarDecl *ParentThis;
>    SmallVector<const VarDecl *, 4> Captures;
> +  llvm::Value *AbnormalTermination = nullptr;
>    CaptureFinder(CodeGenFunction &ParentCGF, const VarDecl *ParentThis)
>        : ParentCGF(ParentCGF), ParentThis(ParentThis) {}
>
> @@ -1358,25 +1366,93 @@ struct CaptureFinder : ConstStmtVisitor<
>    void VisitCXXThisExpr(const CXXThisExpr *E) {
>      Captures.push_back(ParentThis);
>    }
> +
> +  void VisitCallExpr(const CallExpr *E) {
> +    // We only need to add parent frame allocations for these builtins in
> x86.
> +    if (ParentCGF.getTarget().getTriple().getArch() != llvm::Triple::x86)
> +      return;
> +
> +    unsigned ID = E->getBuiltinCallee();
> +    switch (ID) {
> +    case Builtin::BI__abnormal_termination:
> +    case Builtin::BI_abnormal_termination:
> +      // This is the simple case where we are the outermost finally. All
> we
> +      // have to do here is make sure we escape this and recover it in the
> +      // outlined handler.
> +      if (!AbnormalTermination)
> +        AbnormalTermination = ParentCGF.CreateMemTemp(
> +            ParentCGF.getContext().IntTy, "abnormal_termination");
> +      break;
> +    }
> +  }
>  };
>  }
>
> +llvm::Value *CodeGenFunction::recoverAddrOfEscapedLocal(
> +    CodeGenFunction &ParentCGF, llvm::Value *ParentVar, llvm::Value
> *ParentFP) {
> +  llvm::CallInst *RecoverCall = nullptr;
> +  CGBuilderTy Builder(AllocaInsertPt);
> +  if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(ParentVar)) {
> +    // Mark the variable escaped if nobody else referenced it and compute
> the
> +    // frameescape index.
> +    auto InsertPair = ParentCGF.EscapedLocals.insert(
> +        std::make_pair(ParentAlloca, ParentCGF.EscapedLocals.size()));
> +    int FrameEscapeIdx = InsertPair.first->second;
> +    // call i8* @llvm.framerecover(i8* bitcast(@parentFn), i8* %fp, i32 N)
> +    llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration(
> +        &CGM.getModule(), llvm::Intrinsic::framerecover);
> +    llvm::Constant *ParentI8Fn =
> +        llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy);
> +    RecoverCall =
> +        Builder.CreateCall3(FrameRecoverFn, ParentI8Fn, ParentFP,
> +                            llvm::ConstantInt::get(Int32Ty,
> FrameEscapeIdx));
> +
> +  } else {
> +    // If the parent didn't have an alloca, we're doing some nested
> outlining.
> +    // Just clone the existing framerecover call, but tweak the FP
> argument to
> +    // use our FP value. All other arguments are constants.
> +    auto *ParentRecover =
> +        cast<llvm::IntrinsicInst>(ParentVar->stripPointerCasts());
> +    assert(ParentRecover->getIntrinsicID() ==
> llvm::Intrinsic::framerecover &&
> +           "expected alloca or framerecover in parent LocalDeclMap");
> +    RecoverCall = cast<llvm::CallInst>(ParentRecover->clone());
> +    RecoverCall->setArgOperand(1, ParentFP);
> +    RecoverCall->insertBefore(AllocaInsertPt);
> +  }
> +
> +  // Bitcast the variable, rename it, and insert it in the local decl map.
> +  llvm::Value *ChildVar =
> +      Builder.CreateBitCast(RecoverCall, ParentVar->getType());
> +  ChildVar->setName(ParentVar->getName());
> +  return ChildVar;
> +}
> +
>  void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF,
> -                                         const Stmt *OutlinedStmt,
> -                                         llvm::Value *ParentFP) {
> +                                         const Stmt *OutlinedStmt) {
>    // Find all captures in the Stmt.
>    CaptureFinder Finder(ParentCGF, ParentCGF.CXXABIThisDecl);
>    Finder.Visit(OutlinedStmt);
>
>    // Typically there are no captures and we can exit early.
> -  if (Finder.Captures.empty())
> +  if (Finder.Captures.empty() && !Finder.AbnormalTermination)
>      return;
>
> -  // Prepare the first two arguments to llvm.framerecover.
> -  llvm::Function *FrameRecoverFn = llvm::Intrinsic::getDeclaration(
> -      &CGM.getModule(), llvm::Intrinsic::framerecover);
> -  llvm::Constant *ParentI8Fn =
> -      llvm::ConstantExpr::getBitCast(ParentCGF.CurFn, Int8PtrTy);
> +  // The parent FP is passed in as EBP on x86 and the second argument on
> x64.
> +  llvm::Value *ParentFP;
> +  if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86_64) {
> +    auto AI = CurFn->arg_begin();
> +    ++AI;
> +    ParentFP = AI;
> +  } else {
> +    CGBuilderTy Builder(AllocaInsertPt);
> +    ParentFP = Builder.CreateCall(
> +        CGM.getIntrinsic(llvm::Intrinsic::frameaddress),
> Builder.getInt32(1));
> +
> +    // Inlining will break llvm.frameaddress(1), so disable it.
> +    // FIXME: We could teach the inliner about the special meaning of
> +    // frameaddress, framerecover, and frameescape to remove this
> limitation.
> +    CurFn->addFnAttr(llvm::Attribute::NoInline);
> +  }
>
>    // Create llvm.framerecover calls for all captures.
>    for (const VarDecl *VD : Finder.Captures) {
> @@ -1399,39 +1475,16 @@ void CodeGenFunction::EmitCapturedLocals
>        continue;
>      llvm::Value *ParentVar = I->second;
>
> -    llvm::CallInst *RecoverCall = nullptr;
> -    CGBuilderTy Builder(AllocaInsertPt);
> -    if (auto *ParentAlloca = dyn_cast<llvm::AllocaInst>(ParentVar)) {
> -      // Mark the variable escaped if nobody else referenced it and
> compute the
> -      // frameescape index.
> -      auto InsertPair =
> -          ParentCGF.EscapedLocals.insert(std::make_pair(ParentAlloca,
> -1));
> -      if (InsertPair.second)
> -        InsertPair.first->second = ParentCGF.EscapedLocals.size() - 1;
> -      int FrameEscapeIdx = InsertPair.first->second;
> -      // call i8* @llvm.framerecover(i8* bitcast(@parentFn), i8* %fp, i32
> N)
> -      RecoverCall =
> -          Builder.CreateCall3(FrameRecoverFn, ParentI8Fn, ParentFP,
> -                              llvm::ConstantInt::get(Int32Ty,
> FrameEscapeIdx));
> +    LocalDeclMap[VD] =
> +        recoverAddrOfEscapedLocal(ParentCGF, ParentVar, ParentFP);
> +  }
>
> -    } else {
> -      // If the parent didn't have an alloca, we're doing some nested
> outlining.
> -      // Just clone the existing framerecover call, but tweak the FP
> argument to
> -      // use our FP value. All other arguments are constants.
> -      auto *ParentRecover =
> -          cast<llvm::IntrinsicInst>(ParentVar->stripPointerCasts());
> -      assert(ParentRecover->getIntrinsicID() ==
> llvm::Intrinsic::framerecover &&
> -             "expected alloca or framerecover in parent LocalDeclMap");
> -      RecoverCall = cast<llvm::CallInst>(ParentRecover->clone());
> -      RecoverCall->setArgOperand(1, ParentFP);
> -      RecoverCall->insertBefore(AllocaInsertPt);
> -    }
> -
> -    // Bitcast the variable, rename it, and insert it in the local decl
> map.
> -    llvm::Value *ChildVar =
> -        Builder.CreateBitCast(RecoverCall, ParentVar->getType());
> -    ChildVar->setName(ParentVar->getName());
> -    LocalDeclMap[VD] = ChildVar;
> +  // AbnormalTermination is just another capture, but it has no Decl.
> +  if (Finder.AbnormalTermination) {
> +    AbnormalTerminationSlot = recoverAddrOfEscapedLocal(
> +        ParentCGF, Finder.AbnormalTermination, ParentFP);
> +    // Save the slot on the parent so it can store 1 and 0 to it.
> +    ParentCGF.ChildAbnormalTerminationSlot = Finder.AbnormalTermination;
>    }
>  }
>
> @@ -1466,10 +1519,7 @@ void CodeGenFunction::startOutlinedSEHHe
>                  OutlinedStmt->getLocStart(), OutlinedStmt->getLocStart());
>
>    CGM.SetLLVMFunctionAttributes(nullptr, FnInfo, CurFn);
> -
> -  auto AI = Fn->arg_begin();
> -  ++AI;
> -  EmitCapturedLocals(ParentCGF, OutlinedStmt, &*AI);
> +  EmitCapturedLocals(ParentCGF, OutlinedStmt);
>  }
>
>  /// Create a stub filter function that will ultimately hold the code of
> the
> @@ -1481,14 +1531,16 @@ CodeGenFunction::GenerateSEHFilterFuncti
>    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));
> +  if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86_64) {
> +    SEHPointersDecl = ImplicitParamDecl::Create(
> +        getContext(), nullptr, StartLoc,
> +        &getContext().Idents.get("exception_pointers"),
> getContext().VoidPtrTy);
> +    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;
> @@ -1529,13 +1581,15 @@ CodeGenFunction::GenerateSEHFinallyFunct
>    SourceLocation StartLoc = FinallyBlock->getLocStart();
>
>    FunctionArgList Args;
> -  Args.push_back(ImplicitParamDecl::Create(
> -      getContext(), nullptr, StartLoc,
> -      &getContext().Idents.get("abnormal_termination"),
> -      getContext().UnsignedCharTy));
> -  Args.push_back(ImplicitParamDecl::Create(
> -      getContext(), nullptr, StartLoc,
> -      &getContext().Idents.get("frame_pointer"), getContext().VoidPtrTy));
> +  if (CGM.getTarget().getTriple().getArch() == llvm::Triple::x86_64) {
> +    Args.push_back(ImplicitParamDecl::Create(
> +        getContext(), nullptr, StartLoc,
> +        &getContext().Idents.get("abnormal_termination"),
> +        getContext().UnsignedCharTy));
> +    Args.push_back(ImplicitParamDecl::Create(
> +        getContext(), nullptr, StartLoc,
> +        &getContext().Idents.get("frame_pointer"),
> getContext().VoidPtrTy));
> +  }
>
>    // Get the mangled function name.
>    SmallString<128> Name;
> @@ -1567,7 +1621,7 @@ void CodeGenFunction::EmitSEHExceptionCo
>    // };
>    // void *exn.slot =
>    //     (void
> *)(uintptr_t)exception_pointers->ExceptionRecord->ExceptionCode;
> -  llvm::Value *Ptrs =
> Builder.CreateLoad(GetAddrOfLocalVar(SEHPointersDecl));
> +  llvm::Value *Ptrs = EmitSEHExceptionInfo();
>    llvm::Type *RecordTy = CGM.Int32Ty->getPointerTo();
>    llvm::Type *PtrsTy = llvm::StructType::get(RecordTy, CGM.VoidPtrTy,
> nullptr);
>    Ptrs = Builder.CreateBitCast(Ptrs, PtrsTy->getPointerTo());
> @@ -1582,6 +1636,9 @@ void CodeGenFunction::EmitSEHExceptionCo
>  }
>
>  llvm::Value *CodeGenFunction::EmitSEHExceptionInfo() {
> +  if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86_64)
> +    return Builder.CreateCall(
> +        CGM.getIntrinsic(llvm::Intrinsic::eh_exceptioninfo));
>    // Sema should diagnose calling this builtin outside of a filter
> context, but
>    // don't crash if we screw up.
>    if (!SEHPointersDecl)
> @@ -1599,6 +1656,8 @@ llvm::Value *CodeGenFunction::EmitSEHExc
>  }
>
>  llvm::Value *CodeGenFunction::EmitSEHAbnormalTermination() {
> +  if (CGM.getTarget().getTriple().getArch() != llvm::Triple::x86_64)
> +    return Builder.CreateLoad(AbnormalTerminationSlot);
>    // Abnormal termination is just the first parameter to the outlined
> finally
>    // helper.
>    auto AI = CurFn->arg_begin();
> @@ -1608,9 +1667,15 @@ llvm::Value *CodeGenFunction::EmitSEHAbn
>  void CodeGenFunction::EnterSEHTryStmt(const SEHTryStmt &S) {
>    CodeGenFunction HelperCGF(CGM, /*suppressNewContext=*/true);
>    if (const SEHFinallyStmt *Finally = S.getFinallyHandler()) {
> -    // Push a cleanup for __finally blocks.
> +    // Outline the finally block.
>      llvm::Function *FinallyFunc =
>          HelperCGF.GenerateSEHFinallyFunction(*this, *Finally);
> +
> +    // Store 1 to indicate abnormal termination if an exception is thrown.
> +    if (ChildAbnormalTerminationSlot)
> +      Builder.CreateStore(Builder.getInt32(1),
> ChildAbnormalTerminationSlot);
> +
> +    // Push a cleanup for __finally blocks.
>      EHStack.pushCleanup<PerformSEHFinally>(NormalAndEHCleanup,
> FinallyFunc);
>      return;
>    }
> @@ -1642,6 +1707,7 @@ void CodeGenFunction::ExitSEHTryStmt(con
>    // Just pop the cleanup if it's a __finally block.
>    if (S.getFinallyHandler()) {
>      PopCleanupBlock();
> +    ChildAbnormalTerminationSlot = nullptr;
>      return;
>    }
>
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=236052&r1=236051&r2=236052&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Tue Apr 28 17:19:32 2015
> @@ -45,12 +45,13 @@ CodeGenFunction::CodeGenFunction(CodeGen
>        LambdaThisCaptureField(nullptr), NormalCleanupDest(nullptr),
>        NextCleanupDestIndex(1), FirstBlockInfo(nullptr),
> EHResumeBlock(nullptr),
>        ExceptionSlot(nullptr), EHSelectorSlot(nullptr),
> -      AbnormalTerminationSlot(nullptr), SEHPointersDecl(nullptr),
> -      DebugInfo(CGM.getModuleDebugInfo()), DisableDebugInfo(false),
> -      DidCallStackSave(false), IndirectBranch(nullptr), PGO(cgm),
> -      SwitchInsn(nullptr), SwitchWeights(nullptr),
> CaseRangeBlock(nullptr),
> -      UnreachableBlock(nullptr), NumReturnExprs(0),
> NumSimpleReturnExprs(0),
> -      CXXABIThisDecl(nullptr), CXXABIThisValue(nullptr),
> CXXThisValue(nullptr),
> +      ChildAbnormalTerminationSlot(nullptr),
> AbnormalTerminationSlot(nullptr),
> +      SEHPointersDecl(nullptr), DebugInfo(CGM.getModuleDebugInfo()),
> +      DisableDebugInfo(false), DidCallStackSave(false),
> IndirectBranch(nullptr),
> +      PGO(cgm), SwitchInsn(nullptr), SwitchWeights(nullptr),
> +      CaseRangeBlock(nullptr), UnreachableBlock(nullptr),
> NumReturnExprs(0),
> +      NumSimpleReturnExprs(0), CXXABIThisDecl(nullptr),
> +      CXXABIThisValue(nullptr), CXXThisValue(nullptr),
>        CXXDefaultInitExprThis(nullptr),
> CXXStructorImplicitParamDecl(nullptr),
>        CXXStructorImplicitParamValue(nullptr),
> OutermostConditional(nullptr),
>        CurLexicalScope(nullptr), TerminateLandingPad(nullptr),
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=236052&r1=236051&r2=236052&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Apr 28 17:19:32 2015
> @@ -310,7 +310,13 @@ public:
>    /// write the current selector value into this alloca.
>    llvm::AllocaInst *EHSelectorSlot;
>
> -  llvm::AllocaInst *AbnormalTerminationSlot;
> +  /// Entering and leaving an SEH __try / __finally scope causes stores
> to this
> +  /// slot.
> +  llvm::Value *ChildAbnormalTerminationSlot;
> +
> +  /// The SEH __abnormal_termination() intrinsic lowers down to loads
> from this
> +  /// slot from a parent function.
> +  llvm::Value *AbnormalTerminationSlot;
>
>    /// The implicit parameter to SEH filter functions of type
>    /// 'EXCEPTION_POINTERS*'.
> @@ -2033,8 +2039,16 @@ public:
>    /// Scan the outlined statement for captures from the parent function.
> For
>    /// each capture, mark the capture as escaped and emit a call to
>    /// llvm.framerecover. Insert the framerecover result into the
> LocalDeclMap.
> -  void EmitCapturedLocals(CodeGenFunction &ParentCGF, const Stmt
> *OutlinedStmt,
> -                          llvm::Value *ParentFP);
> +  void EmitCapturedLocals(CodeGenFunction &ParentCGF, const Stmt
> *OutlinedStmt);
> +
> +  /// Recovers the address of a local in a parent function. ParentVar is
> the
> +  /// address of the variable used in the immediate parent function. It
> can
> +  /// either be an alloca or a call to llvm.framerecover if there are
> nested
> +  /// outlined functions. ParentFP is the frame pointer of the outermost
> parent
> +  /// frame.
> +  llvm::Value *recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF,
> +                                         llvm::Value *ParentVar,
> +                                         llvm::Value *ParentFP);
>
>    void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
>                             ArrayRef<const Attr *> Attrs = None);
>
> Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=236052&r1=236051&r2=236052&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaStmt.cpp Tue Apr 28 17:19:32 2015
> @@ -25,6 +25,7 @@
>  #include "clang/AST/StmtObjC.h"
>  #include "clang/AST/TypeLoc.h"
>  #include "clang/AST/TypeOrdering.h"
> +#include "clang/Basic/TargetInfo.h"
>  #include "clang/Lex/Preprocessor.h"
>  #include "clang/Sema/Initialization.h"
>  #include "clang/Sema/Lookup.h"
> @@ -3637,6 +3638,10 @@ StmtResult Sema::ActOnSEHTryBlock(bool I
>    else
>      Diag(TryLoc, diag::err_seh_try_outside_functions);
>
> +  // Reject __try on unsupported targets.
> +  if (!Context.getTargetInfo().isSEHTrySupported())
> +    Diag(TryLoc, diag::err_seh_try_unsupported);
> +
>    return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler);
>  }
>
>
> 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=236052&r1=236051&r2=236052&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/exceptions-seh-finally.c (original)
> +++ cfe/trunk/test/CodeGen/exceptions-seh-finally.c Tue Apr 28 17:19:32
> 2015
> @@ -1,4 +1,7 @@
> -// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm
> -o - | FileCheck %s
> +// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm
> -o - \
> +// RUN:         | FileCheck %s --check-prefix=CHECK --check-prefix=X64
> +// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o
> - \
> +// RUN:         | FileCheck %s --check-prefix=CHECK --check-prefix=X86
>
>  void abort(void) __attribute__((noreturn));
>  void might_crash(void);
> @@ -17,18 +20,20 @@ void basic_finally(void) {
>  // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
>  //
>  // CHECK: [[invoke_cont]]
> -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> -// CHECK: call void @"\01?fin$0 at 0@basic_finally@@"(i8 0, i8* %[[fp]])
> +// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> +// X64: call void @"\01?fin$0 at 0@basic_finally@@"(i8 0, i8* %[[fp]])
> +// X86: call void @"\01?fin$0 at 0@basic_finally@@"()
>  // CHECK-NEXT: ret void
>  //
>  // CHECK: [[lpad]]
>  // CHECK-NEXT: landingpad
>  // CHECK-NEXT: cleanup
> -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> -// CHECK: call void @"\01?fin$0 at 0@basic_finally@@"(i8 1, i8* %[[fp]])
> +// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> +// X64: call void @"\01?fin$0 at 0@basic_finally@@"(i8 1, i8* %[[fp]])
> +// X86: call void @"\01?fin$0 at 0@basic_finally@@"()
>  // CHECK: resume { i8*, i32 }
>
> -// CHECK: define internal void @"\01?fin$0 at 0@basic_finally@@"(i8
> %abnormal_termination, i8* %frame_pointer)
> +// CHECK: define internal void @"\01?fin$0 at 0@basic_finally@@"({{.*}})
>  // CHECK: call void @cleanup()
>
>  // Mostly check that we don't double emit 'r' which would crash.
> @@ -57,11 +62,12 @@ l:
>  // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
>  //
>  // CHECK: [[invoke_cont]]
> -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> -// CHECK: call void @"\01?fin$0 at 0@label_in_finally@@"(i8 0, i8* %[[fp]])
> +// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> +// X64: call void @"\01?fin$0 at 0@label_in_finally@@"(i8 0, i8* %[[fp]])
> +// X86: call void @"\01?fin$0 at 0@label_in_finally@@"()
>  // CHECK: ret void
>
> -// CHECK: define internal void @"\01?fin$0 at 0@label_in_finally@@"(i8
> %abnormal_termination, i8* %frame_pointer)
> +// CHECK: define internal void @"\01?fin$0 at 0@label_in_finally@@"({{.*}})
>  // CHECK: br label %[[l:[^ ]*]]
>  //
>  // CHECK: [[l]]
> @@ -80,23 +86,33 @@ void use_abnormal_termination(void) {
>  }
>
>  // CHECK-LABEL: define void @use_abnormal_termination()
> +// X86: call void (...) @llvm.frameescape(i32* %[[abnormal_termination:[^
> ),]*]])
> +// X86: store i32 1, i32* %[[abnormal_termination]]
>  // CHECK: invoke void @might_crash()
>  // CHECK:     to label %[[invoke_cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
>  //
>  // CHECK: [[invoke_cont]]
> -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> -// CHECK: call void @"\01?fin$0 at 0@use_abnormal_termination@@"(i8 0, i8*
> %[[fp]])
> +// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> +// X64: call void @"\01?fin$0 at 0@use_abnormal_termination@@"(i8 0, i8*
> %[[fp]])
> +// X86: store i32 0, i32* %[[abnormal_termination]]
> +// X86: call void @"\01?fin$0 at 0@use_abnormal_termination@@"()
>  // CHECK: ret void
>  //
>  // CHECK: [[lpad]]
>  // CHECK-NEXT: landingpad
>  // CHECK-NEXT: cleanup
> -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> -// CHECK: call void @"\01?fin$0 at 0@use_abnormal_termination@@"(i8 1, i8*
> %[[fp]])
> +// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> +// X64: call void @"\01?fin$0 at 0@use_abnormal_termination@@"(i8 1, i8*
> %[[fp]])
> +// X86: call void @"\01?fin$0 at 0@use_abnormal_termination@@"()
>  // CHECK: resume { i8*, i32 }
>
> -// CHECK: define internal void @"\01?fin$0 at 0@use_abnormal_termination@@"(i8
> %abnormal_termination, i8* %frame_pointer)
> -// CHECK: %[[abnormal_zext:[^ ]*]] = zext i8 %abnormal_termination to i32
> +// X64: define internal void @"\01?fin$0 at 0@use_abnormal_termination@@"(i8
> %[[abnormal:abnormal_termination]], i8* %frame_pointer)
> +// X64: %[[abnormal_zext:[^ ]*]] = zext i8 %[[abnormal]] to i32
> +// X86: define internal void @"\01?fin$0 at 0@use_abnormal_termination@@"()
> +// X86: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 1)
> +// X86: %[[abnormal_i8:[^ ]*]] = call i8* @llvm.framerecover(i8* bitcast
> (void ()* @use_abnormal_termination to i8*), i8* %[[fp]], i32 0)
> +// X86: %[[abnormal:[^ ]*]] = bitcast i8* %[[abnormal_i8]] to i32*
> +// X86: %[[abnormal_zext:[^ ]*]] = load i32, i32* %[[abnormal]]
>  // CHECK: store i32 %[[abnormal_zext]], i32* @crashed
>  // CHECK-NEXT: ret void
>
> @@ -109,11 +125,10 @@ void noreturn_noop_finally() {
>  }
>
>  // CHECK-LABEL: define void @noreturn_noop_finally()
> -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> -// CHECK: call void @"\01?fin$0 at 0@noreturn_noop_finally@@"(i8 0, i8*
> %[[fp]])
> +// CHECK: call void @"\01?fin$0 at 0@noreturn_noop_finally@@"({{.*}})
>  // CHECK: ret void
>
> -// CHECK: define internal void @"\01?fin$0 at 0@noreturn_noop_finally@@"(i8
> %abnormal_termination, i8* %frame_pointer)
> +// CHECK: define internal void @"\01?fin$0 at 0@noreturn_noop_finally@
> @"({{.*}})
>  // CHECK: call void @abort()
>  // CHECK: unreachable
>
> @@ -130,18 +145,16 @@ void noreturn_finally() {
>  // CHECK:     to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
>  //
>  // CHECK: [[cont]]
> -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> -// CHECK: call void @"\01?fin$0 at 0@noreturn_finally@@"(i8 0, i8* %[[fp]])
> +// CHECK: call void @"\01?fin$0 at 0@noreturn_finally@@"({{.*}})
>  // CHECK: ret void
>  //
>  // CHECK: [[lpad]]
>  // CHECK: landingpad
>  // CHECK-NEXT: cleanup
> -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> -// CHECK: call void @"\01?fin$0 at 0@noreturn_finally@@"(i8 1, i8* %[[fp]])
> +// CHECK: call void @"\01?fin$0 at 0@noreturn_finally@@"({{.*}})
>  // CHECK: resume { i8*, i32 }
>
> -// CHECK: define internal void @"\01?fin$0 at 0@noreturn_finally@@"(i8
> %abnormal_termination, i8* %frame_pointer)
> +// CHECK: define internal void @"\01?fin$0 at 0@noreturn_finally@@"({{.*}})
>  // CHECK: call void @abort()
>  // CHECK: unreachable
>
> @@ -152,11 +165,10 @@ int finally_with_return() {
>    }
>  }
>  // CHECK-LABEL: define i32 @finally_with_return()
> -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> -// CHECK-NEXT: call void @"\01?fin$0 at 0@finally_with_return@@"(i8 0, i8*
> %[[fp]])
> +// CHECK: call void @"\01?fin$0 at 0@finally_with_return@@"({{.*}})
>  // CHECK-NEXT: ret i32 42
>
> -// CHECK: define internal void @"\01?fin$0 at 0@finally_with_return@@"(i8
> %abnormal_termination, i8* %frame_pointer)
> +// CHECK: define internal void @"\01?fin$0 at 0@finally_with_return@
> @"({{.*}})
>  // CHECK-NOT: br i1
>  // CHECK-NOT: br label
>  // CHECK: ret void
> @@ -174,25 +186,22 @@ int nested___finally___finally() {
>  }
>
>  // CHECK-LABEL: define i32 @nested___finally___finally
> -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> -// CHECK: invoke void @"\01?fin$1 at 0@nested___finally___finally@@"(i8 0,
> i8* %[[fp]])
> +// CHECK: invoke void @"\01?fin$1 at 0@nested___finally___finally@@"({{.*}})
>  // 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@@"(i8
> 0, i8* %[[fp]])
> +// CHECK: call void @"\01?fin$0 at 0@nested___finally___finally@@"({{.*}})
>  // CHECK-NEXT: ret i32 0
>  //
>  // 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@@"(i8
> 1, i8* %[[fp]])
> +// CHECK: call void @"\01?fin$0 at 0@nested___finally___finally@@"({{.*}})
>
> -// CHECK-LABEL: define internal void @"\01?fin$0 at 0
> @nested___finally___finally@@"(i8 %abnormal_termination, i8*
> %frame_pointer)
> +// CHECK-LABEL: define internal void @"\01?fin$0 at 0
> @nested___finally___finally@@"({{.*}})
>  // CHECK: ret void
>
> -// CHECK-LABEL: define internal void @"\01?fin$1 at 0
> @nested___finally___finally@@"(i8 %abnormal_termination, i8*
> %frame_pointer)
> +// CHECK-LABEL: define internal void @"\01?fin$1 at 0
> @nested___finally___finally@@"({{.*}})
>  // CHECK: unreachable
>
>  int nested___finally___finally_with_eh_edge() {
> @@ -212,31 +221,27 @@ int nested___finally___finally_with_eh_e
>  // 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@@"(i8 0, i8* %[[fp]])
> +// CHECK: invoke void @"\01?fin$1 at 0
> @nested___finally___finally_with_eh_edge@@"({{.*}})
>  // 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@@"(i8 0, i8* %[[fp]])
> +// CHECK: call void @"\01?fin$0 at 0
> @nested___finally___finally_with_eh_edge@@"({{.*}})
>  // CHECK-NEXT: ret i32 912
>  //
>  // CHECK: [[lpad1]]
>  // CHECK-NEXT: landingpad
>  // CHECK-NEXT: cleanup
> -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> -// CHECK: invoke void @"\01?fin$1 at 0
> @nested___finally___finally_with_eh_edge@@"(i8 1, i8* %[[fp]])
> +// CHECK: invoke void @"\01?fin$1 at 0
> @nested___finally___finally_with_eh_edge@@"({{.*}})
>  // CHECK:          to label %[[outercont:[^ ]*]] unwind label %[[lpad2]]
>  //
>  // 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@@"(i8 1, i8* %[[fp]])
> +// CHECK: call void @"\01?fin$0 at 0
> @nested___finally___finally_with_eh_edge@@"({{.*}})
>  // CHECK: resume
>
> -// CHECK-LABEL: define internal void @"\01?fin$0 at 0
> @nested___finally___finally_with_eh_edge@@"(i8 %abnormal_termination, i8*
> %frame_pointer)
> +// CHECK-LABEL: define internal void @"\01?fin$0 at 0
> @nested___finally___finally_with_eh_edge@@"({{.*}})
>  // CHECK: ret void
>
> -// CHECK-LABEL: define internal void @"\01?fin$1 at 0
> @nested___finally___finally_with_eh_edge@@"(i8 %abnormal_termination, i8*
> %frame_pointer)
> +// CHECK-LABEL: define internal void @"\01?fin$1 at 0
> @nested___finally___finally_with_eh_edge@@"({{.*}})
>  // 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=236052&r1=236051&r2=236052&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/CodeGen/exceptions-seh.c (original)
> +++ cfe/trunk/test/CodeGen/exceptions-seh.c Tue Apr 28 17:19:32 2015
> @@ -1,4 +1,7 @@
> -// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm
> -o - | FileCheck %s
> +// RUN: %clang_cc1 %s -triple x86_64-pc-win32 -fms-extensions -emit-llvm
> -o - \
> +// RUN:         | FileCheck %s --check-prefix=CHECK --check-prefix=X64
> +// RUN: %clang_cc1 %s -triple i686-pc-win32 -fms-extensions -emit-llvm -o
> - \
> +// RUN:         | FileCheck %s --check-prefix=CHECK --check-prefix=X86
>
>  void try_body(int numerator, int denominator, int *myres) {
>    *myres = numerator / denominator;
> @@ -24,7 +27,8 @@ int safe_div(int numerator, int denomina
>  // CHECK:       to label %{{.*}} unwind label %[[lpad:[^ ]*]]
>  //
>  // CHECK: [[lpad]]
> -// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)*
> @__C_specific_handler to i8*)
> +// X64: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)*
> @__C_specific_handler to i8*)
> +// X86: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)*
> @_except_handler3 to i8*)
>  // CHECK-NEXT: catch i8* null
>  // CHECK-NOT: br i1
>  // CHECK: br label %[[except:[^ ]*]]
> @@ -52,14 +56,19 @@ int filter_expr_capture(void) {
>  // CHECK: invoke void @j() #[[NOINLINE]]
>  //
>  // CHECK: landingpad
> -// CHECK-NEXT: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0 at 0
> @filter_expr_capture@@" to i8*)
> +// CHECK-NEXT: catch i8* bitcast (i32 ({{.*}})* @"\01?filt$0 at 0
> @filter_expr_capture@@" to i8*)
>  // CHECK: store i32 13, i32* %[[r]]
>  //
>  // CHECK: %[[rv:[^ ]*]] = load i32, i32* %[[r]]
>  // CHECK: ret i32 %[[rv]]
>
> -// CHECK-LABEL: define internal i32 @"\01?filt$0 at 0@filter_expr_capture@@"(i8*
> %exception_pointers, i8* %frame_pointer)
> -// CHECK: call i8* @llvm.framerecover(i8* bitcast (i32 ()*
> @filter_expr_capture to i8*), i8* %frame_pointer, i32 0)
> +// X64-LABEL: define internal i32 @"\01?filt$0 at 0@filter_expr_capture@@"(i8*
> %exception_pointers, i8* %frame_pointer)
> +// X64: call i8* @llvm.framerecover(i8* bitcast (i32 ()*
> @filter_expr_capture to i8*), i8* %frame_pointer, i32 0)
> +//
> +// X86-LABEL: define internal i32 @"\01?filt$0 at 0@filter_expr_capture@@"()
> +// X86: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 1)
> +// X86: call i8* @llvm.framerecover(i8* bitcast (i32 ()*
> @filter_expr_capture to i8*), i8* %[[fp]], i32 0)
> +//
>  // CHECK: store i32 -1, i32* %{{.*}}
>  // CHECK: ret i32 -1
>
> @@ -87,19 +96,20 @@ int nested_try(void) {
>  // CHECK: br label %[[inner_try_cont:[^ ]*]]
>  //
>  // CHECK: [[lpad]]
> -// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)*
> @__C_specific_handler to i8*)
> -// CHECK: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$1 at 0@nested_try@@"
> to i8*)
> -// CHECK: catch i8* bitcast (i32 (i8*, i8*)* @"\01?filt$0 at 0@nested_try@@"
> to i8*)
> +// X64: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)*
> @__C_specific_handler to i8*)
> +// X86: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)*
> @_except_handler3 to i8*)
> +// CHECK: catch i8* bitcast (i32 ({{.*}})* @"\01?filt$1 at 0@nested_try@@"
> to i8*)
> +// CHECK: catch i8* bitcast (i32 ({{.*}})* @"\01?filt$0 at 0@nested_try@@"
> to i8*)
>  // CHECK: store i8* %{{.*}}, i8** %[[ehptr_slot:[^ ]*]]
>  // CHECK: store i32 %{{.*}}, i32* %[[sel_slot:[^ ]*]]
>  //
>  // CHECK: load i32, i32* %[[sel_slot]]
> -// CHECK: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)*
> @"\01?filt$1 at 0@nested_try@@" to i8*))
> +// CHECK: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ({{.*}})*
> @"\01?filt$1 at 0@nested_try@@" to i8*))
>  // CHECK: icmp eq i32
>  // CHECK: br i1
>  //
>  // CHECK: load i32, i32* %[[sel_slot]]
> -// CHECK: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 (i8*, i8*)*
> @"\01?filt$0 at 0@nested_try@@" to i8*))
> +// CHECK: call i32 @llvm.eh.typeid.for(i8* bitcast (i32 ({{.*}})*
> @"\01?filt$0 at 0@nested_try@@" to i8*))
>  // CHECK: icmp eq i32
>  // CHECK: br i1
>  //
> @@ -115,6 +125,20 @@ int nested_try(void) {
>  //
>  // CHECK: [[inner_try_cont]]
>  // CHECK: br label %[[outer_try_cont]]
> +//
> +// CHECK-LABEL: define internal i32 @"\01?filt$0 at 0@nested_try@@"({{.*}})
> +// X86: call i8* @llvm.eh.exceptioninfo()
> +// CHECK: load i32*, i32**
> +// CHECK: load i32, i32*
> +// CHECK: ptrtoint
> +// CHECK: icmp eq i32 %{{.*}}, 456
> +//
> +// CHECK-LABEL: define internal i32 @"\01?filt$1 at 0@nested_try@@"({{.*}})
> +// X86: call i8* @llvm.eh.exceptioninfo()
> +// CHECK: load i32*, i32**
> +// CHECK: load i32, i32*
> +// CHECK: ptrtoint
> +// CHECK: icmp eq i32 %{{.*}}, 123
>
>  static unsigned g = 0;
>  void basic_finally(void) {
> @@ -134,18 +158,21 @@ void basic_finally(void) {
>  // CHECK:       to label %[[cont:[^ ]*]] unwind label %[[lpad:[^ ]*]]
>  //
>  // CHECK: [[cont]]
> -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> -// CHECK: call void @"\01?fin$0 at 0@basic_finally@@"(i8 0, i8* %[[fp]])
> +// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> +// X64: call void @"\01?fin$0 at 0@basic_finally@@"(i8 0, i8* %[[fp]])
> +// X86: call void @"\01?fin$0 at 0@basic_finally@@"()
>  // CHECK: ret void
>  //
>  // CHECK: [[lpad]]
> -// CHECK: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)*
> @__C_specific_handler to i8*)
> +// X64: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)*
> @__C_specific_handler to i8*)
> +// X86: landingpad { i8*, i32 } personality i8* bitcast (i32 (...)*
> @_except_handler3 to i8*)
>  // CHECK-NEXT: cleanup
> -// CHECK: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> -// CHECK: call void @"\01?fin$0 at 0@basic_finally@@"(i8 1, i8* %[[fp]])
> +// X64: %[[fp:[^ ]*]] = call i8* @llvm.frameaddress(i32 0)
> +// X64: call void @"\01?fin$0 at 0@basic_finally@@"(i8 1, i8* %[[fp]])
> +// X86: call void @"\01?fin$0 at 0@basic_finally@@"()
>  // CHECK: resume
>
> -// CHECK: define internal void @"\01?fin$0 at 0@basic_finally@@"(i8
> %abnormal_termination, i8* %frame_pointer)
> +// CHECK: define internal void @"\01?fin$0 at 0@basic_finally@@"({{.*}})
>  // CHECK:   load i32, i32* @g, align 4
>  // CHECK:   add i32 %{{.*}}, -1
>  // CHECK:   store i32 %{{.*}}, i32* @g, align 4
>
>
> _______________________________________________
> 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/20150428/a485427a/attachment.html>


More information about the cfe-commits mailing list