From a8b46e705502dd9b4fb5d5d2eaf16af1f18e6484 Mon Sep 17 00:00:00 2001
From: Reid Kleckner <reid@kleckner.net>
Date: Wed, 25 Mar 2015 20:10:36 +0000
Subject: [PATCH] WinEH: Create an unwind help alloca for __CxxFrameHandler3
 xdata tables

We don't have any logic to emit those tables yet, so the sdag lowering
of this intrinsic is just a stub. We can see the intrinsic in the
prepared IR, though.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@233209 91177308-0d34-0410-b5e6-96231b3b80d8
---
 docs/ExceptionHandling.rst                       | 12 ++++++++++++
 include/llvm/IR/Intrinsics.td                    |  4 ++++
 lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 10 ++++++++++
 lib/CodeGen/WinEHPrepare.cpp                     | 13 +++++++++++++
 lib/IR/Verifier.cpp                              |  7 +++++++
 test/CodeGen/WinEH/cppeh-catch-unwind.ll         |  3 +++
 6 files changed, 49 insertions(+)

diff --git a/docs/ExceptionHandling.rst b/docs/ExceptionHandling.rst
index ee157d096a2..21de19b0752 100644
--- a/docs/ExceptionHandling.rst
+++ b/docs/ExceptionHandling.rst
@@ -539,6 +539,18 @@ In order to preserve the structure of the CFG, a call to '``llvm.eh.actions``'
 must be followed by an ':ref:`indirectbr <i_indirectbr>`' instruction that jumps
 to the result of the intrinsic call.
 
+``llvm.eh.unwindhelp``
+----------------------
+
+.. code-block:: llvm
+
+  void @llvm.eh.unwindhelp(i8*)
+
+This intrinsic designates the provided static alloca as the unwind help object.
+This object is used by Windows native exception handling on non-x86 platforms
+where xdata unwind information is used. It is typically an 8 byte chunk of
+memory treated as two 32-bit integers.
+
 
 SJLJ Intrinsics
 ---------------
diff --git a/include/llvm/IR/Intrinsics.td b/include/llvm/IR/Intrinsics.td
index 110d6b22e8a..da9d8cb61f5 100644
--- a/include/llvm/IR/Intrinsics.td
+++ b/include/llvm/IR/Intrinsics.td
@@ -421,6 +421,10 @@ def int_eh_endcatch : Intrinsic<[], []>;
 // Represents the list of actions to take when an exception is thrown.
 def int_eh_actions : Intrinsic<[llvm_ptr_ty], [llvm_vararg_ty], []>;
 
+// Designates the provided static alloca as the unwind help object. Required
+// for WinEH.
+def int_eh_unwindhelp : Intrinsic<[], [llvm_ptr_ty], []>;
+
 // __builtin_unwind_init is an undocumented GCC intrinsic that causes all
 // callee-saved registers to be saved and restored (regardless of whether they
 // are used) in the calling function. It is used by libgcc_eh.
diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 6f5ea7c7469..6c14e7969c5 100644
--- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -5446,6 +5446,16 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
   case Intrinsic::eh_begincatch:
   case Intrinsic::eh_endcatch:
     llvm_unreachable("begin/end catch intrinsics not lowered in codegen");
+  case Intrinsic::eh_unwindhelp: {
+    AllocaInst *Slot =
+        cast<AllocaInst>(I.getArgOperand(0)->stripPointerCasts());
+    assert(FuncInfo.StaticAllocaMap.count(Slot) &&
+           "can only use static allocas with llvm.eh.unwindhelp");
+    int FI = FuncInfo.StaticAllocaMap[Slot];
+    // TODO: Save this in the not-yet-existant WinEHFuncInfo struct.
+    (void)FI;
+    return nullptr;
+  }
   }
 }
 
diff --git a/lib/CodeGen/WinEHPrepare.cpp b/lib/CodeGen/WinEHPrepare.cpp
index d1b385579b9..ab0f96ef05f 100644
--- a/lib/CodeGen/WinEHPrepare.cpp
+++ b/lib/CodeGen/WinEHPrepare.cpp
@@ -601,6 +601,19 @@ bool WinEHPrepare::prepareExceptionHandlers(
   Builder.SetInsertPoint(&F.getEntryBlock().back());
   Builder.CreateCall(FrameEscapeFn, AllocasToEscape);
 
+  // Insert an alloca for the EH state in the entry block. On x86, we will also
+  // insert stores to update the EH state, but on other ISAs, the runtime does
+  // it for us.
+  // FIXME: This record is different on x86.
+  Type *UnwindHelpTy = Type::getInt64Ty(Context);
+  AllocaInst *UnwindHelp =
+      new AllocaInst(UnwindHelpTy, "unwindhelp", &F.getEntryBlock().front());
+  Builder.CreateStore(llvm::ConstantInt::get(UnwindHelpTy, -2), UnwindHelp);
+  Function *UnwindHelpFn =
+      Intrinsic::getDeclaration(M, Intrinsic::eh_unwindhelp);
+  Builder.CreateCall(UnwindHelpFn,
+                     Builder.CreateBitCast(UnwindHelp, Int8PtrType));
+
   // Clean up the handler action maps we created for this function
   DeleteContainerSeconds(CatchHandlerMap);
   CatchHandlerMap.clear();
diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp
index 5f25891f2b1..ee3582d00ca 100644
--- a/lib/IR/Verifier.cpp
+++ b/lib/IR/Verifier.cpp
@@ -2908,6 +2908,13 @@ void Verifier::visitIntrinsicFunctionCall(Intrinsic::ID ID, CallInst &CI) {
     break;
   }
 
+  case Intrinsic::eh_unwindhelp: {
+    auto *AI = dyn_cast<AllocaInst>(CI.getArgOperand(0)->stripPointerCasts());
+    Assert(AI && AI->isStaticAlloca(),
+           "llvm.eh.unwindhelp requires a static alloca", &CI);
+    break;
+  }
+
   case Intrinsic::experimental_gc_statepoint:
     Assert(!CI.isInlineAsm(),
            "gc.statepoint support for inline assembly unimplemented", &CI);
diff --git a/test/CodeGen/WinEH/cppeh-catch-unwind.ll b/test/CodeGen/WinEH/cppeh-catch-unwind.ll
index 011f2df96ed..3db1635a110 100644
--- a/test/CodeGen/WinEH/cppeh-catch-unwind.ll
+++ b/test/CodeGen/WinEH/cppeh-catch-unwind.ll
@@ -33,10 +33,13 @@ $"\01??_R0H@8" = comdat any
 
 ; CHECK-LABEL: define void @"\01?test@@YAXXZ"() #0 {
 ; CHECK: entry:
+; CHECK:   [[UNWIND_HELP:\%.+]] = alloca i64
 ; CHECK:   [[OBJ_PTR:\%.+]] = alloca %class.SomeClass
 ; CHECK:   [[TMP0:\%.+]] = alloca i32, align 4
 ; CHECK:   [[TMP1:\%.+]] = alloca i32, align 4
 ; CHECK:   call void (...)* @llvm.frameescape(i32* [[TMP1]], %class.SomeClass* [[OBJ_PTR]], i32* [[TMP0]])
+; CHECK:   [[UNWIND_HELP_i8:\%.+]] = bitcast i64* [[UNWIND_HELP]] to i8*
+; CHECK:   call void @llvm.eh.unwindhelp(i8* [[UNWIND_HELP_i8]])
 ; CHECK:   %call = invoke %class.SomeClass* @"\01??0SomeClass@@QEAA@XZ"(%class.SomeClass* %obj)
 ; CHECK:           to label %invoke.cont unwind label %[[LPAD_LABEL:lpad[0-9]+]]
 
-- 
2.40.0