about summary refs log tree commit diff
path: root/src/librustc_codegen_llvm
diff options
context:
space:
mode:
authorAmanieu d'Antras <amanieu@gmail.com>2020-03-02 13:59:20 +0000
committerAmanieu d'Antras <amanieu@gmail.com>2020-03-05 17:36:50 +0000
commit1c950e5c6f85422283bb23bb4bad07ae6c3d2fe1 (patch)
tree01318bda757bf28d59cdd218b456b99736c613a8 /src/librustc_codegen_llvm
parent5953c100d1e9eea5ca70f185e905ea0773a34eb5 (diff)
downloadrust-1c950e5c6f85422283bb23bb4bad07ae6c3d2fe1.tar.gz
rust-1c950e5c6f85422283bb23bb4bad07ae6c3d2fe1.zip
Simplify the try intrinsic by using a callback in the catch block
Diffstat (limited to 'src/librustc_codegen_llvm')
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs100
1 files changed, 46 insertions, 54 deletions
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index baaa2a5cf45..d34540638f1 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -851,21 +851,21 @@ fn memset_intrinsic(
 
 fn try_intrinsic(
     bx: &mut Builder<'a, 'll, 'tcx>,
-    func: &'ll Value,
+    try_func: &'ll Value,
     data: &'ll Value,
-    local_ptr: &'ll Value,
+    catch_func: &'ll Value,
     dest: &'ll Value,
 ) {
     if bx.sess().no_landing_pads() {
-        bx.call(func, &[data], None);
+        bx.call(try_func, &[data], None);
         // Return 0 unconditionally from the intrinsic call;
         // we can never unwind.
         let ret_align = bx.tcx().data_layout.i32_align.abi;
         bx.store(bx.const_i32(0), dest, ret_align);
     } else if wants_msvc_seh(bx.sess()) {
-        codegen_msvc_try(bx, func, data, local_ptr, dest);
+        codegen_msvc_try(bx, try_func, data, catch_func, dest);
     } else {
-        codegen_gnu_try(bx, func, data, local_ptr, dest);
+        codegen_gnu_try(bx, try_func, data, catch_func, dest);
     }
 }
 
@@ -878,9 +878,9 @@ fn try_intrinsic(
 // as the old ones are still more optimized.
 fn codegen_msvc_try(
     bx: &mut Builder<'a, 'll, 'tcx>,
-    func: &'ll Value,
+    try_func: &'ll Value,
     data: &'ll Value,
-    local_ptr: &'ll Value,
+    catch_func: &'ll Value,
     dest: &'ll Value,
 ) {
     let llfn = get_rust_try_fn(bx, &mut |mut bx| {
@@ -892,15 +892,15 @@ fn codegen_msvc_try(
         let mut catchpad = bx.build_sibling_block("catchpad");
         let mut caught = bx.build_sibling_block("caught");
 
-        let func = llvm::get_param(bx.llfn(), 0);
+        let try_func = llvm::get_param(bx.llfn(), 0);
         let data = llvm::get_param(bx.llfn(), 1);
-        let local_ptr = llvm::get_param(bx.llfn(), 2);
+        let catch_func = llvm::get_param(bx.llfn(), 2);
 
         // We're generating an IR snippet that looks like:
         //
-        //   declare i32 @rust_try(%func, %data, %ptr) {
-        //      %slot = alloca [2 x i64]
-        //      invoke %func(%data) to label %normal unwind label %catchswitch
+        //   declare i32 @rust_try(%try_func, %data, %catch_func) {
+        //      %slot = alloca u8*
+        //      invoke %try_func(%data) to label %normal unwind label %catchswitch
         //
         //   normal:
         //      ret i32 0
@@ -910,8 +910,8 @@ fn codegen_msvc_try(
         //
         //   catchpad:
         //      %tok = catchpad within %cs [%type_descriptor, 0, %slot]
-        //      %ptr[0] = %slot[0]
-        //      %ptr[1] = %slot[1]
+        //      %ptr = load %slot
+        //      call %catch_func(%data, %ptr)
         //      catchret from %tok to label %caught
         //
         //   caught:
@@ -928,26 +928,26 @@ fn codegen_msvc_try(
         //          ~rust_panic();
         //
         //          uint64_t x[2];
-        //      }
+        //      };
         //
-        //      int bar(void (*foo)(void), uint64_t *ret) {
+        //      int __rust_try(
+        //          void (*try_func)(void*),
+        //          void *data,
+        //          void (*catch_func)(void*, void*) noexcept
+        //      ) {
         //          try {
-        //              foo();
+        //              try_func(data);
         //              return 0;
         //          } catch(rust_panic& a) {
-        //              ret[0] = a.x[0];
-        //              ret[1] = a.x[1];
-        //              a.x[0] = 0;
+        //              catch_func(data, &a);
         //              return 1;
         //          }
         //      }
         //
         // More information can be found in libstd's seh.rs implementation.
-        let i64_2 = bx.type_array(bx.type_i64(), 2);
-        let i64_2_ptr = bx.type_ptr_to(i64_2);
         let ptr_align = bx.tcx().data_layout.pointer_align.abi;
-        let slot = bx.alloca(i64_2_ptr, ptr_align);
-        bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), None);
+        let slot = bx.alloca(bx.type_i8p(), ptr_align);
+        bx.invoke(try_func, &[data], normal.llbb(), catchswitch.llbb(), None);
 
         normal.ret(bx.const_i32(0));
 
@@ -987,17 +987,8 @@ fn codegen_msvc_try(
         // Source: MicrosoftCXXABI::getAddrOfCXXCatchHandlerType in clang
         let flags = bx.const_i32(8);
         let funclet = catchpad.catch_pad(cs, &[tydesc, flags, slot]);
-        let i64_align = bx.tcx().data_layout.i64_align.abi;
-        let payload_ptr = catchpad.load(slot, ptr_align);
-        let payload = catchpad.load(payload_ptr, i64_align);
-        let local_ptr = catchpad.bitcast(local_ptr, bx.type_ptr_to(i64_2));
-        catchpad.store(payload, local_ptr, i64_align);
-
-        // Clear the first word of the exception so avoid double-dropping it.
-        // This will be read by the destructor which is implicitly called at the
-        // end of the catch block by the runtime.
-        let payload_0_ptr = catchpad.inbounds_gep(payload_ptr, &[bx.const_i32(0), bx.const_i32(0)]);
-        catchpad.store(bx.const_u64(0), payload_0_ptr, i64_align);
+        let ptr = catchpad.load(slot, ptr_align);
+        catchpad.call(catch_func, &[data, ptr], Some(&funclet));
 
         catchpad.catch_ret(&funclet, caught.llbb());
 
@@ -1006,7 +997,7 @@ fn codegen_msvc_try(
 
     // Note that no invoke is used here because by definition this function
     // can't panic (that's what it's catching).
-    let ret = bx.call(llfn, &[func, data, local_ptr], None);
+    let ret = bx.call(llfn, &[try_func, data, catch_func], None);
     let i32_align = bx.tcx().data_layout.i32_align.abi;
     bx.store(ret, dest, i32_align);
 }
@@ -1024,38 +1015,34 @@ fn codegen_msvc_try(
 // the right personality function.
 fn codegen_gnu_try(
     bx: &mut Builder<'a, 'll, 'tcx>,
-    func: &'ll Value,
+    try_func: &'ll Value,
     data: &'ll Value,
-    local_ptr: &'ll Value,
+    catch_func: &'ll Value,
     dest: &'ll Value,
 ) {
     let llfn = get_rust_try_fn(bx, &mut |mut bx| {
         // Codegens the shims described above:
         //
         //   bx:
-        //      invoke %func(%args...) normal %normal unwind %catch
+        //      invoke %func(%data) normal %normal unwind %catch
         //
         //   normal:
         //      ret 0
         //
         //   catch:
-        //      (ptr, _) = landingpad
-        //      store ptr, %local_ptr
+        //      (%ptr, _) = landingpad
+        //      call %catch_func(%data, %ptr)
         //      ret 1
-        //
-        // Note that the `local_ptr` data passed into the `try` intrinsic is
-        // expected to be `*mut *mut u8` for this to actually work, but that's
-        // managed by the standard library.
 
         bx.sideeffect();
 
         let mut then = bx.build_sibling_block("then");
         let mut catch = bx.build_sibling_block("catch");
 
-        let func = llvm::get_param(bx.llfn(), 0);
+        let try_func = llvm::get_param(bx.llfn(), 0);
         let data = llvm::get_param(bx.llfn(), 1);
-        let local_ptr = llvm::get_param(bx.llfn(), 2);
-        bx.invoke(func, &[data], then.llbb(), catch.llbb(), None);
+        let catch_func = llvm::get_param(bx.llfn(), 2);
+        bx.invoke(try_func, &[data], then.llbb(), catch.llbb(), None);
         then.ret(bx.const_i32(0));
 
         // Type indicator for the exception being thrown.
@@ -1075,15 +1062,13 @@ fn codegen_gnu_try(
         };
         catch.add_clause(vals, tydesc);
         let ptr = catch.extract_value(vals, 0);
-        let ptr_align = bx.tcx().data_layout.pointer_align.abi;
-        let bitcast = catch.bitcast(local_ptr, bx.type_ptr_to(bx.type_i8p()));
-        catch.store(ptr, bitcast, ptr_align);
+        catch.call(catch_func, &[data, ptr], None);
         catch.ret(bx.const_i32(1));
     });
 
     // Note that no invoke is used here because by definition this function
     // can't panic (that's what it's catching).
-    let ret = bx.call(llfn, &[func, data, local_ptr], None);
+    let ret = bx.call(llfn, &[try_func, data, catch_func], None);
     let i32_align = bx.tcx().data_layout.i32_align.abi;
     bx.store(ret, dest, i32_align);
 }
@@ -1130,15 +1115,22 @@ fn get_rust_try_fn<'ll, 'tcx>(
     // Define the type up front for the signature of the rust_try function.
     let tcx = cx.tcx;
     let i8p = tcx.mk_mut_ptr(tcx.types.i8);
-    let fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
+    let try_fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
         iter::once(i8p),
         tcx.mk_unit(),
         false,
         hir::Unsafety::Unsafe,
         Abi::Rust,
     )));
+    let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
+        [i8p, i8p].iter().cloned(),
+        tcx.mk_unit(),
+        false,
+        hir::Unsafety::Unsafe,
+        Abi::Rust,
+    )));
     let output = tcx.types.i32;
-    let rust_try = gen_fn(cx, "__rust_try", vec![fn_ty, i8p, i8p], output, codegen);
+    let rust_try = gen_fn(cx, "__rust_try", vec![try_fn_ty, i8p, catch_fn_ty], output, codegen);
     cx.rust_try_fn.set(Some(rust_try));
     rust_try
 }