tentzen created this revision.
tentzen added reviewers: andrew.w.kaylor, rnk, majnemer, pengfei, eli.friedman, 
JosephTremoulet, asmith.
Herald added subscribers: llvm-commits, cfe-commits, jdoerfert, kbarton, 
hiraditya, kristof.beyls, nemanjai.
Herald added projects: clang, LLVM.

This patch adds the support of Hardware Exception for Microsoft Windows SEH 
(Structured Exception Handling).  This is the first step of this project; only 
X86_64 target is enabled in this patch. We will add AArch64 & ARM and X86 
targets later.

Compiler options:
For clang-cl.exe, the option is -EHa, the same as MSVC.
For clang.exe, the extra option is -feh-asynch, plus -triple x86_64-windows  
-fexceptions and -fcxx-exceptions as usual.

NOTE: : Without the -EHa or -feh-asynch, this patch is a NO-DIFF change.

The rules for C code:
For C-code, one way (MSVC approach) to achieve SEH -EHa semantic is to follow 
three rules. First, no exception can move in or out of _try region., i.e., no 
"potential faulty instruction can be moved across _try boundary. Second, the 
order of exceptions for instructions 'directly' under a _try must be preserved 
(not applied to those in callees). Finally, global states (local/global/heap 
variables) that can be read outside of _try region must be updated in memory 
(not just in register) before the subsequent exception occurs.

The impact to C++ code:
Although SEH is a feature for C code, -EHa does have a profound effect on C++ 
side. When a C++ function (in the same compilation unit with option -EHa ) is 
called by a SEH C function, a hardware exception occurs in C++ code can also be 
handled properly by an upstream SEH _try-handler or a C++ catch(…). As such, 
when that happens in the middle of an object’s life scope, the dtor must be 
invoked the same way as C++ Synchronous Exception during unwinding process.

Design:
A natural way to achieve the rules above in LLVM today is to allow an EH edge 
added on memory/computation instruction (previous iload/istore idea) so that 
exception path is modeled in Flow graph preciously. However, tracking every 
single memory instruction and potential faulty instruction can create many 
Invokes, complicate flow graph and possibly result in negative performance 
impact for downstream optimization and code generation. Making all 
optimizations be aware of the new semantic is also substantial.

This design does not intend to model exception path at instruction level. 
Instead, the proposed design tracks and reports EH state at BLOCK-level to 
reduce the complexity of flow graph and minimize the performance-impact on CPP 
code under -EHa option.

One key element of this design is the ability to compute State number at 
block-level. Our algorithm is based on the following rationales:

A _try scope is always a SEME (Single Entry Multiple Exits) region as jumping 
into a _try is not allowed.
The single entry must start with a seh_try_begin() invoke with a correct State 
number that is the initial state of the SEME.
Through control-flow, state number is propagated into all blocks.
Side exits marked by seh_try_end() will unwind to parent state based on 
existing SEHUnwindMap[].
Side exits can ONLY jump into parent scopes (lower state number).
Thus, when a block succeeds various states from its predecessors, the lowest 
State triumphs others.
If some exits flow to unreachable, propagation on those paths terminate, not 
affecting remaining blocks.
For CPP code, object lifetime region is usually a SEME as SEH _try. However 
there is one rare exception: jumping into a lifetime that has Dtor but has no 
Ctor is warned, but allowed:

  note: jump bypasses variable with a non-trivial destructor

In this case, this region is actually a MEME (multiple entry multiple exits). 
Our solution is to inject a seh_try_begin() invoke in the side entry block to 
ensure a correct State.

Implementation:
Detailed implementation described below.

- Two intrinsic are created to track CPP object scopes; eha_scope_begin() and 
eha_scope_end(). _scope_begin() is immediately added after ctor() is called and 
EHStack is pushed. So it must be an invoke, not a call. With that it's also 
guaranteed an EH-cleanup-pad is created regardless whether there exists a call 
in this scope. _scope_end is added before dtor(). These two intrinsics make the 
computation of Block-State possible in downstream code gen pass, even in the 
presence of ctor/dtor inlining.

- Two intrinsic, seh_try_begin() and seh_try_end(), are added for C-code to 
mark _try boundary and to prevent from exceptions being moved across _try 
boundary.

- All memory instructions inside a _try are considered as 'volatile' to assure 
2nd and 3rd rules for C-code above. This is a little sub-optimized. But it's 
acceptable as the amount of code directly under _try is very small.

- For both C++ & C-code, the state of each block is computed at the same place 
in BE (WinEHPreparing pass) where all other EH tables/maps are calculated. In 
addition to _scope_begin & _scope_end, the computation of block state also rely 
on the existing State tracking code (UnwindMap and InvokeStateMap).

- For both C++ & C-code, the state of each block with potential trap 
instruction is marked and reported in DAG Instruction Selection pass, the same 
place where the state for -EHsc (synchronous exceptions) is done.

- If the first instruction in a reported block scope can trap, a Nop is 
injected before this instruction. This nop is needed to accommodate LLVM 
Windows EH implementation, in which the address in IPToState table is offset by 
+1. (note the purpose of that is to ensure the return address of a call is in 
the same scope as the call address.

- The handler for catch(...) for -EHa must handle HW exception. So it is 
'adjective' flag is reset (it cannot be IsStdDotDot (0x40) that only catches 
C++ exceptions).

- Suppress push/popTerminate() scope (from noexcept/noTHrow) so that HW 
exceptions can be passed through.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D80344

Files:
  clang/include/clang/AST/Stmt.h
  clang/include/clang/Basic/LangOptions.def
  clang/include/clang/Driver/Options.td
  clang/lib/CodeGen/CGCleanup.cpp
  clang/lib/CodeGen/CGDecl.cpp
  clang/lib/CodeGen/CGException.cpp
  clang/lib/CodeGen/CGStmt.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/CodeGen/CodeGenModule.cpp
  clang/lib/Driver/ToolChains/Clang.cpp
  clang/lib/Frontend/CompilerInvocation.cpp
  clang/lib/Sema/JumpDiagnostics.cpp
  clang/test/CodeGen/windows-seh-EHa-CppCatchDotDotDot.cpp
  clang/test/CodeGen/windows-seh-EHa-CppDtors01.cpp
  clang/test/CodeGen/windows-seh-EHa-TryInFinally.cpp
  llvm/include/llvm/CodeGen/SelectionDAGISel.h
  llvm/include/llvm/CodeGen/WinEHFuncInfo.h
  llvm/include/llvm/IR/BasicBlock.h
  llvm/include/llvm/IR/Intrinsics.td
  llvm/lib/Analysis/EHPersonalities.cpp
  llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
  llvm/lib/CodeGen/AsmPrinter/WinException.cpp
  llvm/lib/CodeGen/BranchFolding.cpp
  llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
  llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
  llvm/lib/CodeGen/WinEHPrepare.cpp
  llvm/lib/IR/BasicBlock.cpp
  llvm/lib/IR/Verifier.cpp
  llvm/test/CodeGen/X86/windows-seh-EHa-CppCatchDotDotDot.ll
  llvm/test/CodeGen/X86/windows-seh-EHa-CppDtors01.ll
  llvm/test/CodeGen/X86/windows-seh-EHa-TryInFinally.ll

Index: llvm/test/CodeGen/X86/windows-seh-EHa-TryInFinally.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/X86/windows-seh-EHa-TryInFinally.ll
@@ -0,0 +1,226 @@
+; RUN: llc -verify-machineinstrs < %s | FileCheck %s
+
+; CHECK-LABEL: "?fin$0@0@main@@"
+; CHECK:      .seh_handlerdata
+; CHECK:      .set ".L?fin$0@0@main@@$parent_frame_offset", 48
+; CHECK-NEXT:        .long   (.Llsda_end1-.Llsda_begin1)/16 
+; CHECK-NEXT: .Llsda_begin1:
+; CHECK-NEXT:        .long   .Ltmp
+; CHECK-NEXT:        .long   .Ltmp
+; CHECK-NEXT:        .long   "?dtor$
+; CHECK-NEXT:        .long   0
+; CHECK-NEXT: .Llsda_end1:
+
+; ModuleID = 'windows-seh-EHa-TryInFinally.cpp'
+source_filename = "windows-seh-EHa-TryInFinally.cpp"
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-msvc"
+
+$"??_C@_0CI@MDFPIOJJ@?5?9?9?9?5Test?5_Try?5in?5_finally?5?9?9?9?5i@" = comdat any
+
+$"??_C@_0BN@HHKJHLBE@?5?5In?5Inner?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@" = comdat any
+
+$"??_C@_0BN@HAIIIOKI@?5?5In?5outer?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@" = comdat any
+
+$"??_C@_0BJ@OJMMAGCD@?5?5In?5outer?5_try?5i?5?$DN?5?$CFd?5?6?$AA@" = comdat any
+
+$"??_C@_0CG@ENDJHCGA@?5?9?9?9?5In?5outer?5except?5handler?5i?5?$DN@" = comdat any
+
+@"??_C@_0CI@MDFPIOJJ@?5?9?9?9?5Test?5_Try?5in?5_finally?5?9?9?9?5i@" = linkonce_odr dso_local unnamed_addr constant [40 x i8] c" --- Test _Try in _finally --- i = %d \0A\00", comdat, align 1
+@"??_C@_0BN@HHKJHLBE@?5?5In?5Inner?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [29 x i8] c"  In Inner _finally i = %d \0A\00", comdat, align 1
+@"??_C@_0BN@HAIIIOKI@?5?5In?5outer?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [29 x i8] c"  In outer _finally i = %d \0A\00", comdat, align 1
+@"??_C@_0BJ@OJMMAGCD@?5?5In?5outer?5_try?5i?5?$DN?5?$CFd?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [25 x i8] c"  In outer _try i = %d \0A\00", comdat, align 1
+@"??_C@_0CG@ENDJHCGA@?5?9?9?9?5In?5outer?5except?5handler?5i?5?$DN@" = linkonce_odr dso_local unnamed_addr constant [38 x i8] c" --- In outer except handler i = %d \0A\00", comdat, align 1
+
+; Function Attrs: noinline norecurse optnone
+define dso_local i32 @main() #0 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
+entry:
+  %retval = alloca i32, align 4
+  %i = alloca i32, align 4
+  %__exception_code = alloca i32, align 4
+  call void (...) @llvm.localescape(i32* %i)
+  store i32 0, i32* %retval, align 4
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %cmp = icmp slt i32 %0, 3
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  %1 = load i32, i32* %i, align 4
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([40 x i8], [40 x i8]* @"??_C@_0CI@MDFPIOJJ@?5?9?9?9?5Test?5_Try?5in?5_finally?5?9?9?9?5i@", i64 0, i64 0), i32 %1)
+  invoke void @llvm.seh.try.begin()
+          to label %invoke.cont unwind label %catch.dispatch
+
+invoke.cont:                                      ; preds = %for.body
+  invoke void @llvm.seh.try.begin()
+          to label %invoke.cont1 unwind label %ehcleanup
+
+invoke.cont1:                                     ; preds = %invoke.cont
+  %2 = load volatile i32, i32* %i, align 4
+  invoke void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @"??_C@_0BJ@OJMMAGCD@?5?5In?5outer?5_try?5i?5?$DN?5?$CFd?5?6?$AA@", i64 0, i64 0), i32 %2) #6
+          to label %invoke.cont2 unwind label %ehcleanup
+
+invoke.cont2:                                     ; preds = %invoke.cont1
+  %3 = load volatile i32, i32* %i, align 4
+  %cmp3 = icmp eq i32 %3, 0
+  br i1 %cmp3, label %if.then, label %if.end
+
+if.then:                                          ; preds = %invoke.cont2
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %invoke.cont2
+  invoke void @llvm.seh.try.end()
+          to label %invoke.cont4 unwind label %ehcleanup
+
+invoke.cont4:                                     ; preds = %if.end
+  %4 = call i8* @llvm.localaddress()
+  invoke void @"?fin$0@0@main@@"(i8 0, i8* %4) #6
+          to label %invoke.cont5 unwind label %catch.dispatch
+
+invoke.cont5:                                     ; preds = %invoke.cont4
+  invoke void @llvm.seh.try.end()
+          to label %invoke.cont7 unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %invoke.cont5, %invoke.cont6, %ehcleanup, %invoke.cont4, %for.body
+  %5 = catchswitch within none [label %__except] unwind to caller
+
+__except:                                         ; preds = %catch.dispatch
+  %6 = catchpad within %5 [i8* null]
+  catchret from %6 to label %__except8
+
+__except8:                                        ; preds = %__except
+  %7 = call i32 @llvm.eh.exceptioncode(token %6)
+  store i32 %7, i32* %__exception_code, align 4
+  %8 = load i32, i32* %i, align 4
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([38 x i8], [38 x i8]* @"??_C@_0CG@ENDJHCGA@?5?9?9?9?5In?5outer?5except?5handler?5i?5?$DN@", i64 0, i64 0), i32 %8)
+  br label %__try.cont
+
+__try.cont:                                       ; preds = %__except8, %invoke.cont7
+  br label %for.inc
+
+for.inc:                                          ; preds = %__try.cont
+  %9 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %9, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+invoke.cont7:                                     ; preds = %invoke.cont5
+  br label %__try.cont
+
+ehcleanup:                                        ; preds = %if.end, %invoke.cont1, %invoke.cont
+  %10 = cleanuppad within none []
+  %11 = call i8* @llvm.localaddress()
+  invoke void @"?fin$0@0@main@@"(i8 1, i8* %11) #6 [ "funclet"(token %10) ]
+          to label %invoke.cont6 unwind label %catch.dispatch
+
+invoke.cont6:                                     ; preds = %ehcleanup
+  cleanupret from %10 unwind label %catch.dispatch
+
+for.end:                                          ; preds = %for.cond
+  ret i32 0
+}
+
+declare dso_local void @"?printf@@YAXZZ"(...) #1
+
+; Function Attrs: nounwind willreturn
+declare dso_local void @llvm.seh.try.begin() #2
+
+declare dso_local i32 @__C_specific_handler(...)
+
+; Function Attrs: noinline
+define internal void @"?fin$0@0@main@@"(i8 %abnormal_termination, i8* %frame_pointer) #3 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
+entry:
+  %frame_pointer.addr = alloca i8*, align 8
+  %abnormal_termination.addr = alloca i8, align 1
+  %0 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @main to i8*), i8* %frame_pointer, i32 0)
+  %i = bitcast i8* %0 to i32*
+  store i8* %frame_pointer, i8** %frame_pointer.addr, align 8
+  store i8 %abnormal_termination, i8* %abnormal_termination.addr, align 1
+  invoke void @llvm.seh.try.begin()
+          to label %invoke.cont unwind label %ehcleanup
+
+invoke.cont:                                      ; preds = %entry
+  %1 = load volatile i32, i32* %i, align 4
+  invoke void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([29 x i8], [29 x i8]* @"??_C@_0BN@HAIIIOKI@?5?5In?5outer?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@", i64 0, i64 0), i32 %1) #6
+          to label %invoke.cont1 unwind label %ehcleanup
+
+invoke.cont1:                                     ; preds = %invoke.cont
+  %2 = load volatile i32, i32* %i, align 4
+  %cmp = icmp eq i32 %2, 1
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %invoke.cont1
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %invoke.cont1
+  invoke void @llvm.seh.try.end()
+          to label %invoke.cont2 unwind label %ehcleanup
+
+invoke.cont2:                                     ; preds = %if.end
+  call void @"?fin$1@0@main@@"(i8 0, i8* %frame_pointer)
+  ret void
+
+ehcleanup:                                        ; preds = %if.end, %invoke.cont, %entry
+  %3 = cleanuppad within none []
+  call void @"?fin$1@0@main@@"(i8 1, i8* %frame_pointer) [ "funclet"(token %3) ]
+  cleanupret from %3 unwind to caller
+}
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.localrecover(i8*, i8*, i32 immarg) #4
+
+; Function Attrs: noinline
+define internal void @"?fin$1@0@main@@"(i8 %abnormal_termination, i8* %frame_pointer) #3 {
+entry:
+  %frame_pointer.addr = alloca i8*, align 8
+  %abnormal_termination.addr = alloca i8, align 1
+  %0 = call i8* @llvm.localrecover(i8* bitcast (i32 ()* @main to i8*), i8* %frame_pointer, i32 0)
+  %i = bitcast i8* %0 to i32*
+  store i8* %frame_pointer, i8** %frame_pointer.addr, align 8
+  store i8 %abnormal_termination, i8* %abnormal_termination.addr, align 1
+  %1 = load i32, i32* %i, align 4
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([29 x i8], [29 x i8]* @"??_C@_0BN@HHKJHLBE@?5?5In?5Inner?5_finally?5i?5?$DN?5?$CFd?5?6?$AA@", i64 0, i64 0), i32 %1)
+  %2 = load i32, i32* %i, align 4
+  %cmp = icmp eq i32 %2, 2
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %entry
+  ret void
+}
+
+; Function Attrs: nounwind willreturn
+declare dso_local void @llvm.seh.try.end() #2
+
+; Function Attrs: nounwind readnone
+declare i8* @llvm.localaddress() #4
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.eh.exceptioncode(token) #4
+
+; Function Attrs: nounwind
+declare void @llvm.localescape(...) #5
+
+attributes #0 = { noinline norecurse optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind willreturn }
+attributes #3 = { noinline "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #4 = { nounwind readnone }
+attributes #5 = { nounwind }
+attributes #6 = { noinline }
+
+!llvm.module.flags = !{!0, !1}
+!llvm.ident = !{!2}
+
+!0 = !{i32 1, !"wchar_size", i32 2}
+!1 = !{i32 2, !"eh-asynch", i32 1}
+!2 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project 7ee479a760e0a4402b4eb7fb6168768a44f66945)"}
+
Index: llvm/test/CodeGen/X86/windows-seh-EHa-CppDtors01.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/X86/windows-seh-EHa-CppDtors01.ll
@@ -0,0 +1,258 @@
+; RUN: llc -verify-machineinstrs < %s | FileCheck %s
+
+; CHECK-LABEL: "$cppxdata$?crash@@YAXH@Z":
+; CHECK:	.long	("$stateUnwindMap$?crash@@YAXH@Z")
+; CHECK:	.long	("$ip2state$?crash@@YAXH@Z")
+
+; CHECK-LABEL: "$stateUnwindMap$?crash@@YAXH@Z":
+; CHECK:	.long	-1 
+; CHECK:	.long	"?dtor$
+; CHECK:	.long	0 
+; CHECK:	.long	"?dtor$
+; CHECK:	.long	1
+; CHECK:	.long	"?dtor$
+
+; CHECK-LABEL: "$ip2state$?crash@@YAXH@Z":
+; CHECK-NEXT:	.long	.Lfunc_begin0@IMGREL
+; CHECK-NEXT:	.long	-1                  
+; CHECK-NEXT:	.long	.Ltmp     
+; CHECK-NEXT:	.long	0                   
+; CHECK-NEXT:	.long	.Ltmp     
+; CHECK-NEXT:	.long	1                   
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	2                   
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	1                   
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	0                   
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	-1                  
+
+; ModuleID = 'windows-seh-EHa-CppDtors01.cpp'
+source_filename = "windows-seh-EHa-CppDtors01.cpp"
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-msvc"
+
+%struct.A = type { i8 }
+%struct.B = type { i8 }
+%struct.C = type { i8 }
+
+$"??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@" = comdat any
+
+$"??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@" = comdat any
+
+$"??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@" = comdat any
+
+$"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" = comdat any
+
+@"?g@@3HA" = dso_local global i32 0, align 4
+@"??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@" = linkonce_odr dso_local unnamed_addr constant [44 x i8] c" Test CPP unwind: in catch handler i = %d \0A\00", comdat, align 1
+@"??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c" in C dtor \0A\00", comdat, align 1
+@"??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c" in B dtor \0A\00", comdat, align 1
+@"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c" in A dtor \0A\00", comdat, align 1
+
+; Function Attrs: noinline optnone
+define dso_local void @"?crash@@YAXH@Z"(i32 %i) #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+  %i.addr = alloca i32, align 4
+  %ObjA = alloca %struct.A, align 1
+  %ObjB = alloca %struct.B, align 1
+  %ObjC = alloca %struct.C, align 1
+  store i32 %i, i32* %i.addr, align 4
+  invoke void @llvm.eha.scope.begin()
+          to label %invoke.cont unwind label %ehcleanup13
+
+invoke.cont:                                      ; preds = %entry
+  %0 = load i32, i32* %i.addr, align 4
+  %cmp = icmp eq i32 %0, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %invoke.cont
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %invoke.cont
+  invoke void @llvm.eha.scope.begin()
+          to label %invoke.cont1 unwind label %ehcleanup11
+
+invoke.cont1:                                     ; preds = %if.end
+  %1 = load i32, i32* %i.addr, align 4
+  %cmp2 = icmp eq i32 %1, 1
+  br i1 %cmp2, label %if.then3, label %if.end4
+
+if.then3:                                         ; preds = %invoke.cont1
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end4
+
+if.end4:                                          ; preds = %if.then3, %invoke.cont1
+  invoke void @llvm.eha.scope.begin()
+          to label %invoke.cont5 unwind label %ehcleanup
+
+invoke.cont5:                                     ; preds = %if.end4
+  %2 = load i32, i32* %i.addr, align 4
+  %cmp6 = icmp eq i32 %2, 2
+  br i1 %cmp6, label %if.then7, label %if.end8
+
+if.then7:                                         ; preds = %invoke.cont5
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end8
+
+if.end8:                                          ; preds = %if.then7, %invoke.cont5
+  invoke void @llvm.eha.scope.end()
+          to label %invoke.cont9 unwind label %ehcleanup
+
+invoke.cont9:                                     ; preds = %if.end8
+  call void @"??1C@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.C* %ObjC) #6
+  invoke void @llvm.eha.scope.end()
+          to label %invoke.cont10 unwind label %ehcleanup11
+
+invoke.cont10:                                    ; preds = %invoke.cont9
+  call void @"??1B@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.B* %ObjB) #6
+  invoke void @llvm.eha.scope.end()
+          to label %invoke.cont12 unwind label %ehcleanup13
+
+invoke.cont12:                                    ; preds = %invoke.cont10
+  call void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %ObjA) #6
+  ret void
+
+ehcleanup:                                        ; preds = %if.end8, %if.end4
+  %3 = cleanuppad within none []
+  call void @"??1C@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.C* %ObjC) #6 [ "funclet"(token %3) ]
+  cleanupret from %3 unwind label %ehcleanup11
+
+ehcleanup11:                                      ; preds = %invoke.cont9, %ehcleanup, %if.end
+  %4 = cleanuppad within none []
+  call void @"??1B@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.B* %ObjB) #6 [ "funclet"(token %4) ]
+  cleanupret from %4 unwind label %ehcleanup13
+
+ehcleanup13:                                      ; preds = %invoke.cont10, %ehcleanup11, %entry
+  %5 = cleanuppad within none []
+  call void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %ObjA) #6 [ "funclet"(token %5) ]
+  cleanupret from %5 unwind to caller
+}
+
+; Function Attrs: nounwind readnone
+declare dso_local void @llvm.eha.scope.begin() #1
+
+declare dso_local i32 @__CxxFrameHandler3(...)
+
+; Function Attrs: nounwind readnone
+declare dso_local void @llvm.eha.scope.end() #1
+
+; Function Attrs: noinline nounwind optnone
+define internal void @"??1C@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.C* %this) unnamed_addr #2 align 2 {
+entry:
+  %this.addr = alloca %struct.C*, align 8
+  store %struct.C* %this, %struct.C** %this.addr, align 8
+  %this1 = load %struct.C*, %struct.C** %this.addr, align 8
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@FCCEEGKL@?5in?5C?5dtor?5?6?$AA@", i64 0, i64 0))
+  ret void
+}
+
+; Function Attrs: noinline nounwind optnone
+define internal void @"??1B@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.B* %this) unnamed_addr #2 align 2 {
+entry:
+  %this.addr = alloca %struct.B*, align 8
+  store %struct.B* %this, %struct.B** %this.addr, align 8
+  %this1 = load %struct.B*, %struct.B** %this.addr, align 8
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@EFFPFCOI@?5in?5B?5dtor?5?6?$AA@", i64 0, i64 0))
+  ret void
+}
+
+; Function Attrs: noinline nounwind optnone
+define internal void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %this) unnamed_addr #2 align 2 {
+entry:
+  %this.addr = alloca %struct.A*, align 8
+  store %struct.A* %this, %struct.A** %this.addr, align 8
+  %this1 = load %struct.A*, %struct.A** %this.addr, align 8
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@", i64 0, i64 0))
+  ret void
+}
+
+; Function Attrs: noinline norecurse optnone
+define dso_local i32 @main() #3 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
+entry:
+  %retval = alloca i32, align 4
+  %i = alloca i32, align 4
+  %__exception_code = alloca i32, align 4
+  store i32 0, i32* %retval, align 4
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %cmp = icmp slt i32 %0, 3
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  invoke void @llvm.seh.try.begin()
+          to label %invoke.cont unwind label %catch.dispatch
+
+invoke.cont:                                      ; preds = %for.body
+  %1 = load volatile i32, i32* %i, align 4
+  invoke void @"?crash@@YAXH@Z"(i32 %1) #7
+          to label %invoke.cont1 unwind label %catch.dispatch
+
+invoke.cont1:                                     ; preds = %invoke.cont
+  invoke void @llvm.seh.try.end()
+          to label %invoke.cont2 unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %invoke.cont1, %invoke.cont, %for.body
+  %2 = catchswitch within none [label %__except] unwind to caller
+
+__except:                                         ; preds = %catch.dispatch
+  %3 = catchpad within %2 [i8* null]
+  catchret from %3 to label %__except3
+
+__except3:                                        ; preds = %__except
+  %4 = call i32 @llvm.eh.exceptioncode(token %3)
+  store i32 %4, i32* %__exception_code, align 4
+  %5 = load i32, i32* %i, align 4
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([44 x i8], [44 x i8]* @"??_C@_0CM@KAOHJHDK@?5Test?5CPP?5unwind?3?5in?5catch?5handl@", i64 0, i64 0), i32 %5)
+  br label %__try.cont
+
+__try.cont:                                       ; preds = %__except3, %invoke.cont2
+  br label %for.inc
+
+for.inc:                                          ; preds = %__try.cont
+  %6 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %6, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+invoke.cont2:                                     ; preds = %invoke.cont1
+  br label %__try.cont
+
+for.end:                                          ; preds = %for.cond
+  ret i32 0
+}
+
+; Function Attrs: nounwind willreturn
+declare dso_local void @llvm.seh.try.begin() #4
+
+declare dso_local i32 @__C_specific_handler(...)
+
+; Function Attrs: nounwind willreturn
+declare dso_local void @llvm.seh.try.end() #4
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.eh.exceptioncode(token) #1
+
+declare dso_local void @"?printf@@YAXZZ"(...) #5
+
+attributes #0 = { noinline optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { nounwind readnone }
+attributes #2 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #3 = { noinline norecurse optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #4 = { nounwind willreturn }
+attributes #5 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #6 = { nounwind }
+attributes #7 = { noinline }
+
+!llvm.module.flags = !{!0, !1}
+!llvm.ident = !{!2}
+
+!0 = !{i32 1, !"wchar_size", i32 2}
+!1 = !{i32 2, !"eh-asynch", i32 1}
+!2 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project 7ee479a760e0a4402b4eb7fb6168768a44f66945)"}
+
Index: llvm/test/CodeGen/X86/windows-seh-EHa-CppCatchDotDotDot.ll
===================================================================
--- /dev/null
+++ llvm/test/CodeGen/X86/windows-seh-EHa-CppCatchDotDotDot.ll
@@ -0,0 +1,291 @@
+; RUN: llc -verify-machineinstrs < %s | FileCheck %s
+
+; CHECK-LABEL: "$cppxdata$?crash@@YAXH@Z":
+; CHECK:	.long	("$stateUnwindMap$?crash@@YAXH@Z")
+; CHECK:        .long   ("$tryMap$?crash@@YAXH@Z")@IMGREL # TryBlockMap
+; CHECK-NEXT:   .long   6                       # IPMapEntries
+; CHECK-NEXT:	.long	("$ip2state$?crash@@YAXH@Z")
+
+; CHECK-LABEL: "$stateUnwindMap$?crash@@YAXH@Z":
+; CHECK-NEXT:        .long   -1                
+; CHECK-NEXT:        .long   0                 
+; CHECK-NEXT:        .long   0                 
+; CHECK-NEXT:        .long   "?dtor$
+; CHECK-NEXT:        .long   -1                
+; CHECK-NEXT:        .long   0                 
+
+; CHECK-LABEL: "$tryMap$?crash@@YAXH@Z":
+; CHECK-NEXT:        .long   0             
+; CHECK-NEXT:        .long   1             
+; CHECK-NEXT:        .long   2             
+; CHECK-NEXT:        .long   1             
+; CHECK-NEXT:        .long   ("$handlerMap$
+
+; CHECK:       "$handlerMap$0$?crash@@YAXH@Z"
+; CHECK-NEXT:        .long   0             
+; CHECK-NEXT:        .long   0             
+; CHECK-NEXT:        .long   0             
+; CHECK-NEXT:        .long   "?catch$ 
+
+; CHECK-LABEL: "$ip2state$?crash@@YAXH@Z":
+; CHECK-NEXT:	.long	.Lfunc_begin0@IMGREL
+; CHECK-NEXT:	.long	-1                  
+; CHECK-NEXT:	.long	.Ltmp     
+; CHECK-NEXT:	.long	0                   
+; CHECK-NEXT:	.long	.Ltmp     
+; CHECK-NEXT:	.long	1                   
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	0                  
+; CHECK-NEXT:	.long	.Ltmp
+; CHECK-NEXT:	.long	-1                                  
+; CHECK-NEXT:	.long	"?catch$
+; CHECK-NEXT:	.long	2                  
+
+; ModuleID = 'windows-seh-EHa-CppCatchDotDotDot.cpp'
+source_filename = "windows-seh-EHa-CppCatchDotDotDot.cpp"
+target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-windows-msvc"
+
+%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
+%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 }
+%eh.CatchableTypeArray.1 = type { i32, [1 x i32] }
+%eh.ThrowInfo = type { i32, i32, i32, i32 }
+%struct.A = type { i8 }
+
+$"??_C@_0BJ@EIKFKKLB@?5in?5catch?$CI?4?4?4?$CJ?5funclet?5?6?$AA@" = comdat any
+
+$"??_R0H@8" = comdat any
+
+$"_CT??_R0H@84" = comdat any
+
+$_CTA1H = comdat any
+
+$_TI1H = comdat any
+
+$"??_C@_0CN@MKCAOFNA@?5Test?5CPP?5unwind?3?5in?5except?5hand@" = comdat any
+
+$"??_C@_0N@LJHFFAKD@?5in?5A?5ctor?5?6?$AA@" = comdat any
+
+$"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" = comdat any
+
+@"?pt1@@3PEAHEA" = dso_local global i32* null, align 8
+@"?pt2@@3PEAHEA" = dso_local global i32* null, align 8
+@"?pt3@@3PEAHEA" = dso_local global i32* null, align 8
+@"?g@@3HA" = dso_local global i32 0, align 4
+@"??_C@_0BJ@EIKFKKLB@?5in?5catch?$CI?4?4?4?$CJ?5funclet?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [25 x i8] c" in catch(...) funclet \0A\00", comdat, align 1
+@"??_7type_info@@6B@" = external constant i8*
+@"??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
+@__ImageBase = external dso_local constant i8
+@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat
+@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat
+@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat
+@"??_C@_0CN@MKCAOFNA@?5Test?5CPP?5unwind?3?5in?5except?5hand@" = linkonce_odr dso_local unnamed_addr constant [45 x i8] c" Test CPP unwind: in except handler i = %d \0A\00", comdat, align 1
+@"??_C@_0N@LJHFFAKD@?5in?5A?5ctor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c" in A ctor \0A\00", comdat, align 1
+@"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@" = linkonce_odr dso_local unnamed_addr constant [13 x i8] c" in A dtor \0A\00", comdat, align 1
+
+; Function Attrs: noinline nounwind optnone
+define dso_local void @"?foo@@YAXXZ"() #0 {
+entry:
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  ret void
+}
+
+; Function Attrs: noinline optnone
+define dso_local void @"?crash@@YAXH@Z"(i32 %i) #1 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
+entry:
+  %i.addr = alloca i32, align 4
+  %ObjA = alloca %struct.A, align 1
+  %tmp = alloca i32, align 4
+  store i32 %i, i32* %i.addr, align 4
+  %0 = load i32, i32* %i.addr, align 4
+  store i32 %0, i32* @"?g@@3HA", align 4
+  invoke void @llvm.seh.try.begin()
+          to label %invoke.cont unwind label %catch.dispatch
+
+invoke.cont:                                      ; preds = %entry
+  %call = invoke %struct.A* @"??0A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %ObjA)
+          to label %invoke.cont1 unwind label %catch.dispatch
+
+invoke.cont1:                                     ; preds = %invoke.cont
+  invoke void @llvm.eha.scope.begin()
+          to label %invoke.cont2 unwind label %ehcleanup
+
+invoke.cont2:                                     ; preds = %invoke.cont1
+  %1 = load i32, i32* %i.addr, align 4
+  %cmp = icmp eq i32 %1, 1
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %invoke.cont2
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %invoke.cont2
+  invoke void @llvm.eha.scope.end()
+          to label %invoke.cont3 unwind label %ehcleanup
+
+invoke.cont3:                                     ; preds = %if.end
+  call void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %ObjA) #6
+  br label %try.cont
+
+ehcleanup:                                        ; preds = %if.end, %invoke.cont1
+  %2 = cleanuppad within none []
+  call void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %ObjA) #6 [ "funclet"(token %2) ]
+  cleanupret from %2 unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %ehcleanup, %invoke.cont, %entry
+  %3 = catchswitch within none [label %catch] unwind to caller
+
+catch:                                            ; preds = %catch.dispatch
+  %4 = catchpad within %3 [i8* null, i32 0, i8* null]
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([25 x i8], [25 x i8]* @"??_C@_0BJ@EIKFKKLB@?5in?5catch?$CI?4?4?4?$CJ?5funclet?5?6?$AA@", i64 0, i64 0)) [ "funclet"(token %4) ]
+  %5 = load i32, i32* %i.addr, align 4
+  %cmp4 = icmp eq i32 %5, 1
+  br i1 %cmp4, label %if.then5, label %if.end6
+
+if.then5:                                         ; preds = %catch
+  %6 = load i32, i32* %i.addr, align 4
+  store i32 %6, i32* %tmp, align 4
+  %7 = bitcast i32* %tmp to i8*
+  call void @_CxxThrowException(i8* %7, %eh.ThrowInfo* @_TI1H) #7 [ "funclet"(token %4) ]
+  unreachable
+
+if.end6:                                          ; preds = %catch
+  catchret from %4 to label %catchret.dest
+
+catchret.dest:                                    ; preds = %if.end6
+  br label %try.cont
+
+try.cont:                                         ; preds = %catchret.dest, %invoke.cont3
+  ret void
+}
+
+; Function Attrs: nounwind willreturn
+declare dso_local void @llvm.seh.try.begin() #2
+
+declare dso_local i32 @__CxxFrameHandler3(...)
+
+; Function Attrs: noinline optnone
+define internal %struct.A* @"??0A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* returned %this) unnamed_addr #1 align 2 {
+entry:
+  %retval = alloca %struct.A*, align 8
+  %this.addr = alloca %struct.A*, align 8
+  store %struct.A* %this, %struct.A** %this.addr, align 8
+  %this1 = load %struct.A*, %struct.A** %this.addr, align 8
+  store %struct.A* %this1, %struct.A** %retval, align 8
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@LJHFFAKD@?5in?5A?5ctor?5?6?$AA@", i64 0, i64 0))
+  %0 = load i32, i32* @"?g@@3HA", align 4
+  %cmp = icmp eq i32 %0, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  store volatile i32 0, i32* inttoptr (i64 17 to i32*), align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.then, %entry
+  %1 = load %struct.A*, %struct.A** %retval, align 8
+  ret %struct.A* %1
+}
+
+; Function Attrs: nounwind readnone
+declare dso_local void @llvm.eha.scope.begin() #3
+
+; Function Attrs: nounwind readnone
+declare dso_local void @llvm.eha.scope.end() #3
+
+; Function Attrs: noinline nounwind optnone
+define internal void @"??1A@?1??crash@@YAXH@Z@QEAA@XZ"(%struct.A* %this) unnamed_addr #0 align 2 {
+entry:
+  %this.addr = alloca %struct.A*, align 8
+  store %struct.A* %this, %struct.A** %this.addr, align 8
+  %this1 = load %struct.A*, %struct.A** %this.addr, align 8
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @"??_C@_0N@HMNCGOCN@?5in?5A?5dtor?5?6?$AA@", i64 0, i64 0))
+  ret void
+}
+
+declare dso_local void @"?printf@@YAXZZ"(...) #4
+
+declare dso_local void @_CxxThrowException(i8*, %eh.ThrowInfo*)
+
+; Function Attrs: noinline norecurse optnone
+define dso_local i32 @main() #5 personality i8* bitcast (i32 (...)* @__C_specific_handler to i8*) {
+entry:
+  %retval = alloca i32, align 4
+  %i = alloca i32, align 4
+  %__exception_code = alloca i32, align 4
+  store i32 0, i32* %retval, align 4
+  store i32 0, i32* %i, align 4
+  br label %for.cond
+
+for.cond:                                         ; preds = %for.inc, %entry
+  %0 = load i32, i32* %i, align 4
+  %cmp = icmp slt i32 %0, 2
+  br i1 %cmp, label %for.body, label %for.end
+
+for.body:                                         ; preds = %for.cond
+  invoke void @llvm.seh.try.begin()
+          to label %invoke.cont unwind label %catch.dispatch
+
+invoke.cont:                                      ; preds = %for.body
+  %1 = load volatile i32, i32* %i, align 4
+  invoke void @"?crash@@YAXH@Z"(i32 %1) #8
+          to label %invoke.cont1 unwind label %catch.dispatch
+
+invoke.cont1:                                     ; preds = %invoke.cont
+  invoke void @llvm.seh.try.end()
+          to label %invoke.cont2 unwind label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %invoke.cont1, %invoke.cont, %for.body
+  %2 = catchswitch within none [label %__except] unwind to caller
+
+__except:                                         ; preds = %catch.dispatch
+  %3 = catchpad within %2 [i8* null]
+  catchret from %3 to label %__except3
+
+__except3:                                        ; preds = %__except
+  %4 = call i32 @llvm.eh.exceptioncode(token %3)
+  store i32 %4, i32* %__exception_code, align 4
+  %5 = load i32, i32* %i, align 4
+  call void (...) @"?printf@@YAXZZ"(i8* getelementptr inbounds ([45 x i8], [45 x i8]* @"??_C@_0CN@MKCAOFNA@?5Test?5CPP?5unwind?3?5in?5except?5hand@", i64 0, i64 0), i32 %5)
+  br label %__try.cont
+
+__try.cont:                                       ; preds = %__except3, %invoke.cont2
+  br label %for.inc
+
+for.inc:                                          ; preds = %__try.cont
+  %6 = load i32, i32* %i, align 4
+  %inc = add nsw i32 %6, 1
+  store i32 %inc, i32* %i, align 4
+  br label %for.cond
+
+invoke.cont2:                                     ; preds = %invoke.cont1
+  br label %__try.cont
+
+for.end:                                          ; preds = %for.cond
+  ret i32 0
+}
+
+declare dso_local i32 @__C_specific_handler(...)
+
+; Function Attrs: nounwind willreturn
+declare dso_local void @llvm.seh.try.end() #2
+
+; Function Attrs: nounwind readnone
+declare i32 @llvm.eh.exceptioncode(token) #3
+
+attributes #0 = { noinline nounwind optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #1 = { noinline optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #2 = { nounwind willreturn }
+attributes #3 = { nounwind readnone }
+attributes #4 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #5 = { noinline norecurse optnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-features"="+cx8,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" }
+attributes #6 = { nounwind }
+attributes #7 = { noreturn }
+attributes #8 = { noinline }
+
+!llvm.module.flags = !{!0, !1}
+!llvm.ident = !{!2}
+
+!0 = !{i32 1, !"wchar_size", i32 2}
+!1 = !{i32 2, !"eh-asynch", i32 1}
+!2 = !{!"clang version 11.0.0 (https://github.com/llvm/llvm-project 7ee479a760e0a4402b4eb7fb6168768a44f66945)"}
+
Index: llvm/lib/IR/Verifier.cpp
===================================================================
--- llvm/lib/IR/Verifier.cpp
+++ llvm/lib/IR/Verifier.cpp
@@ -4223,6 +4223,10 @@
       Assert(
           !F->isIntrinsic() || isa<CallInst>(I) ||
               F->getIntrinsicID() == Intrinsic::donothing ||
+              F->getIntrinsicID() == Intrinsic::seh_try_begin ||
+              F->getIntrinsicID() == Intrinsic::seh_try_end ||
+              F->getIntrinsicID() == Intrinsic::eha_scope_begin ||
+              F->getIntrinsicID() == Intrinsic::eha_scope_end ||
               F->getIntrinsicID() == Intrinsic::coro_resume ||
               F->getIntrinsicID() == Intrinsic::coro_destroy ||
               F->getIntrinsicID() == Intrinsic::experimental_patchpoint_void ||
Index: llvm/lib/IR/BasicBlock.cpp
===================================================================
--- llvm/lib/IR/BasicBlock.cpp
+++ llvm/lib/IR/BasicBlock.cpp
@@ -211,6 +211,16 @@
   return BB->getTerminatingDeoptimizeCall();
 }
 
+const Instruction* BasicBlock::getFirstFaultyInst() const {
+  if (InstList.empty())
+    return nullptr;
+  for (const Instruction& I : *this)
+    if (isa<LoadInst>(I) || isa<StoreInst>(I) ||
+      isa<CallInst>(I))
+      return &I;
+  return nullptr;
+}
+
 const Instruction* BasicBlock::getFirstNonPHI() const {
   for (const Instruction &I : *this)
     if (!isa<PHINode>(I))
Index: llvm/lib/CodeGen/WinEHPrepare.cpp
===================================================================
--- llvm/lib/CodeGen/WinEHPrepare.cpp
+++ llvm/lib/CodeGen/WinEHPrepare.cpp
@@ -215,6 +215,98 @@
   }
 }
 
+// See comments below for calculateSEHStateForBlocks().
+// State - incoming State of normal paths
+void llvm::calculateCXXStateForBlocks(const BasicBlock* BB, int State,
+  WinEHFuncInfo& EHInfo)
+{
+  if (EHInfo.BlockToStateMap.count(BB) && EHInfo.BlockToStateMap[BB] <= State)
+    return;  // skip already visited or EHPad
+
+  const llvm::Instruction* I = BB->getFirstNonPHI();
+  const llvm::Instruction* TI = BB->getTerminator();
+  if (I->isEHPad())
+    State = EHInfo.EHPadStateMap[I];
+  EHInfo.BlockToStateMap[BB] = State;  // Record state, also flag visiting
+
+  if ((isa<CleanupReturnInst>(TI) || isa<CatchReturnInst>(TI)) &&
+    State > 0) {
+    // Retrive the new State
+    State = EHInfo.CxxUnwindMap[State].ToState;  // Retrive next State
+  }
+  else if (isa<InvokeInst>(TI)) {
+    auto *Call = dyn_cast<CallBase>(TI);
+    const Function *Fn = Call->getCalledFunction();
+    if (Fn && Fn->isIntrinsic() &&
+      (Fn->getIntrinsicID() == Intrinsic::eha_scope_begin ||
+        Fn->getIntrinsicID() == Intrinsic::seh_try_begin))
+      // Retrive the new State from eha_scope_begin
+      State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)];
+    else if (Fn && Fn->isIntrinsic() &&
+      (Fn->getIntrinsicID() == Intrinsic::eha_scope_end ||
+        Fn->getIntrinsicID() == Intrinsic::seh_try_end))
+      // end of current state, retrive new state from UnwindMap
+      State = EHInfo.CxxUnwindMap[State].ToState;
+  }
+  // Continue traveling successors recursively
+  for (auto* SuccBB : successors(BB)) {
+    calculateCXXStateForBlocks(SuccBB, State, EHInfo);
+  }
+}
+
+// The central theory of this routine is based on the following:
+//   A _try scope is always a SEME (Single Entry Multiple Exits) region
+//     as jumping into a _try is not allowed
+//   The single entry must start with a seh_try_begin() invoke with a
+//     correct State number that is the initial state of the SEME.
+//   Through control-flow, state number is propagated into all blocks.
+//   Side exits marked by seh_try_end() will unwind to parent state via
+//     existing SEHUnwindMap[].
+//   Side exits can ONLY jump into parent scopes (lower state number).
+//   Thus, when a block succeeds various states from its predecessors,
+//     the lowest State triumphs others.
+//   If some exits flow to unreachable, propagation on those paths terminate,
+//     not affecting remaining blocks.
+void llvm::calculateSEHStateForBlocks(const BasicBlock* BB, int State,
+  WinEHFuncInfo& EHInfo)
+{
+  if (EHInfo.BlockToStateMap.count(BB) && EHInfo.BlockToStateMap[BB] <= State)
+    return;  // skip already visited by lower State
+
+  const llvm::Instruction* I = BB->getFirstNonPHI();
+  const llvm::Instruction* TI = BB->getTerminator();
+  if (I->isEHPad())
+    State = EHInfo.EHPadStateMap[I];
+  EHInfo.BlockToStateMap[BB] = State;  // Record state
+
+  if (isa<CatchPadInst>(I) && isa<CatchReturnInst>(TI)) {
+    const Constant* FilterOrNull =
+      cast<Constant>(cast<CatchPadInst>(I)->getArgOperand(0)->stripPointerCasts());
+    const Function* Filter = dyn_cast<Function>(FilterOrNull);
+    if (!Filter || !Filter->getName().startswith("__IsLocalUnwind"))
+      State = EHInfo.SEHUnwindMap[State].ToState;  // Retrive next State
+  }
+  else if ((isa<CleanupReturnInst>(TI) || isa<CatchReturnInst>(TI)) &&
+    State > 0) {
+    // Retrive the new State.
+    State = EHInfo.SEHUnwindMap[State].ToState;  // Retrive next State
+  }
+  else if (isa<InvokeInst>(TI)) {
+    auto *Call = dyn_cast<CallBase>(TI);
+    const Function *Fn = Call->getCalledFunction();
+    if (Fn && Fn->isIntrinsic() && Fn->getIntrinsicID() == Intrinsic::seh_try_begin)
+      // Retrive the new State from seh_try_begin
+      State = EHInfo.InvokeStateMap[cast<InvokeInst>(TI)];
+    else if (Fn && Fn->isIntrinsic() && Fn->getIntrinsicID() == Intrinsic::seh_try_end)
+      // end of current state, retrive new state from UnwindMap
+      State = EHInfo.SEHUnwindMap[State].ToState;
+  }
+  // Continue traveling successors recursively
+  for (auto* SuccBB : successors(BB)) {
+    calculateSEHStateForBlocks(SuccBB, State, EHInfo);
+  }
+}
+
 // Given BB which ends in an unwind edge, return the EHPad that this BB belongs
 // to. If the unwind edge came from an invoke, return null.
 static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB,
@@ -275,6 +367,7 @@
 
     for (const auto *CatchPad : Handlers) {
       FuncInfo.FuncletBaseStateMap[CatchPad] = CatchLow;
+      FuncInfo.EHPadStateMap[CatchPad] = CatchLow;
       for (const User *U : CatchPad->users()) {
         const auto *UserI = cast<Instruction>(U);
         if (auto *InnerCatchSwitch = dyn_cast<CatchSwitchInst>(UserI)) {
@@ -383,6 +476,7 @@
 
     // Everything in the __try block uses TryState as its parent state.
     FuncInfo.EHPadStateMap[CatchSwitch] = TryState;
+    FuncInfo.EHPadStateMap[CatchPad] = TryState;
     LLVM_DEBUG(dbgs() << "Assigning state #" << TryState << " to BB "
                       << CatchPadBB->getName() << '\n');
     for (const BasicBlock *PredBlock : predecessors(BB))
@@ -463,6 +557,12 @@
   }
 
   calculateStateNumbersForInvokes(Fn, FuncInfo);
+
+  bool IsEHa = Fn->getParent()->getModuleFlag("eh-asynch");
+  if (IsEHa) {
+    const BasicBlock* EntryBB = &(Fn->getEntryBlock());
+    calculateSEHStateForBlocks(EntryBB, -1, FuncInfo);
+  }
 }
 
 void llvm::calculateWinCXXEHStateNumbers(const Function *Fn,
@@ -481,6 +581,12 @@
   }
 
   calculateStateNumbersForInvokes(Fn, FuncInfo);
+
+  bool IsEHa = Fn->getParent()->getModuleFlag("eh-asynch");
+  if (IsEHa) {
+    const BasicBlock* EntryBB = &(Fn->getEntryBlock());
+    calculateCXXStateForBlocks(EntryBB, -1, FuncInfo);
+  }
 }
 
 static int addClrEHHandler(WinEHFuncInfo &FuncInfo, int HandlerParentState,
@@ -1267,4 +1373,8 @@
   LabelToStateMap[InvokeBegin] = std::make_pair(InvokeStateMap[II], InvokeEnd);
 }
 
+void WinEHFuncInfo::addIPToStateRange(int State, MCSymbol* InvokeBegin,
+  MCSymbol* InvokeEnd) {
+  LabelToStateMap[InvokeBegin] = std::make_pair(State, InvokeEnd);
+}
 WinEHFuncInfo::WinEHFuncInfo() {}
Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
===================================================================
--- llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
+++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
@@ -58,6 +58,7 @@
 #include "llvm/CodeGen/TargetRegisterInfo.h"
 #include "llvm/CodeGen/TargetSubtargetInfo.h"
 #include "llvm/CodeGen/ValueTypes.h"
+#include "llvm/CodeGen/WinEHFuncInfo.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
@@ -1295,6 +1296,39 @@
   return true;
 }
 
+// Mark and Report IPToState for each Block under IsEHa
+void SelectionDAGISel::ReportIPToStateForBlocks(MachineFunction * MF)
+{
+  MachineModuleInfo & MMI = MF->getMMI();
+  llvm::WinEHFuncInfo * EHInfo = MF->getWinEHFuncInfo();
+  if (!EHInfo)
+    return;
+  for (auto MBBI = MF->begin(); MBBI != MF->end(); ++MBBI) {
+    MachineBasicBlock * MBB = &*MBBI;
+    const BasicBlock * BB = MBB->getBasicBlock();
+    int State = EHInfo->BlockToStateMap[BB];
+    if (BB->getFirstFaultyInst()) {
+      // Report IP range only for blocks with Faulty inst
+      MCSymbol * BeginLabel = MMI.getContext().createTempSymbol();
+      MCSymbol * EndLabel = MMI.getContext().createTempSymbol();
+      EHInfo->addIPToStateRange(State, BeginLabel, EndLabel);
+
+      // Insert EH Labels
+      auto MBBb = MBB->getFirstNonPHI();
+      BuildMI(*MBB, MBBb, SDB->getCurDebugLoc(),
+        TII->get(TargetOpcode::EH_LABEL)).addSym(BeginLabel);
+      auto MBBe = MBB->instr_end();
+      MachineInstr * MIb = &*(--MBBe);
+      // insert before (possible multiple) terminators
+      while (MIb->isTerminator())
+        MIb = &*(--MBBe);
+      ++MBBe;
+      BuildMI(*MBB, MBBe, SDB->getCurDebugLoc(),
+        TII->get(TargetOpcode::EH_LABEL)).addSym(EndLabel);
+    }
+  }
+}
+
 /// isFoldedOrDeadInstruction - Return true if the specified instruction is
 /// side-effect free and is either dead or folded into a generated instruction.
 /// Return false if it needs to be emitted.
@@ -1624,6 +1658,10 @@
     ElidedArgCopyInstrs.clear();
   }
 
+  // IsEHa: Report Block State under -EHa
+  if (Fn.getParent()->getModuleFlag("eh-asynch"))
+    ReportIPToStateForBlocks(MF);
+
   SP.copyToMachineFrameInfo(MF->getFrameInfo());
 
   SwiftError->propagateVRegs();
Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
===================================================================
--- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -2771,6 +2771,7 @@
   // catchswitch for successors.
   MachineBasicBlock *Return = FuncInfo.MBBMap[I.getSuccessor(0)];
   const BasicBlock *EHPadBB = I.getSuccessor(1);
+  MachineBasicBlock* CleanupMBB = FuncInfo.MBBMap[EHPadBB];
 
   // Deopt bundles are lowered in LowerCallSiteWithDeoptBundle, and we don't
   // have to do anything here to lower funclet bundles.
@@ -2789,6 +2790,12 @@
       llvm_unreachable("Cannot invoke this intrinsic");
     case Intrinsic::donothing:
       // Ignore invokes to @llvm.donothing: jump directly to the next BB.
+    case Intrinsic::seh_try_begin:
+    case Intrinsic::eha_scope_begin:
+    case Intrinsic::seh_try_end:
+    case Intrinsic::eha_scope_end:
+      if (CleanupMBB) // a CleanupPad, referenced by EH table
+        CleanupMBB->setHasAddressTaken(); // so dtor-funclet not removed by opts
       break;
     case Intrinsic::experimental_patchpoint_void:
     case Intrinsic::experimental_patchpoint_i64:
@@ -6583,6 +6590,10 @@
       lowerCallToExternalSymbol(I, FunctionName);
     return;
   case Intrinsic::donothing:
+  case Intrinsic::seh_try_begin:
+  case Intrinsic::eha_scope_begin:
+  case Intrinsic::seh_try_end:
+  case Intrinsic::eha_scope_end:
     // ignore
     return;
   case Intrinsic::experimental_stackmap:
Index: llvm/lib/CodeGen/BranchFolding.cpp
===================================================================
--- llvm/lib/CodeGen/BranchFolding.cpp
+++ llvm/lib/CodeGen/BranchFolding.cpp
@@ -1206,7 +1206,7 @@
     MadeChange |= OptimizeBlock(MBB);
 
     // If it is dead, remove it.
-    if (MBB->pred_empty()) {
+    if (MBB->pred_empty() && !MBB->hasAddressTaken()) {
       RemoveDeadBlock(MBB);
       MadeChange = true;
       ++NumDeadBlocks;
Index: llvm/lib/CodeGen/AsmPrinter/WinException.cpp
===================================================================
--- llvm/lib/CodeGen/AsmPrinter/WinException.cpp
+++ llvm/lib/CodeGen/AsmPrinter/WinException.cpp
@@ -746,7 +746,10 @@
   OS.emitInt32(0);
 
   AddComment("EHFlags");
-  OS.emitInt32(1);
+  if (MMI->getModule()->getModuleFlag("eh-asynch"))
+    OS.emitInt32(0); // -EHa
+  else
+    OS.emitInt32(1);
 
   // UnwindMapEntry {
   //   int32_t ToState;
Index: llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
===================================================================
--- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -1104,7 +1104,7 @@
   // Print out code for the function.
   bool HasAnyRealCode = false;
   int NumInstsInFunction = 0;
-
+  bool IsEHa = MMI->getModule()->getModuleFlag("eh-asynch");
   for (auto &MBB : *MF) {
     // Print a label for the basic block.
     emitBasicBlockStart(MBB);
@@ -1140,10 +1140,24 @@
         emitFrameAlloc(MI);
         break;
       case TargetOpcode::ANNOTATION_LABEL:
-      case TargetOpcode::EH_LABEL:
       case TargetOpcode::GC_LABEL:
         OutStreamer->emitLabel(MI.getOperand(0).getMCSymbol());
         break;
+      case TargetOpcode::EH_LABEL:
+        OutStreamer->emitLabel(MI.getOperand(0).getMCSymbol());
+        // For IsEHa, insert a Nop if followed by a trap inst
+        //   Or the exception won't be caught.
+        //   (see MCConstantExpr::create(1,..) in WinException.cpp)
+        //  Ignore SDiv/UDiv bcause a DIV with Const-0 divisor
+        //    must have being turned into an UndefValue.
+        //  Div with variable opnds must be led by at least a Load
+        {
+          auto MI2 = std::next(MI.getIterator());
+          if (IsEHa && MI2 != MBB.end()
+                    && (MI2->mayLoadOrStore() || MI2->mayRaiseFPException()))
+            emitNops(1);
+        }
+        break;
       case TargetOpcode::INLINEASM:
       case TargetOpcode::INLINEASM_BR:
         emitInlineAsm(&MI);
Index: llvm/lib/Analysis/EHPersonalities.cpp
===================================================================
--- llvm/lib/Analysis/EHPersonalities.cpp
+++ llvm/lib/Analysis/EHPersonalities.cpp
@@ -11,6 +11,7 @@
 #include "llvm/IR/CFG.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
@@ -71,7 +72,11 @@
   // We can't simplify any invokes to nounwind functions if the personality
   // function wants to catch asynch exceptions.  The nounwind attribute only
   // implies that the function does not throw synchronous exceptions.
-  return !isAsynchronousEHPersonality(Personality);
+
+  // Cannot simplify CXX Personality under EHa
+  llvm::Module *M = (llvm::Module*) F->getParent();
+  bool EHa = M->getModuleFlag("eh-asynch");
+  return !isAsynchronousEHPersonality(Personality) && !EHa;
 }
 
 DenseMap<BasicBlock *, ColorVector> llvm::colorEHFunclets(Function &F) {
Index: llvm/include/llvm/IR/Intrinsics.td
===================================================================
--- llvm/include/llvm/IR/Intrinsics.td
+++ llvm/include/llvm/IR/Intrinsics.td
@@ -456,6 +456,16 @@
                                  [llvm_ptr_ty, llvm_ptr_ty],
                                  [IntrNoMem]>;
 
+// To mark the beginning/end of a try-scope for Windows SEH -EHa
+//  calls/invokes to these intrinsics are placed to model control flows
+//    caused by HW exceptions under option -EHa.
+//  calls/invokes to these intrinsics will be discarded during a codegen pass
+//   after EH tables are generated
+def int_seh_try_begin : Intrinsic<[], [], [IntrReadMem, IntrWriteMem, IntrWillReturn]>;
+def int_seh_try_end : Intrinsic<[], [], [IntrReadMem, IntrWriteMem, IntrWillReturn]>;
+def int_eha_scope_begin : Intrinsic<[], [], [IntrNoMem]>;
+def int_eha_scope_end : Intrinsic<[], [], [IntrNoMem]>;
+
 // Note: we treat stacksave/stackrestore as writemem because we don't otherwise
 // model their dependencies on allocas.
 def int_stacksave     : Intrinsic<[llvm_ptr_ty]>,
Index: llvm/include/llvm/IR/BasicBlock.h
===================================================================
--- llvm/include/llvm/IR/BasicBlock.h
+++ llvm/include/llvm/IR/BasicBlock.h
@@ -189,6 +189,13 @@
                                           ->getFirstInsertionPt().getNonConst();
   }
 
+  /// Returns the first potential -EHa faulty instruction
+  const Instruction * getFirstFaultyInst() const;
+  Instruction * getFirstFaultyInst() {
+    return const_cast<Instruction*>(
+      static_cast<const BasicBlock*>(this)->getFirstFaultyInst());
+  }
+
   /// Return a const iterator range over the instructions in the block, skipping
   /// any debug instructions.
   iterator_range<filter_iterator<BasicBlock::const_iterator,
Index: llvm/include/llvm/CodeGen/WinEHFuncInfo.h
===================================================================
--- llvm/include/llvm/CodeGen/WinEHFuncInfo.h
+++ llvm/include/llvm/CodeGen/WinEHFuncInfo.h
@@ -92,6 +92,7 @@
   DenseMap<const FuncletPadInst *, int> FuncletBaseStateMap;
   DenseMap<const InvokeInst *, int> InvokeStateMap;
   DenseMap<MCSymbol *, std::pair<int, MCSymbol *>> LabelToStateMap;
+  DenseMap<const BasicBlock*, int> BlockToStateMap; // for IsEHa
   SmallVector<CxxUnwindMapEntry, 4> CxxUnwindMap;
   SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
   SmallVector<SEHUnwindMapEntry, 4> SEHUnwindMap;
@@ -104,6 +105,9 @@
   void addIPToStateRange(const InvokeInst *II, MCSymbol *InvokeBegin,
                          MCSymbol *InvokeEnd);
 
+  void addIPToStateRange(int State, MCSymbol * InvokeBegin,
+    MCSymbol * InvokeEnd);
+
   int EHRegNodeFrameIndex = std::numeric_limits<int>::max();
   int EHRegNodeEndOffset = std::numeric_limits<int>::max();
   int EHGuardFrameIndex = std::numeric_limits<int>::max();
@@ -122,6 +126,9 @@
                               WinEHFuncInfo &FuncInfo);
 
 void calculateClrEHStateNumbers(const Function *Fn, WinEHFuncInfo &FuncInfo);
+// For IsEHa
+void calculateCXXStateForBlocks(const BasicBlock * BB, int State, WinEHFuncInfo & FuncInfo);
+void calculateSEHStateForBlocks(const BasicBlock * BB, int State, WinEHFuncInfo & FuncInfo);
 
 } // end namespace llvm
 
Index: llvm/include/llvm/CodeGen/SelectionDAGISel.h
===================================================================
--- llvm/include/llvm/CodeGen/SelectionDAGISel.h
+++ llvm/include/llvm/CodeGen/SelectionDAGISel.h
@@ -330,6 +330,9 @@
   /// instruction selected, false if no code should be emitted for it.
   bool PrepareEHLandingPad();
 
+  // Mark and Report IPToState for each Block under IsEHa
+  void ReportIPToStateForBlocks(MachineFunction * Fn);
+
   /// Perform instruction selection on all basic blocks in the function.
   void SelectAllBasicBlocks(const Function &Fn);
 
Index: clang/test/CodeGen/windows-seh-EHa-TryInFinally.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/windows-seh-EHa-TryInFinally.cpp
@@ -0,0 +1,45 @@
+// RUN: %clang_cc1 -triple x86_64-windows -feh-asynch -fcxx-exceptions -fexceptions -fms-extensions -x c++ -Wno-implicit-function-declaration -S -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: invoke void @llvm.seh.try.begin()
+// CHECK: invoke void @llvm.seh.try.begin()
+// CHECK: %[[src:[0-9-]+]] = load volatile i32, i32* %i
+// CHECK-NEXT: i32 %[[src]]
+// CHECK: invoke void @llvm.seh.try.end()
+// CHECK: invoke void @llvm.seh.try.end()
+
+// CHECK: define internal void @"?fin$0@0@main@@"(i8 %abnormal_termination
+// CHECK: invoke void @llvm.seh.try.begin()
+// CHECK: invoke void @llvm.seh.try.end()
+
+// *****************************************************************************
+// Abstract:     Test __Try in __finally under SEH -EHa option
+void printf(...);
+int main() {
+  for (int i = 0; i < 3; i++) {
+    printf(" --- Test _Try in _finally --- i = %d \n", i);
+    __try {
+      __try {
+        printf("  In outer _try i = %d \n", i);
+        if (i == 0)
+          *(volatile int*)0x11 = 0;
+      }
+      __finally {
+        __try {
+          printf("  In outer _finally i = %d \n", i);
+          if (i == 1)
+            *(volatile int*)0x11 = 0;
+        }
+        __finally {
+          printf("  In Inner _finally i = %d \n", i);
+          if (i == 2)
+            *(volatile int*)0x11 = 0;
+        }
+      }
+    }
+    __except(1) {
+        printf(" --- In outer except handler i = %d \n", i);
+    }
+  }
+  return 0;
+}
+
Index: clang/test/CodeGen/windows-seh-EHa-CppDtors01.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/windows-seh-EHa-CppDtors01.cpp
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 -triple x86_64-windows -feh-asynch -fcxx-exceptions -fexceptions -fms-extensions -x c++ -Wno-implicit-function-declaration -S -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: invoke void @llvm.eha.scope.begin()
+// CHECK: invoke void @llvm.eha.scope.begin()
+// CHECK: invoke void @llvm.eha.scope.begin()
+// CHECK: invoke void @llvm.eha.scope.end()
+// CHECK: invoke void @llvm.eha.scope.end()
+// CHECK: invoke void @llvm.eha.scope.end()
+
+// CHECK: invoke void @llvm.seh.try.begin()
+// CHECK: %[[src:[0-9-]+]] = load volatile i32, i32* %i
+// CHECK-NEXT: invoke void @"?crash@@YAXH@Z"(i32 %[[src]])
+// CHECK: invoke void @llvm.seh.try.end()
+
+// ****************************************************************************
+// Abstract:     Test CPP unwind Dtoring under SEH -EHa option
+
+void printf(...);
+
+void crash(int i) {
+  struct A {
+    ~A() {
+      printf(" in A dtor \n");
+    }
+  } ObjA;
+  if (i == 0)
+    *(volatile int*)0x11 = 0;
+
+  struct B {
+    ~B() {
+      printf(" in B dtor \n");
+    }
+  } ObjB;
+  if (i == 1)
+    *(volatile int*)0x11 = 0;
+
+  struct C {
+    ~C() {
+      printf(" in C dtor \n");
+    }
+  } ObjC;
+  if (i == 2)
+    *(volatile int*)0x11 = 0;
+
+}
+
+#define TRY __try
+#define CATCH_ALL __except (1)
+
+int g;
+int main() {
+  for (int i = 0; i < 3; i++) {
+    TRY {
+      crash(i);
+    }
+    CATCH_ALL{
+        printf(" Test CPP unwind: in catch handler i = %d \n", i);
+    }
+  }
+  return 0;
+}
+
Index: clang/test/CodeGen/windows-seh-EHa-CppCatchDotDotDot.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/windows-seh-EHa-CppCatchDotDotDot.cpp
@@ -0,0 +1,63 @@
+// RUN: %clang_cc1 -triple x86_64-windows -feh-asynch -fcxx-exceptions -fexceptions -fms-extensions -x c++ -Wno-implicit-function-declaration -S -emit-llvm %s -o - | FileCheck %s
+
+// CHECK: define dso_local void @"?crash@@YAXH@Z
+// CHECK: invoke void @llvm.seh.try.begin()
+// CHECK: invoke void @llvm.eha.scope.begin()
+// CHECK: invoke void @llvm.eha.scope.end()
+
+// CHECK: %[[dst:[0-9-]+]] = catchswitch within none [label %catch] unwind to caller
+// CHECK: %[[dst1:[0-9-]+]] = catchpad within %[[dst]] [i8* null, i32 0, i8* null]
+// CHECK: "funclet"(token %[[dst1]])
+
+// CHECK: invoke void @llvm.seh.try.begin()
+// CHECK: %[[src:[0-9-]+]] = load volatile i32, i32* %i
+// CHECK-NEXT: invoke void @"?crash@@YAXH@Z"(i32 %[[src]])
+// CHECK: invoke void @llvm.seh.try.end()
+
+// *****************************************************************************
+// Abstract:     Test CPP catch(...) under SEH -EHa option
+
+void printf(...);
+
+void foo() {
+  *(volatile int*)0x11 = 0;
+}
+int *pt1, *pt2, *pt3;
+int g;
+void crash(int i) {
+  g = i;
+  try 
+  {
+    struct A {
+      A() {
+        printf(" in A ctor \n");
+        if (g == 0)
+          *(volatile int*)0x11 = 0;
+      }
+      ~A() {
+        printf(" in A dtor \n");
+      }
+    } ObjA;
+    if (i == 1)
+      *(volatile int*)0x11 = 0;
+  }
+  catch (...) 
+  {
+    printf(" in catch(...) funclet \n");
+    if (i == 1)
+      throw(i);
+  }
+}
+
+int main() {
+  for (int i = 0; i < 2; i++) {
+    __try {
+      crash(i);
+    }
+    __except(1) {
+        printf(" Test CPP unwind: in except handler i = %d \n", i);
+    }
+  }
+  return 0;
+}
+
Index: clang/lib/Sema/JumpDiagnostics.cpp
===================================================================
--- clang/lib/Sema/JumpDiagnostics.cpp
+++ clang/lib/Sema/JumpDiagnostics.cpp
@@ -930,6 +930,9 @@
   if (!ToScopesWarning.empty()) {
     S.Diag(DiagLoc, JumpDiagWarning);
     NoteJumpIntoScopes(ToScopesWarning);
+    assert(isa<LabelStmt>(To));
+    LabelStmt* Label = cast<LabelStmt>(To);
+    Label->setSideEntry();
   }
 
   // Handle errors.
Index: clang/lib/Frontend/CompilerInvocation.cpp
===================================================================
--- clang/lib/Frontend/CompilerInvocation.cpp
+++ clang/lib/Frontend/CompilerInvocation.cpp
@@ -2783,6 +2783,7 @@
   Opts.IgnoreExceptions = Args.hasArg(OPT_fignore_exceptions);
   Opts.ObjCExceptions = Args.hasArg(OPT_fobjc_exceptions);
   Opts.CXXExceptions = Args.hasArg(OPT_fcxx_exceptions);
+  Opts.EHAsynch = Args.hasArg(OPT_feh_asynch);
 
   // -ffixed-point
   Opts.FixedPoint =
Index: clang/lib/Driver/ToolChains/Clang.cpp
===================================================================
--- clang/lib/Driver/ToolChains/Clang.cpp
+++ clang/lib/Driver/ToolChains/Clang.cpp
@@ -426,6 +426,7 @@
     Args.ClaimAllArgs(options::OPT_fobjc_exceptions);
     Args.ClaimAllArgs(options::OPT_fno_objc_exceptions);
     Args.ClaimAllArgs(options::OPT_fcxx_exceptions);
+    Args.ClaimAllArgs(options::OPT_feh_asynch);
     Args.ClaimAllArgs(options::OPT_fno_cxx_exceptions);
     return;
   }
@@ -434,6 +435,12 @@
   bool EH = Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions,
                          false);
 
+  bool EHa = Args.hasFlag(options::OPT_feh_asynch, options::OPT_fno_eh_asynch, false);
+  if (EHa) {
+    CmdArgs.push_back("-feh-asynch");
+    EH = true;
+  }
+
   // Obj-C exceptions are enabled by default, regardless of -fexceptions. This
   // is not necessarily sensible, but follows GCC.
   if (types::isObjC(InputType) &&
@@ -6572,7 +6579,10 @@
     if (types::isCXX(InputType))
       CmdArgs.push_back("-fcxx-exceptions");
     CmdArgs.push_back("-fexceptions");
+    if (EH.Asynch)
+      CmdArgs.push_back("-feh-asynch");
   }
+
   if (types::isCXX(InputType) && EH.Synch && EH.NoUnwindC)
     CmdArgs.push_back("-fexternc-nounwind");
 
Index: clang/lib/CodeGen/CodeGenModule.cpp
===================================================================
--- clang/lib/CodeGen/CodeGenModule.cpp
+++ clang/lib/CodeGen/CodeGenModule.cpp
@@ -597,6 +597,10 @@
                                   llvm::DenormalMode::IEEE);
   }
 
+  if (LangOpts.EHAsynch) {
+    getModule().addModuleFlag(llvm::Module::Warning, "eh-asynch", 1);
+  }
+
   // Emit OpenCL specific module metadata: OpenCL/SPIR version.
   if (LangOpts.OpenCL) {
     EmitOpenCLMetadata();
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -2687,6 +2687,11 @@
   void EmitCXXTemporary(const CXXTemporary *Temporary, QualType TempType,
                         Address Ptr);
 
+  void CodeGenFunction::EmitSehCppScopeBegin();
+  void CodeGenFunction::EmitSehCppScopeEnd();
+  void CodeGenFunction::EmitSehTryScopeBegin();
+  void CodeGenFunction::EmitSehTryScopeEnd();
+
   llvm::Value *EmitLifetimeStart(uint64_t Size, llvm::Value *Addr);
   void EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr);
 
@@ -3037,6 +3042,7 @@
   void EmitSEHLeaveStmt(const SEHLeaveStmt &S);
   void EnterSEHTryStmt(const SEHTryStmt &S);
   void ExitSEHTryStmt(const SEHTryStmt &S);
+  void VolatilizeTryBlocks(llvm::BasicBlock* BB, llvm::SmallPtrSet<llvm::BasicBlock*, 10>& V);
 
   void pushSEHCleanup(CleanupKind kind,
                       llvm::Function *FinallyFunc);
Index: clang/lib/CodeGen/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ clang/lib/CodeGen/CGStmt.cpp
@@ -604,6 +604,11 @@
 
 void CodeGenFunction::EmitLabelStmt(const LabelStmt &S) {
   EmitLabel(S.getDecl());
+
+  // IsEHa - emit eha.scope.begin if it's a side entry of a scope
+  if (getLangOpts().EHAsynch && S.IsSideEntry())
+    EmitSehCppScopeBegin();
+
   EmitStmt(S.getSubStmt());
 }
 
Index: clang/lib/CodeGen/CGException.cpp
===================================================================
--- clang/lib/CodeGen/CGException.cpp
+++ clang/lib/CodeGen/CGException.cpp
@@ -38,6 +38,18 @@
   return CGM.CreateRuntimeFunction(FTy, "__cxa_free_exception");
 }
 
+static llvm::FunctionCallee getSehTryBeginFn(CodeGenModule & CGM) {
+  llvm::FunctionType * FTy =
+    llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+  return CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.begin");
+}
+
+static llvm::FunctionCallee getSehTryEndFn(CodeGenModule & CGM) {
+  llvm::FunctionType * FTy =
+    llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+  return CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end");
+}
+
 static llvm::FunctionCallee getUnexpectedFn(CodeGenModule &CGM) {
   // void __cxa_call_unexpected(void *thrown_exception);
 
@@ -450,7 +462,7 @@
   if (!FD) {
     // Check if CapturedDecl is nothrow and create terminate scope for it.
     if (const CapturedDecl* CD = dyn_cast_or_null<CapturedDecl>(D)) {
-      if (CD->isNothrow())
+      if (CD->isNothrow() && !getLangOpts().EHAsynch /* !IsEHa */)
         EHStack.pushTerminate();
     }
     return;
@@ -462,7 +474,8 @@
   ExceptionSpecificationType EST = Proto->getExceptionSpecType();
   if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot) {
     // noexcept functions are simple terminate scopes.
-    EHStack.pushTerminate();
+    if (!getLangOpts().EHAsynch) // -EHa: HW exception still can occur
+      EHStack.pushTerminate();
   } else if (EST == EST_Dynamic || EST == EST_DynamicNone) {
     // TODO: Revisit exception specifications for the MS ABI.  There is a way to
     // encode these in an object file but MSVC doesn't do anything with it.
@@ -527,7 +540,7 @@
   if (!FD) {
     // Check if CapturedDecl is nothrow and pop terminate scope for it.
     if (const CapturedDecl* CD = dyn_cast_or_null<CapturedDecl>(D)) {
-      if (CD->isNothrow())
+      if (CD->isNothrow() && !EHStack.empty())
         EHStack.popTerminate();
     }
     return;
@@ -537,7 +550,8 @@
     return;
 
   ExceptionSpecificationType EST = Proto->getExceptionSpecType();
-  if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot) {
+  if (isNoexceptExceptionSpec(EST) && Proto->canThrow() == CT_Cannot &&
+    !EHStack.empty() /* possible empty when -EHa */) {
     EHStack.popTerminate();
   } else if (EST == EST_Dynamic || EST == EST_DynamicNone) {
     // TODO: Revisit exception specifications for the MS ABI.  There is a way to
@@ -584,7 +598,16 @@
       CatchScope->setHandler(I, TypeInfo, Handler);
     } else {
       // No exception decl indicates '...', a catch-all.
-      CatchScope->setHandler(I, CGM.getCXXABI().getCatchAllTypeInfo(), Handler);
+      CatchTypeInfo TypeInfo = CGM.getCXXABI().getCatchAllTypeInfo();
+
+      //  For IsEHa catch(...) must handle HW exception
+      //  Adjective = HT_IsStdDotDot (0x40), only catch C++ exceptions
+      //  Also mark scope with SehTryBegin
+      if (getLangOpts().EHAsynch) {
+        TypeInfo.Flags = 0;
+        EmitRuntimeCallOrInvoke(getSehTryBeginFn(CGM));
+      }
+      CatchScope->setHandler(I, TypeInfo, Handler);
     }
   }
 }
@@ -706,7 +729,7 @@
   // If exceptions are disabled/ignored and SEH is not in use, then there is no
   // invoke destination. SEH "works" even if exceptions are off. In practice,
   // this means that C++ destructors and other EH cleanups don't run, which is
-  // consistent with MSVC's behavior.
+  // consistent with MSVC's behavior, except in the presence of -EHa
   const LangOptions &LO = CGM.getLangOpts();
   if (!LO.Exceptions || LO.IgnoreExceptions) {
     if (!LO.Borland && !LO.MicrosoftExt)
@@ -1602,7 +1625,23 @@
     JumpDest TryExit = getJumpDestInCurrentScope("__try.__leave");
 
     SEHTryEpilogueStack.push_back(&TryExit);
+
+    llvm::BasicBlock* TryBB = nullptr;
+    // IsEHa: emit an invoke to _seh_try_begin() runtime for -EHa
+    if (getLangOpts().EHAsynch) {
+      EmitRuntimeCallOrInvoke(getSehTryBeginFn(CGM));
+      if (SEHTryEpilogueStack.size() == 1) // outermost only
+        TryBB = Builder.GetInsertBlock();
+    }
+
     EmitStmt(S.getTryBlock());
+
+    // Volatilize all blocks in Try, till current insert point
+    if (TryBB) {
+      llvm::SmallPtrSet<llvm::BasicBlock*, 10> Visited;
+      VolatilizeTryBlocks(TryBB, Visited);
+    }
+
     SEHTryEpilogueStack.pop_back();
 
     if (!TryExit.getBlock()->use_empty())
@@ -1613,6 +1652,41 @@
   ExitSEHTryStmt(S);
 }
 
+//  Recursively walk through blocks in a _try
+//      and make all memory instructions volatile
+void CodeGenFunction::VolatilizeTryBlocks(llvm::BasicBlock* BB,
+  llvm::SmallPtrSet<llvm::BasicBlock*, 10>& V)
+{
+  if (BB == SEHTryEpilogueStack.back()->getBlock() /* end of Try */ ||
+    !V.insert(BB).second /* already visited */ ||
+    !BB->getParent()  /* not emitted */ || BB->empty())
+    return;
+
+  if (!BB->isEHPad()) {
+    for (llvm::BasicBlock::iterator J = BB->begin(),
+      JE = BB->end(); J != JE; ++J) {
+      if (isa<llvm::LoadInst>(J)) {
+        auto LI = cast<llvm::LoadInst>(J);
+        LI->setVolatile(true);
+      }
+      else if (isa<llvm::StoreInst>(J)) {
+        auto SI = cast<llvm::StoreInst>(J);
+        SI->setVolatile(true);
+      }
+      else if (isa<llvm::MemIntrinsic>(J)) {
+        auto* MCI = cast<llvm::MemIntrinsic>(J);
+        MCI->setVolatile(llvm::ConstantInt::get(Builder.getInt1Ty(), 1));
+      }
+    } // end of for
+  }
+  const llvm::Instruction* TI = BB->getTerminator();
+  if (TI) {
+    unsigned N = TI->getNumSuccessors();
+    for (unsigned I = 0; I < N; I++)
+      VolatilizeTryBlocks(TI->getSuccessor(I), V);
+  }
+}
+
 namespace {
 struct PerformSEHFinally final : EHScopeStack::Cleanup {
   llvm::Function *OutlinedFinally;
@@ -2050,6 +2124,12 @@
     return;
   }
 
+  // IsEHa: emit an invoke _seh_try_end() to mark end of FT flow
+  if (getLangOpts().EHAsynch && Builder.GetInsertBlock()) {
+    llvm::FunctionCallee SehTryEnd = getSehTryEndFn(CGM);
+    EmitRuntimeCallOrInvoke(SehTryEnd);
+  }
+
   // Otherwise, we must have an __except block.
   const SEHExceptStmt *Except = S.getExceptHandler();
   assert(Except && "__try must have __finally xor __except");
Index: clang/lib/CodeGen/CGDecl.cpp
===================================================================
--- clang/lib/CodeGen/CGDecl.cpp
+++ clang/lib/CodeGen/CGDecl.cpp
@@ -1997,9 +1997,16 @@
   const VarDecl &D = *emission.Variable;
 
   // Check the type for a cleanup.
-  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext()))
+  if (QualType::DestructionKind dtorKind = D.needsDestruction(getContext())) {
     emitAutoVarTypeCleanup(emission, dtorKind);
 
+    // <tentzen>: Under -EHa, Invoke llvm.eha.scope.begin() right after
+    //      Ctor is emitted and EHStack.pushCleanup
+    bool IsEHa = getLangOpts().EHAsynch;
+    if (IsEHa && dtorKind == QualType::DK_cxx_destructor)
+      EmitSehCppScopeBegin();
+  }
+
   // In GC mode, honor objc_precise_lifetime.
   if (getLangOpts().getGC() != LangOptions::NonGC &&
       D.hasAttr<ObjCPreciseLifetimeAttr>()) {
Index: clang/lib/CodeGen/CGCleanup.cpp
===================================================================
--- clang/lib/CodeGen/CGCleanup.cpp
+++ clang/lib/CodeGen/CGCleanup.cpp
@@ -638,6 +638,12 @@
   delete entry;
 }
 
+static llvm::FunctionCallee getSehTryEndFn(CodeGenModule& CGM) {
+  llvm::FunctionType* FTy =
+    llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+  return CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end");
+}
+
 /// Pops a cleanup block.  If the block includes a normal cleanup, the
 /// current insertion point is threaded through the cleanup, as are
 /// any branch fixups on the cleanup.
@@ -765,11 +771,22 @@
     destroyOptimisticNormalEntry(*this, Scope);
     EHStack.popCleanup();
   } else {
+    // Under -EHa, invoke eha_scope_end() to mark scope end before dtor
+    bool IsEHa = getLangOpts().EHAsynch && !Scope.isLifetimeMarker();
+    const EHPersonality& Personality = EHPersonality::get(*this);
+
     // If we have a fallthrough and no other need for the cleanup,
     // emit it directly.
     if (HasFallthrough && !HasPrebranchedFallthrough &&
         !HasFixups && !HasExistingBranches) {
 
+      // mark EHa scope end for fall-through flow
+      if (IsEHa && getInvokeDest())
+        if (Personality.isMSVCXXPersonality())
+          EmitSehCppScopeEnd();
+        else
+          EmitSehTryScopeEnd();
+
       destroyOptimisticNormalEntry(*this, Scope);
       EHStack.popCleanup();
 
@@ -803,6 +820,13 @@
       // should already be branched to it.
       EmitBlock(NormalEntry);
 
+      // intercept normal cleanup to mark EHa scope end
+      if (IsEHa)
+        if (Personality.isMSVCXXPersonality())
+          EmitSehCppScopeEnd();
+        else
+          EmitSehTryScopeEnd();
+
       // III.  Figure out where we're going and build the cleanup
       // epilogue.
 
@@ -1278,3 +1302,62 @@
   pushDestroy(NormalAndEHCleanup, Ptr, TempType, destroyCXXObject,
               /*useEHCleanup*/ true);
 }
+
+// Need to set "funclet" in OperandBundle properly for noThrow
+//       intrinsic (see CGCall.cpp)
+static void EmitSehEHaScope(CodeGenFunction& CGF,
+  llvm::FunctionCallee& SehCppScope)
+{
+  llvm::BasicBlock* InvokeDest = CGF.getInvokeDest();
+  llvm::BasicBlock* BB = CGF.Builder.GetInsertBlock();
+  assert(BB && InvokeDest);
+  llvm::BasicBlock* Cont = CGF.createBasicBlock("invoke.cont");
+  SmallVector<llvm::OperandBundleDef, 1> BundleList =
+    CGF.getBundlesForFunclet(SehCppScope.getCallee());
+  if (CGF.CurrentFuncletPad)
+    BundleList.emplace_back("funclet", CGF.CurrentFuncletPad);
+  CGF.Builder.CreateInvoke(SehCppScope, Cont, InvokeDest, None, BundleList);
+  CGF.EmitBlock(Cont);
+}
+
+// Invoke a llvm.eha.scope.begin at the beginning of a CPP scope for -EHa
+void CodeGenFunction::EmitSehCppScopeBegin() {
+  assert(getLangOpts().EHAsynch);
+  llvm::FunctionType* FTy =
+    llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+  llvm::FunctionCallee SehCppScope =
+    CGM.CreateRuntimeFunction(FTy, "llvm.eha.scope.begin");
+  EmitSehEHaScope(*this, SehCppScope);
+}
+
+// Invoke a llvm.eha.scope.end at the end of a CPP scope for -EHa
+//   llvm.eha.scope.end is emitted before popCleanup, so it's "invoked"
+void CodeGenFunction::EmitSehCppScopeEnd() {
+  assert(getLangOpts().EHAsynch);
+  llvm::FunctionType* FTy =
+    llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+  llvm::FunctionCallee SehCppScope =
+    CGM.CreateRuntimeFunction(FTy, "llvm.eha.scope.end");
+  EmitSehEHaScope(*this, SehCppScope);
+}
+
+// Invoke a llvm.eha.scope.begin at the beginning of a CPP scope for -EHa
+void CodeGenFunction::EmitSehTryScopeBegin() {
+  assert(getLangOpts().EHAsynch);
+  llvm::FunctionType* FTy =
+    llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+  llvm::FunctionCallee SehCppScope =
+    CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.begin");
+  EmitSehEHaScope(*this, SehCppScope);
+}
+
+// Invoke a llvm.eha.scope.end at the end of a CPP scope for -EHa
+//   llvm.eha.scope.end is emitted before popCleanup, so it's "invoked"
+void CodeGenFunction::EmitSehTryScopeEnd() {
+  assert(getLangOpts().EHAsynch);
+  llvm::FunctionType* FTy =
+    llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
+  llvm::FunctionCallee SehCppScope =
+    CGM.CreateRuntimeFunction(FTy, "llvm.seh.try.end");
+  EmitSehEHaScope(*this, SehCppScope);
+}
Index: clang/include/clang/Driver/Options.td
===================================================================
--- clang/include/clang/Driver/Options.td
+++ clang/include/clang/Driver/Options.td
@@ -883,6 +883,8 @@
 def fcreate_profile : Flag<["-"], "fcreate-profile">, Group<f_Group>;
 def fcxx_exceptions: Flag<["-"], "fcxx-exceptions">, Group<f_Group>,
   HelpText<"Enable C++ exceptions">, Flags<[CC1Option]>;
+def feh_asynch: Flag<["-"], "feh-asynch">, Group<f_Group>,
+  HelpText<"Enable EH Asynchronous exceptions">, Flags<[CC1Option]>;
 def fcxx_modules : Flag <["-"], "fcxx-modules">, Group<f_Group>,
   Flags<[DriverOption]>;
 def fdebug_pass_arguments : Flag<["-"], "fdebug-pass-arguments">, Group<f_Group>;
@@ -1526,6 +1528,7 @@
   Flags<[CC1Option]>,
   HelpText<"Disable creation of CodeFoundation-type constant strings">;
 def fno_cxx_exceptions: Flag<["-"], "fno-cxx-exceptions">, Group<f_Group>;
+def fno_eh_asynch: Flag<["-"], "fno-eh-asynch">, Group<f_Group>;
 def fno_cxx_modules : Flag <["-"], "fno-cxx-modules">, Group<f_Group>,
   Flags<[DriverOption]>;
 def fno_diagnostics_fixit_info : Flag<["-"], "fno-diagnostics-fixit-info">, Group<f_Group>,
Index: clang/include/clang/Basic/LangOptions.def
===================================================================
--- clang/include/clang/Basic/LangOptions.def
+++ clang/include/clang/Basic/LangOptions.def
@@ -128,6 +128,7 @@
 LANGOPT(Exceptions        , 1, 0, "exception handling")
 LANGOPT(ObjCExceptions    , 1, 0, "Objective-C exceptions")
 LANGOPT(CXXExceptions     , 1, 0, "C++ exceptions")
+LANGOPT(EHAsynch          , 1, 0, "C/C++ EH Asynch exceptions")
 LANGOPT(DWARFExceptions   , 1, 0, "dwarf exception handling")
 LANGOPT(SjLjExceptions    , 1, 0, "setjmp-longjump exception handling")
 LANGOPT(SEHExceptions     , 1, 0, "SEH .xdata exception handling")
Index: clang/include/clang/AST/Stmt.h
===================================================================
--- clang/include/clang/AST/Stmt.h
+++ clang/include/clang/AST/Stmt.h
@@ -1743,6 +1743,7 @@
 class LabelStmt : public ValueStmt {
   LabelDecl *TheDecl;
   Stmt *SubStmt;
+  bool SideEntry = false;
 
 public:
   /// Build a label statement.
@@ -1778,6 +1779,9 @@
   static bool classof(const Stmt *T) {
     return T->getStmtClass() == LabelStmtClass;
   }
+
+  bool IsSideEntry() const { return SideEntry; }
+  void setSideEntry() { SideEntry = true; }
 };
 
 /// Represents an attribute applied to a statement.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to