r239415 - Re-land r236052, "[SEH] Add 32-bit lowering code for __try"

Reid Kleckner reid at kleckner.net
Tue Jun 9 10:47:50 PDT 2015


Author: rnk
Date: Tue Jun  9 12:47:50 2015
New Revision: 239415

URL: http://llvm.org/viewvc/llvm-project?rev=239415&view=rev
Log:
Re-land r236052, "[SEH] Add 32-bit lowering code for __try"

This reverts r236167.

LLVM should be ready for this now.

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=239415&r1=239414&r2=239415&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Jun  9 12:47:50 2015
@@ -5559,6 +5559,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=239415&r1=239414&r2=239415&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TargetInfo.h (original)
+++ cfe/trunk/include/clang/Basic/TargetInfo.h Tue Jun  9 12:47:50 2015
@@ -797,6 +797,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=239415&r1=239414&r2=239415&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGException.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGException.cpp Tue Jun  9 12:47:50 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"
@@ -1274,14 +1275,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");
@@ -1306,25 +1299,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);
   }
 };
 }
@@ -1335,6 +1342,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) {}
 
@@ -1361,25 +1369,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.CreateCall(
+        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) {
@@ -1402,39 +1478,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.CreateCall(
-          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;
   }
 }
 
@@ -1469,10 +1522,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
@@ -1484,14 +1534,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;
@@ -1532,13 +1584,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;
@@ -1570,7 +1624,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());
@@ -1585,6 +1639,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)
@@ -1602,6 +1659,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();
@@ -1611,9 +1670,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;
   }
@@ -1645,6 +1710,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=239415&r1=239414&r2=239415&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Tue Jun  9 12:47:50 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=239415&r1=239414&r2=239415&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Tue Jun  9 12:47:50 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*'.
@@ -2039,8 +2045,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=239415&r1=239414&r2=239415&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Tue Jun  9 12:47:50 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"
@@ -3648,6 +3649,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=239415&r1=239414&r2=239415&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/exceptions-seh-finally.c (original)
+++ cfe/trunk/test/CodeGen/exceptions-seh-finally.c Tue Jun  9 12:47:50 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=239415&r1=239414&r2=239415&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/exceptions-seh.c (original)
+++ cfe/trunk/test/CodeGen/exceptions-seh.c Tue Jun  9 12:47:50 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





More information about the cfe-commits mailing list