diff options
| author | antoyo <antoyo@users.noreply.github.com> | 2023-01-11 00:24:47 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-01-11 00:24:47 -0500 |
| commit | 6c5a70de207adc466ab0ffd5151fc1c9161c83e7 (patch) | |
| tree | fdaf58073400f55fb4b784b4857b688cc53730f8 | |
| parent | 7c1d21c3b91e33d5185228e98ec0eb01ed3f1cd5 (diff) | |
| parent | 8e77fbf0cce0fbbc780819ad81459bba2e0ba0c0 (diff) | |
| download | rust-6c5a70de207adc466ab0ffd5151fc1c9161c83e7.tar.gz rust-6c5a70de207adc466ab0ffd5151fc1c9161c83e7.zip | |
Merge pull request #244 from rust-lang/feature/unwinding
Implement unwinding
| -rw-r--r-- | .github/workflows/ci.yml | 12 | ||||
| -rw-r--r-- | Cargo.lock | 4 | ||||
| -rw-r--r-- | Readme.md | 18 | ||||
| -rwxr-xr-x | build_sysroot/build_sysroot.sh | 2 | ||||
| -rw-r--r-- | config.sh | 2 | ||||
| -rw-r--r-- | example/alloc_example.rs | 12 | ||||
| -rw-r--r-- | failing-ui-tests.txt | 26 | ||||
| -rw-r--r-- | failing-ui-tests12.txt | 9 | ||||
| -rw-r--r-- | src/asm.rs | 5 | ||||
| -rw-r--r-- | src/base.rs | 6 | ||||
| -rw-r--r-- | src/builder.rs | 86 | ||||
| -rw-r--r-- | src/callee.rs | 21 | ||||
| -rw-r--r-- | src/context.rs | 77 | ||||
| -rw-r--r-- | src/declare.rs | 10 | ||||
| -rw-r--r-- | src/intrinsic/llvm.rs | 6 | ||||
| -rw-r--r-- | src/intrinsic/mod.rs | 154 | ||||
| -rw-r--r-- | src/mono_item.rs | 3 | ||||
| -rwxr-xr-x | test.sh | 10 | ||||
| -rw-r--r-- | tests/lang_tests_common.rs | 6 | ||||
| -rw-r--r-- | tests/run/int.rs | 16 |
20 files changed, 388 insertions, 97 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2fd27654dc4..927eb307761 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,9 +19,9 @@ jobs: fail-fast: false matrix: libgccjit_version: - - { gcc: "libgccjit.so", extra: "", artifacts_branch: "master" } - - { gcc: "libgccjit_without_int128.so", extra: "", artifacts_branch: "master-without-128bit-integers" } - - { gcc: "libgccjit12.so", extra: "--no-default-features", artifacts_branch: "gcc12" } + - { gcc: "libgccjit.so", extra: "", env_extra: "", artifacts_branch: "master" } + - { gcc: "libgccjit_without_int128.so", extra: "", env_extra: "", artifacts_branch: "master-without-128bit-integers" } + - { gcc: "libgccjit12.so", extra: "--no-default-features", env_extra: "TEST_FLAGS='-Cpanic=abort -Zpanic-abort-tests'", artifacts_branch: "gcc12" } commands: [ "--mini-tests", "--std-tests", @@ -120,8 +120,8 @@ jobs: - name: Build run: | ./prepare_build.sh - ./build.sh ${{ matrix.libgccjit_version.extra }} - cargo test ${{ matrix.libgccjit_version.extra }} + ${{ matrix.libgccjit_version.env_extra }} ./build.sh ${{ matrix.libgccjit_version.extra }} + ${{ matrix.libgccjit_version.env_extra }} cargo test ${{ matrix.libgccjit_version.extra }} ./clean_all.sh - name: Prepare dependencies @@ -143,7 +143,7 @@ jobs: - name: Run tests run: | - ./test.sh --release --clean --build-sysroot ${{ matrix.commands }} ${{ matrix.libgccjit_version.extra }} + ${{ matrix.libgccjit_version.env_extra }} ./test.sh --release --clean --build-sysroot ${{ matrix.commands }} ${{ matrix.libgccjit_version.extra }} duplicates: runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index 10d2542f8b5..e20980caee1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -41,7 +41,7 @@ dependencies = [ [[package]] name = "gccjit" version = "1.0.0" -source = "git+https://github.com/antoyo/gccjit.rs#f30cc2bd330f4fda3d625f305bdfd7e523e2d8f8" +source = "git+https://github.com/antoyo/gccjit.rs#1e6ecc67fe73ac995e511516eacf4fe3aec8974e" dependencies = [ "gccjit_sys", ] @@ -49,7 +49,7 @@ dependencies = [ [[package]] name = "gccjit_sys" version = "0.0.1" -source = "git+https://github.com/antoyo/gccjit.rs#f30cc2bd330f4fda3d625f305bdfd7e523e2d8f8" +source = "git+https://github.com/antoyo/gccjit.rs#1e6ecc67fe73ac995e511516eacf4fe3aec8974e" dependencies = [ "libc 0.1.12", ] diff --git a/Readme.md b/Readme.md index c681e3ca3bc..3201afbd782 100644 --- a/Readme.md +++ b/Readme.md @@ -162,8 +162,26 @@ To print a debug representation of a tree: debug_tree(expr); ``` +(defined in print-tree.h) + +To print a debug reprensentation of a gimple struct: + +```c +debug_gimple_stmt(gimple_struct) +``` + To get the `rustc` command to run in `gdb`, add the `--verbose` flag to `cargo build`. +To have the correct file paths in `gdb` instead of `/usr/src/debug/gcc/libstdc++-v3/libsupc++/eh_personality.cc`, TODO + +Maybe by calling the following at the beginning of gdb: + +``` +set substitute-path /usr/src/debug/gcc /path/to/gcc-repo/gcc +``` + +TODO: but that's not what I remember I was doing. + ### How to use a custom-build rustc * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`). diff --git a/build_sysroot/build_sysroot.sh b/build_sysroot/build_sysroot.sh index f293192a099..9d692d599f6 100755 --- a/build_sysroot/build_sysroot.sh +++ b/build_sysroot/build_sysroot.sh @@ -16,7 +16,7 @@ rm Cargo.lock test_target/Cargo.lock 2>/dev/null || true rm -r sysroot/ 2>/dev/null || true # Build libs -export RUSTFLAGS="$RUSTFLAGS -Z force-unstable-if-unmarked -Cpanic=abort" +export RUSTFLAGS="$RUSTFLAGS -Z force-unstable-if-unmarked" if [[ "$1" == "--release" ]]; then sysroot_channel='release' RUSTFLAGS="$RUSTFLAGS -Zmir-opt-level=3" cargo build --target $TARGET_TRIPLE --release diff --git a/config.sh b/config.sh index b25e215fb9e..166e83901c4 100644 --- a/config.sh +++ b/config.sh @@ -38,7 +38,7 @@ if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then fi fi -export RUSTFLAGS="$CG_RUSTFLAGS $linker -Cpanic=abort -Csymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot" +export RUSTFLAGS="$CG_RUSTFLAGS $linker -Csymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot $TEST_FLAGS" # FIXME(antoyo): remove once the atomic shim is gone if [[ `uname` == 'Darwin' ]]; then diff --git a/example/alloc_example.rs b/example/alloc_example.rs index c327b93f1bb..c80348ca549 100644 --- a/example/alloc_example.rs +++ b/example/alloc_example.rs @@ -1,4 +1,4 @@ -#![feature(start, box_syntax, core_intrinsics, alloc_error_handler)] +#![feature(start, box_syntax, core_intrinsics, alloc_error_handler, lang_items)] #![no_std] extern crate alloc; @@ -26,6 +26,16 @@ fn alloc_error_handler(_: alloc::alloc::Layout) -> ! { core::intrinsics::abort(); } +#[lang = "eh_personality"] +fn eh_personality() -> ! { + loop {} +} + +#[no_mangle] +unsafe extern "C" fn _Unwind_Resume() { + core::intrinsics::unreachable(); +} + #[start] fn main(_argc: isize, _argv: *const *const u8) -> isize { let world: Box<&str> = box "Hello World!\0"; diff --git a/failing-ui-tests.txt b/failing-ui-tests.txt index 6182353599b..2629144f167 100644 --- a/failing-ui-tests.txt +++ b/failing-ui-tests.txt @@ -41,3 +41,29 @@ src/test/ui/sse2.rs src/test/ui/statics/issue-91050-1.rs src/test/ui/statics/issue-91050-2.rs src/test/ui/target-feature/missing-plusminus.rs +src/test/ui/asm/x86_64/may_unwind.rs +src/test/ui/backtrace.rs +src/test/ui/catch-unwind-bang.rs +src/test/ui/cfg/cfg-panic-abort.rs +src/test/ui/drop/dynamic-drop-async.rs +src/test/ui/drop/repeat-drop.rs +src/test/ui/fmt/format-args-capture.rs +src/test/ui/generator/panic-drops-resume.rs +src/test/ui/generator/panic-drops.rs +src/test/ui/generator/panic-safe.rs +src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +src/test/ui/issues/issue-14875.rs +src/test/ui/issues/issue-29948.rs +src/test/ui/issues/issue-43853.rs +src/test/ui/iterators/iter-sum-overflow-debug.rs +src/test/ui/iterators/iter-sum-overflow-overflow-checks.rs +src/test/ui/mir/mir_calls_to_shims.rs +src/test/ui/mir/mir_drop_order.rs +src/test/ui/mir/mir_let_chains_drop_order.rs +src/test/ui/oom_unwind.rs +src/test/ui/panic-runtime/abort-link-to-unwinding-crates.rs +src/test/ui/panic-runtime/abort.rs +src/test/ui/panic-runtime/link-to-abort.rs +src/test/ui/rfc-2091-track-caller/std-panic-locations.rs +src/test/ui/rfcs/rfc1857-drop-order.rs +src/test/ui/unwind-no-uwtable.rs diff --git a/failing-ui-tests12.txt b/failing-ui-tests12.txt index 32feb2c886b..e52248b1d0b 100644 --- a/failing-ui-tests12.txt +++ b/failing-ui-tests12.txt @@ -22,3 +22,12 @@ src/test/ui/simd/intrinsic/inlining-issue67557.rs src/test/ui/simd/monomorphize-shuffle-index.rs src/test/ui/simd/shuffle.rs src/test/ui/simd/simd-bitmask.rs +src/test/ui/binding/fn-arg-incomplete-pattern-drop-order.rs +src/test/ui/drop/dynamic-drop.rs +src/test/ui/generator/resume-after-return.rs +src/test/ui/iterators/iter-step-overflow-debug.rs +src/test/ui/macros/rfc-2011-nicer-assert-messages/all-expr-kinds.rs +src/test/ui/numbers-arithmetic/next-power-of-two-overflow-debug.rs +src/test/ui/panic-while-printing.rs +src/test/ui/privacy/reachable-unnameable-items.rs +src/test/ui/rfc-1937-termination-trait/termination-trait-in-test.rs diff --git a/src/asm.rs b/src/asm.rs index 0d5c343ffe3..19cd44f2819 100644 --- a/src/asm.rs +++ b/src/asm.rs @@ -352,8 +352,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> { inputs.push(AsmInOperand { constraint: "X".into(), rust_idx, - val: self.cx.rvalue_as_function(get_fn(self.cx, instance)) - .get_address(None), + val: get_fn(self.cx, instance).get_address(None), }); } @@ -739,7 +738,7 @@ impl<'gcc, 'tcx> AsmMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } GlobalAsmOperandRef::SymFn { instance } => { - let function = self.rvalue_as_function(get_fn(self, instance)); + let function = get_fn(self, instance); self.add_used_function(function); // TODO(@Amanieu): Additional mangling is needed on // some targets to add a leading underscore (Mach-O) diff --git a/src/base.rs b/src/base.rs index ed3daddf43e..ea933c25b2f 100644 --- a/src/base.rs +++ b/src/base.rs @@ -87,6 +87,10 @@ pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol, supports_ // Instantiate monomorphizations without filling out definitions yet... //let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str()); let context = Context::default(); + + context.add_command_line_option("-fexceptions"); + context.add_driver_option("-fexceptions"); + // TODO(antoyo): only set on x86 platforms. context.add_command_line_option("-masm=intel"); // TODO(antoyo): only add the following cli argument if the feature is supported. @@ -146,7 +150,7 @@ pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol, supports_ context.set_keep_intermediates(true); } - // TODO(bjorn3): Remove once unwinding is properly implemented + // NOTE: The codegen generates unrechable blocks. context.set_allow_unreachable_blocks(true); { diff --git a/src/builder.rs b/src/builder.rs index b7342f50716..0150f5ba8c1 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -372,10 +372,11 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> { } } -impl<'gcc, 'tcx> Deref for Builder<'_, 'gcc, 'tcx> { +impl<'a, 'gcc, 'tcx> Deref for Builder<'a, 'gcc, 'tcx> { type Target = CodegenCx<'gcc, 'tcx>; - fn deref(&self) -> &Self::Target { + fn deref<'b>(&'b self) -> &'a Self::Target + { self.cx } } @@ -393,7 +394,7 @@ impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> { } impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { - fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Self { + fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Builder<'a, 'gcc, 'tcx> { Builder::with_cx(cx, block) } @@ -450,8 +451,36 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { self.block.end_with_switch(None, value, default_block, &gcc_cases); } + #[cfg(feature="master")] + fn invoke(&mut self, typ: Type<'gcc>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { + let try_block = self.current_func().new_block("try"); + + let current_block = self.block.clone(); + self.block = try_block; + let call = self.call(typ, func, args, None); // TODO(antoyo): use funclet here? + self.block = current_block; + + let return_value = self.current_func() + .new_local(None, call.get_type(), "invokeResult"); + + try_block.add_assignment(None, return_value, call); + + try_block.end_with_jump(None, then); + + if self.cleanup_blocks.borrow().contains(&catch) { + self.block.add_try_finally(None, try_block, catch); + } + else { + self.block.add_try_catch(None, try_block, catch); + } + + self.block.end_with_jump(None, then); + + return_value.to_rvalue() + } + + #[cfg(not(feature="master"))] fn invoke(&mut self, typ: Type<'gcc>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> { - // TODO(bjorn3): Properly implement unwinding. let call_site = self.call(typ, func, args, None); let condition = self.context.new_rvalue_from_int(self.bool_type, 1); self.llbb().end_with_conditional(None, condition, then, catch); @@ -1161,22 +1190,61 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { } fn set_personality_fn(&mut self, _personality: RValue<'gcc>) { - // TODO(antoyo) + #[cfg(feature="master")] + { + let personality = self.rvalue_as_function(_personality); + self.current_func().set_personality_function(personality); + } } + #[cfg(feature="master")] + fn cleanup_landing_pad(&mut self, _ty: Type<'gcc>, pers_fn: RValue<'gcc>) -> RValue<'gcc> { + self.set_personality_fn(pers_fn); + + // NOTE: insert the current block in a variable so that a later call to invoke knows to + // generate a try/finally instead of a try/catch for this block. + self.cleanup_blocks.borrow_mut().insert(self.block); + + let eh_pointer_builtin = self.cx.context.get_target_builtin_function("__builtin_eh_pointer"); + let zero = self.cx.context.new_rvalue_zero(self.int_type); + let ptr = self.cx.context.new_call(None, eh_pointer_builtin, &[zero]); + + let field1_type = self.u8_type.make_pointer(); + let field1 = self.context.new_field(None, field1_type, "landing_pad_field_1"); + let field2 = self.context.new_field(None, self.i32_type, "landing_pad_field_2"); + let struct_type = self.context.new_struct_type(None, "landing_pad", &[field1, field2]); + let value = self.current_func().new_local(None, struct_type.as_type(), "landing_pad"); + let ptr = self.cx.context.new_cast(None, ptr, field1_type); + self.block.add_assignment(None, value.access_field(None, field1), ptr); + self.block.add_assignment(None, value.access_field(None, field2), zero); // TODO: set the proper value here (the type of exception?). + + value.to_rvalue() + } + + #[cfg(not(feature="master"))] fn cleanup_landing_pad(&mut self, _ty: Type<'gcc>, _pers_fn: RValue<'gcc>) -> RValue<'gcc> { let field1 = self.context.new_field(None, self.u8_type.make_pointer(), "landing_pad_field_1"); let field2 = self.context.new_field(None, self.i32_type, "landing_pad_field_1"); let struct_type = self.context.new_struct_type(None, "landing_pad", &[field1, field2]); self.current_func().new_local(None, struct_type.as_type(), "landing_pad") .to_rvalue() - // TODO(antoyo): Properly implement unwinding. - // the above is just to make the compilation work as it seems - // rustc_codegen_ssa now calls the unwinding builder methods even on panic=abort. } + #[cfg(feature="master")] + fn resume(&mut self, exn: RValue<'gcc>) { + // TODO: check if this is normal that we need to dereference the value. + // NOTE: the type is wrong, so in order to get a pointer for parameter, cast it to a + // pointer of pointer that is later dereferenced. + let exn_type = exn.get_type().make_pointer(); + let exn = self.context.new_cast(None, exn, exn_type); + let exn = exn.dereference(None).to_rvalue(); + let unwind_resume = self.context.get_target_builtin_function("__builtin_unwind_resume"); + self.llbb().add_eval(None, self.context.new_call(None, unwind_resume, &[exn])); + self.unreachable(); + } + + #[cfg(not(feature="master"))] fn resume(&mut self, _exn: RValue<'gcc>) { - // TODO(bjorn3): Properly implement unwinding. self.unreachable(); } diff --git a/src/callee.rs b/src/callee.rs index be7d48b2279..70cdece7f0a 100644 --- a/src/callee.rs +++ b/src/callee.rs @@ -1,11 +1,9 @@ #[cfg(feature="master")] use gccjit::{FnAttribute, Visibility}; -use gccjit::{FunctionType, RValue}; -use rustc_codegen_ssa::traits::BaseTypeMethods; +use gccjit::{FunctionType, Function}; use rustc_middle::ty::{self, Instance, TypeVisitable}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; -use crate::abi::FnAbiGccExt; use crate::attributes; use crate::context::CodegenCx; @@ -16,22 +14,26 @@ use crate::context::CodegenCx; /// /// - `cx`: the crate context /// - `instance`: the instance to be instantiated -pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) -> RValue<'gcc> { +pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) -> Function<'gcc> { let tcx = cx.tcx(); assert!(!instance.substs.needs_infer()); assert!(!instance.substs.has_escaping_bound_vars()); + let sym = tcx.symbol_name(instance).name; + if let Some(&func) = cx.function_instances.borrow().get(&instance) { return func; } - let sym = tcx.symbol_name(instance).name; - let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty()); let func = - if let Some(func) = cx.get_declared_value(&sym) { + if let Some(_func) = cx.get_declared_value(&sym) { + // FIXME: we never reach this because get_declared_value only returns global variables + // and here we try to get a function. + unreachable!(); + /* // Create a fn pointer with the new signature. let ptrty = fn_abi.ptr_to_gcc_type(cx); @@ -64,7 +66,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) } else { func - } + }*/ } else { cx.linkage.set(FunctionType::Extern); @@ -163,8 +165,7 @@ pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) } } - // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API. - unsafe { std::mem::transmute(func) } + func }; cx.function_instances.borrow_mut().insert(instance, func); diff --git a/src/context.rs b/src/context.rs index 5f34ddd92ba..a66e13b6008 100644 --- a/src/context.rs +++ b/src/context.rs @@ -4,6 +4,7 @@ use gccjit::{Block, CType, Context, Function, FunctionPtrType, FunctionType, LVa use rustc_codegen_ssa::base::wants_msvc_seh; use rustc_codegen_ssa::traits::{ BackendTypes, + BaseTypeMethods, MiscMethods, }; use rustc_data_structures::base_n; @@ -11,7 +12,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::span_bug; use rustc_middle::mir::mono::CodegenUnit; use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt}; -use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers}; +use rustc_middle::ty::layout::{FnAbiError, FnAbiOf, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers}; use rustc_session::Session; use rustc_span::Span; use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx}; @@ -82,7 +83,7 @@ pub struct CodegenCx<'gcc, 'tcx> { /// Cache instances of monomorphic and polymorphic items pub instances: RefCell<FxHashMap<Instance<'tcx>, LValue<'gcc>>>, /// Cache function instances of monomorphic and polymorphic items - pub function_instances: RefCell<FxHashMap<Instance<'tcx>, RValue<'gcc>>>, + pub function_instances: RefCell<FxHashMap<Instance<'tcx>, Function<'gcc>>>, /// Cache generated vtables pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>>, @@ -109,6 +110,7 @@ pub struct CodegenCx<'gcc, 'tcx> { local_gen_sym_counter: Cell<usize>, eh_personality: Cell<Option<RValue<'gcc>>>, + pub rust_try_fn: Cell<Option<(Type<'gcc>, Function<'gcc>)>>, pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>, @@ -118,6 +120,8 @@ pub struct CodegenCx<'gcc, 'tcx> { /// they can be dereferenced later. /// FIXME(antoyo): fix the rustc API to avoid having this hack. pub structs_as_pointer: RefCell<FxHashSet<RValue<'gcc>>>, + + pub cleanup_blocks: RefCell<FxHashSet<Block<'gcc>>>, } impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { @@ -245,15 +249,18 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { struct_types: Default::default(), local_gen_sym_counter: Cell::new(0), eh_personality: Cell::new(None), + rust_try_fn: Cell::new(None), pointee_infos: Default::default(), structs_as_pointer: Default::default(), + cleanup_blocks: Default::default(), } } pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> { let function: Function<'gcc> = unsafe { std::mem::transmute(value) }; + // FIXME: seems like self.functions get overwritten for rust_eh_personality. debug_assert!(self.functions.borrow().values().find(|value| **value == function).is_some(), - "{:?} ({:?}) is not a function", value, value.get_type()); + "{:?} is not a function", function); function } @@ -326,8 +333,8 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn get_fn(&self, instance: Instance<'tcx>) -> RValue<'gcc> { let func = get_fn(self, instance); - *self.current_func.borrow_mut() = Some(self.rvalue_as_function(func)); - func + *self.current_func.borrow_mut() = Some(func); + unsafe { std::mem::transmute(func) } } fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> { @@ -338,8 +345,7 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.intrinsics.borrow()[func_name].clone() } else { - let func = get_fn(self, instance); - self.rvalue_as_function(func) + get_fn(self, instance) }; let ptr = func.get_address(None); @@ -377,31 +383,40 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { return llpersonality; } let tcx = self.tcx; - let llfn = match tcx.lang_items().eh_personality() { - Some(def_id) if !wants_msvc_seh(self.sess()) => self.get_fn_addr( - ty::Instance::resolve( - tcx, - ty::ParamEnv::reveal_all(), - def_id, - tcx.intern_substs(&[]), - ) - .unwrap().unwrap(), - ), - _ => { - let _name = if wants_msvc_seh(self.sess()) { - "__CxxFrameHandler3" - } else { - "rust_eh_personality" - }; - //let func = self.declare_func(name, self.type_i32(), &[], true); - // FIXME(antoyo): this hack should not be needed. That will probably be removed when - // unwinding support is added. - self.context.new_rvalue_from_int(self.int_type, 0) - } - }; + let func = + match tcx.lang_items().eh_personality() { + Some(def_id) if !wants_msvc_seh(self.sess()) => { + let instance = + ty::Instance::resolve( + tcx, + ty::ParamEnv::reveal_all(), + def_id, + tcx.intern_substs(&[]), + ) + .unwrap().unwrap(); + + let symbol_name = tcx.symbol_name(instance).name; + let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty()); + self.linkage.set(FunctionType::Extern); + let func = self.declare_fn(symbol_name, &fn_abi); + let func: RValue<'gcc> = unsafe { std::mem::transmute(func) }; + func + }, + _ => { + let name = + if wants_msvc_seh(self.sess()) { + "__CxxFrameHandler3" + } + else { + "rust_eh_personality" + }; + let func = self.declare_func(name, self.type_i32(), &[], true); + unsafe { std::mem::transmute(func) } + } + }; // TODO(antoyo): apply target cpu attributes. - self.eh_personality.set(Some(llfn)); - llfn + self.eh_personality.set(Some(func)); + func } fn sess(&self) -> &Session { diff --git a/src/declare.rs b/src/declare.rs index 5f6360a7da5..b4b7d1b011e 100644 --- a/src/declare.rs +++ b/src/declare.rs @@ -38,12 +38,10 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { global } - /*pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> RValue<'gcc> { - self.linkage.set(FunctionType::Exported); - let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic); - // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API. - unsafe { std::mem::transmute(func) } - }*/ + pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> Function<'gcc> { + self.linkage.set(FunctionType::Extern); + declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic) + } pub fn declare_global(&self, name: &str, ty: Type<'gcc>, global_kind: GlobalKind, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> { let global = self.context.new_global(None, global_kind, ty, name); diff --git a/src/intrinsic/llvm.rs b/src/intrinsic/llvm.rs index 4552ab95e53..ee0ea6e993f 100644 --- a/src/intrinsic/llvm.rs +++ b/src/intrinsic/llvm.rs @@ -705,9 +705,9 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function "llvm.x86.aesni.aesenclast.512" => "__builtin_ia32_vaesenclast_v64qi", "llvm.x86.aesni.aesdec.512" => "__builtin_ia32_vaesdec_v64qi", "llvm.x86.aesni.aesdeclast.512" => "__builtin_ia32_vaesdeclast_v64qi", - "llvm.x86.avx512bf16.cvtne2ps2bf16.128" => "__builtin_ia32_cvtne2ps2bf16_v8hi", - "llvm.x86.avx512bf16.cvtne2ps2bf16.256" => "__builtin_ia32_cvtne2ps2bf16_v16hi", - "llvm.x86.avx512bf16.cvtne2ps2bf16.512" => "__builtin_ia32_cvtne2ps2bf16_v32hi", + "llvm.x86.avx512bf16.cvtne2ps2bf16.128" => "__builtin_ia32_cvtne2ps2bf16_v8bf", + "llvm.x86.avx512bf16.cvtne2ps2bf16.256" => "__builtin_ia32_cvtne2ps2bf16_v16bf", + "llvm.x86.avx512bf16.cvtne2ps2bf16.512" => "__builtin_ia32_cvtne2ps2bf16_v32bf", "llvm.x86.avx512bf16.cvtneps2bf16.256" => "__builtin_ia32_cvtneps2bf16_v8sf", "llvm.x86.avx512bf16.cvtneps2bf16.512" => "__builtin_ia32_cvtneps2bf16_v16sf", "llvm.x86.avx512bf16.dpbf16ps.128" => "__builtin_ia32_dpbf16ps_v4sf", diff --git a/src/intrinsic/mod.rs b/src/intrinsic/mod.rs index e3461b97973..46471096e91 100644 --- a/src/intrinsic/mod.rs +++ b/src/intrinsic/mod.rs @@ -1,6 +1,9 @@ pub mod llvm; mod simd; +#[cfg(feature="master")] +use std::iter; + use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp, FunctionType}; use rustc_codegen_ssa::MemFlags; use rustc_codegen_ssa::base::wants_msvc_seh; @@ -8,15 +11,23 @@ use rustc_codegen_ssa::common::{IntPredicate, span_invalid_monomorphization_erro use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods}; +#[cfg(feature="master")] +use rustc_codegen_ssa::traits::{DerivedTypeMethods, MiscMethods}; use rustc_middle::bug; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::ty::layout::LayoutOf; +#[cfg(feature="master")] +use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt}; use rustc_span::{Span, Symbol, symbol::kw, sym}; use rustc_target::abi::HasDataLayout; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; use rustc_target::spec::PanicStrategy; +#[cfg(feature="master")] +use rustc_target::spec::abi::Abi; use crate::abi::GccType; +#[cfg(feature="master")] +use crate::abi::FnAbiGccExt; use crate::builder::Builder; use crate::common::{SignType, TypeReflection}; use crate::context::CodegenCx; @@ -1115,10 +1126,8 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { } } -fn try_intrinsic<'gcc, 'tcx>(bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) { - // NOTE: the `|| true` here is to use the panic=abort strategy with panic=unwind too - if bx.sess().panic_strategy() == PanicStrategy::Abort || true { - // TODO(bjorn3): Properly implement unwinding and remove the `|| true` once this is done. +fn try_intrinsic<'a, 'b, 'gcc, 'tcx>(bx: &'b mut Builder<'a, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) { + if bx.sess().panic_strategy() == PanicStrategy::Abort { bx.call(bx.type_void(), try_func, &[data], None); // Return 0 unconditionally from the intrinsic call; // we can never unwind. @@ -1129,6 +1138,143 @@ fn try_intrinsic<'gcc, 'tcx>(bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue< unimplemented!(); } else { + #[cfg(feature="master")] + codegen_gnu_try(bx, try_func, data, _catch_func, dest); + #[cfg(not(feature="master"))] unimplemented!(); } } + +// Definition of the standard `try` function for Rust using the GNU-like model +// of exceptions (e.g., the normal semantics of LLVM's `landingpad` and `invoke` +// instructions). +// +// This codegen is a little surprising because we always call a shim +// function instead of inlining the call to `invoke` manually here. This is done +// because in LLVM we're only allowed to have one personality per function +// definition. The call to the `try` intrinsic is being inlined into the +// function calling it, and that function may already have other personality +// functions in play. By calling a shim we're guaranteed that our shim will have +// the right personality function. +#[cfg(feature="master")] +fn codegen_gnu_try<'gcc>(bx: &mut Builder<'_, 'gcc, '_>, try_func: RValue<'gcc>, data: RValue<'gcc>, catch_func: RValue<'gcc>, dest: RValue<'gcc>) { + //use std::ops::Deref; + //let cx: &CodegenCx<'gcc, '_> = bx.deref(); + let cx: &CodegenCx<'gcc, '_> = bx.cx; + let (llty, func) = get_rust_try_fn(cx, &mut |mut bx| { + // Codegens the shims described above: + // + // bx: + // invoke %try_func(%data) normal %normal unwind %catch + // + // normal: + // ret 0 + // + // catch: + // (%ptr, _) = landingpad + // call %catch_func(%data, %ptr) + // ret 1 + let then = bx.append_sibling_block("then"); + let catch = bx.append_sibling_block("catch"); + + let func = bx.current_func(); + let try_func = func.get_param(0).to_rvalue(); + let data = func.get_param(1).to_rvalue(); + let catch_func = func.get_param(2).to_rvalue(); + let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void()); + + let current_block = bx.block.clone(); + + bx.switch_to_block(then); + bx.ret(bx.const_i32(0)); + + // Type indicator for the exception being thrown. + // + // The value is a pointer to the exception object + // being thrown. + bx.switch_to_block(catch); + bx.set_personality_fn(bx.eh_personality()); + + let eh_pointer_builtin = bx.cx.context.get_target_builtin_function("__builtin_eh_pointer"); + let zero = bx.cx.context.new_rvalue_zero(bx.int_type); + let ptr = bx.cx.context.new_call(None, eh_pointer_builtin, &[zero]); + let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void()); + bx.call(catch_ty, catch_func, &[data, ptr], None); + bx.ret(bx.const_i32(1)); + + // NOTE: the blocks must be filled before adding the try/catch, otherwise gcc will not + // generate a try/catch. + // FIXME: add a check in the libgccjit API to prevent this. + bx.switch_to_block(current_block); + bx.invoke(try_func_ty, try_func, &[data], then, catch, None); + }); + + let func = unsafe { std::mem::transmute(func) }; + + // 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(llty, func, &[try_func, data, catch_func], None); + let i32_align = bx.tcx().data_layout.i32_align.abi; + bx.store(ret, dest, i32_align); +} + + +// Helper function used to get a handle to the `__rust_try` function used to +// catch exceptions. +// +// This function is only generated once and is then cached. +#[cfg(feature="master")] +fn get_rust_try_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, codegen: &mut dyn FnMut(Builder<'a, 'gcc, 'tcx>)) -> (Type<'gcc>, Function<'gcc>) { + if let Some(llfn) = cx.rust_try_fn.get() { + return llfn; + } + + // 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); + // `unsafe fn(*mut i8) -> ()` + let try_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig( + iter::once(i8p), + tcx.mk_unit(), + false, + rustc_hir::Unsafety::Unsafe, + Abi::Rust, + ))); + // `unsafe fn(*mut i8, *mut i8) -> ()` + let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig( + [i8p, i8p].iter().cloned(), + tcx.mk_unit(), + false, + rustc_hir::Unsafety::Unsafe, + Abi::Rust, + ))); + // `unsafe fn(unsafe fn(*mut i8) -> (), *mut i8, unsafe fn(*mut i8, *mut i8) -> ()) -> i32` + let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig( + [try_fn_ty, i8p, catch_fn_ty].iter(), + &tcx.types.i32, + false, + rustc_hir::Unsafety::Unsafe, + Abi::Rust, + )); + let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen); + cx.rust_try_fn.set(Some(rust_try)); + rust_try +} + +// Helper function to give a Block to a closure to codegen a shim function. +// This is currently primarily used for the `try` intrinsic functions above. +#[cfg(feature="master")] +fn gen_fn<'a, 'gcc, 'tcx>(cx: &'a CodegenCx<'gcc, 'tcx>, name: &str, rust_fn_sig: ty::PolyFnSig<'tcx>, codegen: &mut dyn FnMut(Builder<'a, 'gcc, 'tcx>)) -> (Type<'gcc>, Function<'gcc>) { + let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty()); + let (typ, _, _, _) = fn_abi.gcc_type(cx); + // FIXME(eddyb) find a nicer way to do this. + cx.linkage.set(FunctionType::Internal); + let func = cx.declare_fn(name, fn_abi); + let func_val = unsafe { std::mem::transmute(func) }; + cx.set_frame_pointer_type(func_val); + cx.apply_target_cpu_attr(func_val); + let block = Builder::append_block(cx, func_val, "entry-block"); + let bx = Builder::build(cx, block); + codegen(bx); + (typ, func) +} diff --git a/src/mono_item.rs b/src/mono_item.rs index ce439d339b6..0491fffc8ab 100644 --- a/src/mono_item.rs +++ b/src/mono_item.rs @@ -59,5 +59,8 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> { // TODO(antoyo): call set_link_section() to allow initializing argc/argv. // TODO(antoyo): set unique comdat. // TODO(antoyo): use inline attribute from there in linkage.set() above. + + self.functions.borrow_mut().insert(symbol_name.to_string(), decl); + self.function_instances.borrow_mut().insert(instance, unsafe { std::mem::transmute(decl) }); } } diff --git a/test.sh b/test.sh index 12a14190e49..4c490f04ae9 100755 --- a/test.sh +++ b/test.sh @@ -191,11 +191,11 @@ function std_tests() { $RUN_WRAPPER ./target/out/std_example --target $TARGET_TRIPLE echo "[AOT] subslice-patterns-const-eval" - $RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE + $RUSTC example/subslice-patterns-const-eval.rs --crate-type bin $TEST_FLAGS --target $TARGET_TRIPLE $RUN_WRAPPER ./target/out/subslice-patterns-const-eval echo "[AOT] track-caller-attribute" - $RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE + $RUSTC example/track-caller-attribute.rs --crate-type bin $TEST_FLAGS --target $TARGET_TRIPLE $RUN_WRAPPER ./target/out/track-caller-attribute echo "[BUILD] mod_bench" @@ -338,9 +338,9 @@ function test_rustc() { git checkout -- src/test/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed - rm -r src/test/ui/{abi*,extern/,panic-runtime/,panics/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,borrowck/,chalkify/bugs/,test*,*lto*.rs,consts/const-float-bits-reject-conv.rs,consts/issue-miri-1910.rs} || true + rm -r src/test/ui/{abi*,extern/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,borrowck/,chalkify/bugs/,test*,*lto*.rs,consts/const-float-bits-reject-conv.rs,consts/issue-miri-1910.rs} || true rm src/test/ui/mir/mir_heavy_promoted.rs # this tests is oom-killed in the CI. - for test in $(rg --files-with-matches "catch_unwind|should_panic|thread|lto" src/test/ui); do + for test in $(rg --files-with-matches "thread|lto" src/test/ui); do rm $test done git checkout src/test/ui/lto/auxiliary/dylib.rs @@ -348,7 +348,7 @@ function test_rustc() { git checkout src/test/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs git checkout src/test/ui/macros/rfc-2011-nicer-assert-messages/auxiliary/common.rs - RUSTC_ARGS="-Zpanic-abort-tests -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot -Cpanic=abort" + RUSTC_ARGS="$TEST_FLAGS -Csymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot" if [ $# -eq 0 ]; then # No argument supplied to the function. Doing nothing. diff --git a/tests/lang_tests_common.rs b/tests/lang_tests_common.rs index 8e378177e24..06de26f7efc 100644 --- a/tests/lang_tests_common.rs +++ b/tests/lang_tests_common.rs @@ -46,11 +46,15 @@ pub fn main_inner(profile: Profile) { &format!("-Zcodegen-backend={}/target/debug/librustc_codegen_gcc.so", current_dir), "--sysroot", &format!("{}/build_sysroot/sysroot/", current_dir), "-Zno-parallel-llvm", - "-C", "panic=abort", "-C", "link-arg=-lc", "-o", exe.to_str().expect("to_str"), path.to_str().expect("to_str"), ]); + if let Some(flags) = option_env!("TEST_FLAGS") { + for flag in flags.split_whitespace() { + compiler.arg(&flag); + } + } match profile { Profile::Debug => {} Profile::Release => { diff --git a/tests/run/int.rs b/tests/run/int.rs index 2b90e4ae8d8..5693b6a215a 100644 --- a/tests/run/int.rs +++ b/tests/run/int.rs @@ -3,22 +3,14 @@ // Run-time: // status: 0 -#![feature(bench_black_box, const_black_box, core_intrinsics, start)] - -#![no_std] - -#[panic_handler] -fn panic_handler(_: &core::panic::PanicInfo) -> ! { - core::intrinsics::abort(); -} +#![feature(bench_black_box, const_black_box)] /* * Code */ -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { - use core::hint::black_box; +fn main() { + use std::hint::black_box; macro_rules! check { ($ty:ty, $expr:expr) => { @@ -335,6 +327,4 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize { const VAL5: T = 73236519889708027473620326106273939584_i128; check_ops128!(); } - - 0 } |
