Skip to content

Implement unwinding #244

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Jan 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 18 additions & 0 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`).
Expand Down
2 changes: 1 addition & 1 deletion build_sysroot/build_sysroot.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 11 additions & 1 deletion example/alloc_example.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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";
Expand Down
26 changes: 26 additions & 0 deletions failing-ui-tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 9 additions & 0 deletions failing-ui-tests12.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
5 changes: 2 additions & 3 deletions src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
});
}

Expand Down Expand Up @@ -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)
Expand Down
6 changes: 5 additions & 1 deletion src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);

{
Expand Down
86 changes: 77 additions & 9 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand All @@ -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)
}

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exn here should be a struct forming a pair with the same values as the landing pad returned. By the way in the latest rustc I changed cleanup_landing_pad and resume to return/accept two separate values rather than a single pair value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I haven't sync with rustc for a while because I was having issues. I'll try to do it soon.

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();
}

Expand Down
21 changes: 11 additions & 10 deletions src/callee.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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);

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Loading