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