about summary refs log tree commit diff
path: root/src/rustllvm/RustWrapper.cpp
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-10-23 18:18:44 -0700
committerAlex Crichton <alex@alexcrichton.com>2016-01-29 16:25:20 -0800
commit3e9589c0f43af69544b042f50b886005613540f2 (patch)
treeac718169258ed337a5164fe2943ad6b79a8c15df /src/rustllvm/RustWrapper.cpp
parentd1cace17af31ddb21aeb8a3d94cb3eda934047d9 (diff)
downloadrust-3e9589c0f43af69544b042f50b886005613540f2.tar.gz
rust-3e9589c0f43af69544b042f50b886005613540f2.zip
trans: Reimplement unwinding on MSVC
This commit transitions the compiler to using the new exception handling
instructions in LLVM for implementing unwinding for MSVC. This affects both 32
and 64-bit MSVC as they're both now using SEH-based strategies. In terms of
standard library support, lots more details about how SEH unwinding is
implemented can be found in the commits.

In terms of trans, this change necessitated a few modifications:

* Branches were added to detect when the old landingpad instruction is used or
  the new cleanuppad instruction is used to `trans::cleanup`.
* The return value from `cleanuppad` is not stored in an `alloca` (because it
  cannot be).
* Each block in trans now has an `Option<LandingPad>` instead of `is_lpad: bool`
  for indicating whether it's in a landing pad or not. The new exception
  handling intrinsics require that on MSVC each `call` inside of a landing pad
  is annotated with which landing pad that it's in. This change to the basic
  block means that whenever a `call` or `invoke` instruction is generated we
  know whether to annotate it as part of a cleanuppad or not.
* Lots of modifications were made to the instruction builders to construct the
  new instructions as well as pass the tagging information for the call/invoke
  instructions.
* The translation of the `try` intrinsics for MSVC has been overhauled to use
  the new `catchpad` instruction. The filter function is now also a
  rustc-generated function instead of a purely libstd-defined function. The
  libstd definition still exists, it just has a stable ABI across architectures
  and leaves some of the really weird implementation details to the compiler
  (e.g. the `localescape` and `localrecover` intrinsics).
Diffstat (limited to 'src/rustllvm/RustWrapper.cpp')
-rw-r--r--src/rustllvm/RustWrapper.cpp178
1 files changed, 178 insertions, 0 deletions
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index a625a75933d..0c18051dac7 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -987,3 +987,181 @@ LLVMRustBuildLandingPad(LLVMBuilderRef Builder,
                         LLVMValueRef F) {
     return LLVMBuildLandingPad(Builder, Ty, PersFn, NumClauses, Name);
 }
+
+extern "C" LLVMValueRef
+LLVMRustBuildCleanupPad(LLVMBuilderRef Builder,
+                        LLVMValueRef ParentPad,
+                        unsigned ArgCnt,
+                        LLVMValueRef *LLArgs,
+                        const char *Name) {
+#if LLVM_VERSION_MINOR >= 8
+    Value **Args = unwrap(LLArgs);
+    if (ParentPad == NULL) {
+        Type *Ty = Type::getTokenTy(unwrap(Builder)->getContext());
+        ParentPad = wrap(Constant::getNullValue(Ty));
+    }
+    return wrap(unwrap(Builder)->CreateCleanupPad(unwrap(ParentPad),
+                                                  ArrayRef<Value*>(Args, ArgCnt),
+                                                  Name));
+#else
+    return NULL;
+#endif
+}
+
+extern "C" LLVMValueRef
+LLVMRustBuildCleanupRet(LLVMBuilderRef Builder,
+                        LLVMValueRef CleanupPad,
+                        LLVMBasicBlockRef UnwindBB) {
+#if LLVM_VERSION_MINOR >= 8
+    CleanupPadInst *Inst = cast<CleanupPadInst>(unwrap(CleanupPad));
+    return wrap(unwrap(Builder)->CreateCleanupRet(Inst, unwrap(UnwindBB)));
+#else
+    return NULL;
+#endif
+}
+
+extern "C" LLVMValueRef
+LLVMRustBuildCatchPad(LLVMBuilderRef Builder,
+                      LLVMValueRef ParentPad,
+                      unsigned ArgCnt,
+                      LLVMValueRef *LLArgs,
+                      const char *Name) {
+#if LLVM_VERSION_MINOR >= 8
+    Value **Args = unwrap(LLArgs);
+    return wrap(unwrap(Builder)->CreateCatchPad(unwrap(ParentPad),
+                                                ArrayRef<Value*>(Args, ArgCnt),
+                                                Name));
+#else
+    return NULL;
+#endif
+}
+
+extern "C" LLVMValueRef
+LLVMRustBuildCatchRet(LLVMBuilderRef Builder,
+                      LLVMValueRef Pad,
+                      LLVMBasicBlockRef BB) {
+#if LLVM_VERSION_MINOR >= 8
+    return wrap(unwrap(Builder)->CreateCatchRet(cast<CatchPadInst>(unwrap(Pad)),
+                                                unwrap(BB)));
+#else
+    return NULL;
+#endif
+}
+
+extern "C" LLVMValueRef
+LLVMRustBuildCatchSwitch(LLVMBuilderRef Builder,
+                         LLVMValueRef ParentPad,
+                         LLVMBasicBlockRef BB,
+                         unsigned NumHandlers,
+                         const char *Name) {
+#if LLVM_VERSION_MINOR >= 8
+    if (ParentPad == NULL) {
+        Type *Ty = Type::getTokenTy(unwrap(Builder)->getContext());
+        ParentPad = wrap(Constant::getNullValue(Ty));
+    }
+    return wrap(unwrap(Builder)->CreateCatchSwitch(unwrap(ParentPad),
+                                                   unwrap(BB),
+                                                   NumHandlers,
+                                                   Name));
+#else
+    return NULL;
+#endif
+}
+
+extern "C" void
+LLVMRustAddHandler(LLVMValueRef CatchSwitchRef,
+                   LLVMBasicBlockRef Handler) {
+#if LLVM_VERSION_MINOR >= 8
+    Value *CatchSwitch = unwrap(CatchSwitchRef);
+    cast<CatchSwitchInst>(CatchSwitch)->addHandler(unwrap(Handler));
+#endif
+}
+
+extern "C" void
+LLVMRustSetPersonalityFn(LLVMBuilderRef B,
+                         LLVMValueRef Personality) {
+#if LLVM_VERSION_MINOR >= 8
+    unwrap(B)->GetInsertBlock()
+             ->getParent()
+             ->setPersonalityFn(cast<Function>(unwrap(Personality)));
+#endif
+}
+
+#if LLVM_VERSION_MINOR >= 8
+extern "C" OperandBundleDef*
+LLVMRustBuildOperandBundleDef(const char *Name,
+                              LLVMValueRef *Inputs,
+                              unsigned NumInputs) {
+  return new OperandBundleDef(Name, makeArrayRef(unwrap(Inputs), NumInputs));
+}
+
+extern "C" void
+LLVMRustFreeOperandBundleDef(OperandBundleDef* Bundle) {
+  delete Bundle;
+}
+
+extern "C" LLVMValueRef
+LLVMRustBuildCall(LLVMBuilderRef B,
+                    LLVMValueRef Fn,
+                    LLVMValueRef *Args,
+                    unsigned NumArgs,
+                    OperandBundleDef *Bundle,
+                    const char *Name) {
+    unsigned len = Bundle ? 1 : 0;
+    ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, len);
+    return wrap(unwrap(B)->CreateCall(unwrap(Fn),
+                                      makeArrayRef(unwrap(Args), NumArgs),
+                                      Bundles,
+                                      Name));
+}
+
+extern "C" LLVMValueRef
+LLVMRustBuildInvoke(LLVMBuilderRef B,
+                    LLVMValueRef Fn,
+                    LLVMValueRef *Args,
+                    unsigned NumArgs,
+                    LLVMBasicBlockRef Then,
+                    LLVMBasicBlockRef Catch,
+                    OperandBundleDef *Bundle,
+                    const char *Name) {
+    unsigned len = Bundle ? 1 : 0;
+    ArrayRef<OperandBundleDef> Bundles = makeArrayRef(Bundle, len);
+    return wrap(unwrap(B)->CreateInvoke(unwrap(Fn), unwrap(Then), unwrap(Catch),
+                                        makeArrayRef(unwrap(Args), NumArgs),
+                                        Bundles,
+                                        Name));
+}
+#else
+extern "C" void*
+LLVMRustBuildOperandBundleDef(const char *Name,
+                              LLVMValueRef *Inputs,
+                              unsigned NumInputs) {
+  return NULL;
+}
+
+extern "C" void
+LLVMRustFreeOperandBundleDef(void* Bundle) {
+}
+
+extern "C" LLVMValueRef
+LLVMRustBuildCall(LLVMBuilderRef B,
+                    LLVMValueRef Fn,
+                    LLVMValueRef *Args,
+                    unsigned NumArgs,
+                    void *Bundle,
+                    const char *Name) {
+    return LLVMBuildCall(B, Fn, Args, NumArgs, Name);
+}
+
+extern "C" LLVMValueRef
+LLVMRustBuildInvoke(LLVMBuilderRef B,
+                    LLVMValueRef Fn,
+                    LLVMValueRef *Args,
+                    unsigned NumArgs,
+                    LLVMBasicBlockRef Then,
+                    LLVMBasicBlockRef Catch,
+                    void *Bundle,
+                    const char *Name) {
+    return LLVMBuildInvoke(B, Fn, Args, NumArgs, Then, Catch, Name);
+}
+#endif