Skip to content
Closed
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
8 changes: 4 additions & 4 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,18 @@ dependencies = [

[[package]]
name = "gccjit"
version = "3.4.0"
version = "3.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b2c6ee720b5459292678267e9ffed8229b11e0e27fc5ecf7618634dc6272fa4"
checksum = "796be22e4854830de9e785ddbd814b275a80fe6a975598be355c239e5b4eabe1"
dependencies = [
"gccjit_sys",
]

[[package]]
name = "gccjit_sys"
version = "1.4.0"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cea2ed05e093fd90bd21fa03a7d09e07f62103ce94de21859f048c9a6c18e42"
checksum = "3db558fc13a541c478ef791d2a88cdb276a9373f46fb2e8aa30734d19037ffa6"
dependencies = [
"libc",
]
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ default = ["master"]
[dependencies]
object = { version = "0.37.0", default-features = false, features = ["std", "read"] }
tempfile = "3.20"
gccjit = { version = "3.4.0", features = ["dlopen"] }
gccjit = { version = "3.5.0", features = ["dlopen"] }
#gccjit = { git = "https://github.com/rust-lang/gccjit.rs", branch = "error-dlopen", features = ["dlopen"] }

# Local copy.
Expand Down
107 changes: 64 additions & 43 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ use rustc_target::spec::{HasTargetSpec, HasX86AbiOpt, Target, X86Abi};
use crate::abi::FnAbiGccExt;
use crate::common::{SignType, TypeReflection, type_is_pointer};
use crate::context::CodegenCx;
use crate::errors;
use crate::intrinsic::llvm;
use crate::type_of::LayoutGccExt;

Expand Down Expand Up @@ -312,14 +311,48 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
self.block.get_function()
}

/// Shared implementation of `call` and `tail_call`. For tail call it is important that this
/// returns a bare call, and not the result assigned to a local, or the result of `add_eval`.
fn build_call(
&mut self,
typ: Type<'gcc>,
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
func: RValue<'gcc>,
args: &[RValue<'gcc>],
funclet: Option<&Funclet>,
must_tail: bool,
) -> RValue<'gcc> {
// FIXME(antoyo): remove when having a proper API.
let gcc_func = unsafe { std::mem::transmute::<RValue<'gcc>, Function<'gcc>>(func) };
let call = if self.functions.borrow().values().any(|value| *value == gcc_func) {
// FIXME(antoyo): remove when the API supports a different type for functions.
let func: Function<'gcc> = self.cx.rvalue_as_function(func);
self.function_call(func, args, funclet, must_tail)
} else {
// If it's a not function that was defined, it's a function pointer.
self.function_ptr_call(typ, fn_abi, func, args, funclet, must_tail)
};
if let Some(_fn_abi) = fn_abi {
// FIXME(bjorn3): Apply function attributes
}
call
}

pub fn function_call(
&mut self,
func: Function<'gcc>,
args: &[RValue<'gcc>],
_funclet: Option<&Funclet>,
must_tail: bool,
) -> RValue<'gcc> {
let args = self.check_call("call", func, args);

let call = self.cx.context.new_call(self.location, func, &args);
if must_tail {
// Return the bare tail call, don't assign or `add_eval` it yet.
return call;
}

// gccjit requires to use the result of functions, even when it's not used.
// That's why we assign the result to a local or call add_eval().
let return_type = func.get_return_type();
Expand All @@ -331,15 +364,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
return_type,
format!("returnValue{}", self.next_value_counter()),
);
self.block.add_assignment(
self.location,
result,
self.cx.context.new_call(self.location, func, &args),
);
self.block.add_assignment(self.location, result, call);
result.to_rvalue()
} else {
self.block
.add_eval(self.location, self.cx.context.new_call(self.location, func, &args));
self.block.add_eval(self.location, call);
// Return dummy value when not having return value.
self.context.new_rvalue_zero(self.isize_type)
}
Expand All @@ -352,6 +380,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
mut func_ptr: RValue<'gcc>,
args: &[RValue<'gcc>],
_funclet: Option<&Funclet>,
must_tail: bool,
) -> RValue<'gcc> {
let func_ptr_type = {
let func_ptr_type = func_ptr.get_type();
Expand All @@ -376,6 +405,12 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
let args_adjusted = args.len() != previous_arg_count;
let args = self.check_ptr_call("call", func_ptr, &args, &on_stack_param_indices);

if must_tail {
// Return the bare tail call, don't assign or `add_eval` it yet.
let call = self.cx.context.new_call_through_ptr(self.location, func_ptr, &args);
return call;
}

// gccjit requires to use the result of functions, even when it's not used.
// That's why we assign the result to a local or call add_eval().
let return_type = gcc_func.get_return_type();
Expand All @@ -400,20 +435,6 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
self.block.add_assignment(self.location, result, return_value);
result.to_rvalue()
} else {
#[cfg(not(feature = "master"))]
if gcc_func.get_param_count() == 0 {
// FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics.
self.block.add_eval(
self.location,
self.cx.context.new_call_through_ptr(self.location, func_ptr, &[]),
);
} else {
self.block.add_eval(
self.location,
self.cx.context.new_call_through_ptr(self.location, func_ptr, &args),
);
}
#[cfg(feature = "master")]
self.block.add_eval(
self.location,
self.cx.context.new_call_through_ptr(self.location, func_ptr, &args),
Expand Down Expand Up @@ -1798,34 +1819,34 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
funclet: Option<&Funclet>,
_instance: Option<Instance<'tcx>>,
) -> RValue<'gcc> {
// FIXME(antoyo): remove when having a proper API.
let gcc_func = unsafe { std::mem::transmute::<RValue<'gcc>, Function<'gcc>>(func) };
let call = if self.functions.borrow().values().any(|value| *value == gcc_func) {
// FIXME(antoyo): remove when the API supports a different type for functions.
let func: Function<'gcc> = self.cx.rvalue_as_function(func);
self.function_call(func, args, funclet)
} else {
// If it's a not function that was defined, it's a function pointer.
self.function_ptr_call(typ, fn_abi, func, args, funclet)
};
if let Some(_fn_abi) = fn_abi {
// FIXME(bjorn3): Apply function attributes
}
call
self.build_call(typ, fn_abi, func, args, funclet, false)
}

fn tail_call(
&mut self,
_llty: Self::Type,
llty: Self::Type,
_fn_attrs: Option<&CodegenFnAttrs>,
_fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
_llfn: Self::Value,
_args: &[Self::Value],
_funclet: Option<&Self::Funclet>,
fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
llfn: Self::Value,
args: &[Self::Value],
funclet: Option<&Self::Funclet>,
_instance: Option<Instance<'tcx>>,
) {
// FIXME: implement support for explicit tail calls like rustc_codegen_llvm.
self.tcx.dcx().emit_fatal(errors::ExplicitTailCallsUnsupported);
// `emit_call` returns a bare call for here, it has not been assigned or passed to add_eval.
let call = self.build_call(llty, Some(fn_abi), llfn, args, funclet, true);
call.set_require_tail_call(true);

let return_type = self.current_func().get_return_type();
let void_type = self.context.new_type::<()>();

if return_type == void_type {
// For a void return the call is emitted as its own statement, immediately
// followed by a void return, so the tail call sits in tail position.
self.llbb().add_eval(self.location, call);
self.ret_void();
} else {
self.ret(call)
}
}

fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
Expand Down
4 changes: 0 additions & 4 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ pub(crate) struct LtoBitcodeFromRlib {
pub gcc_err: String,
}

#[derive(Diagnostic)]
#[diag("explicit tail calls with the 'become' keyword are not implemented in the GCC backend")]
pub(crate) struct ExplicitTailCallsUnsupported;

#[derive(Diagnostic)]
#[diag("asm contains a NUL byte")]
pub(crate) struct NulBytesInAsm {
Expand Down
7 changes: 0 additions & 7 deletions tests/failing-ui-tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,6 @@ tests/ui/linking/no-gc-encapsulation-symbols.rs
tests/ui/panics/unwind-force-no-unwind-tables.rs
tests/ui/attributes/fn-align-dyn.rs
tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs
tests/ui/explicit-tail-calls/recursion-etc.rs
tests/ui/explicit-tail-calls/indexer.rs
tests/ui/explicit-tail-calls/drop-order.rs
tests/ui/explicit-tail-calls/become-cast-return.rs
tests/ui/explicit-tail-calls/become-indirect-return.rs
tests/ui/panics/panic-abort-backtrace-without-debuginfo.rs
tests/ui/sanitizer/kcfi-c-variadic.rs
tests/ui/sanitizer/kcfi/fn-trait-objects.rs
Expand All @@ -97,7 +92,6 @@ tests/ui/eii/linking/track_caller_cross_crate.rs
tests/ui/asm/x86_64/global_asm_escape.rs
tests/ui/lto/all-crates.rs
tests/ui/eii/default/call_default_panics.rs
tests/ui/explicit-tail-calls/indirect.rs
tests/ui/traits/inheritance/self-in-supertype.rs
tests/ui/fmt/fmt_debug/shallow.rs
tests/ui/eii/eii_impl_with_contract.rs
Expand All @@ -109,5 +103,4 @@ tests/ui/eii/static/default.rs
tests/ui/eii/static/default_cross_crate.rs
tests/ui/eii/static/default_explicit.rs
tests/ui/eii/static/default_cross_crate_explicit.rs
tests/ui/explicit-tail-calls/default-trait-method.rs
tests/ui/explicit-tail-calls/tailcc-no-signature-restriction.rs
Loading