trans: Handle type_of for Rust fn's via abi::FnType.
This commit is contained in:
parent
f6bbbe1070
commit
03942056aa
@ -23,6 +23,7 @@ use trans::cabi_powerpc;
|
||||
use trans::cabi_powerpc64;
|
||||
use trans::cabi_mips;
|
||||
use trans::cabi_asmjs;
|
||||
use trans::machine::llsize_of_alloc;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of;
|
||||
|
||||
@ -146,22 +147,14 @@ impl FnType {
|
||||
let cconv = match ccx.sess().target.target.adjust_abi(abi) {
|
||||
RustIntrinsic => {
|
||||
// Intrinsics are emitted at the call site
|
||||
ccx.sess().bug("asked to register intrinsic fn");
|
||||
ccx.sess().bug("asked to compute FnType of intrinsic");
|
||||
}
|
||||
PlatformIntrinsic => {
|
||||
// Intrinsics are emitted at the call site
|
||||
ccx.sess().bug("asked to register platform intrinsic fn");
|
||||
ccx.sess().bug("asked to compute FnType of platform intrinsic");
|
||||
}
|
||||
|
||||
Rust => {
|
||||
// FIXME(#3678) Implement linking to foreign fns with Rust ABI
|
||||
ccx.sess().unimpl("foreign functions with Rust ABI");
|
||||
}
|
||||
|
||||
RustCall => {
|
||||
// FIXME(#3678) Implement linking to foreign fns with Rust ABI
|
||||
ccx.sess().unimpl("foreign functions with RustCall ABI");
|
||||
}
|
||||
Rust | RustCall => llvm::CCallConv,
|
||||
|
||||
// It's the ABI's job to select this, not us.
|
||||
System => ccx.sess().bug("system abi should be selected elsewhere"),
|
||||
@ -184,8 +177,27 @@ impl FnType {
|
||||
_ => Type::void(ccx)
|
||||
};
|
||||
|
||||
let mut args = Vec::with_capacity(sig.inputs.len() + extra_args.len());
|
||||
for ty in sig.inputs.iter().chain(extra_args.iter()) {
|
||||
let mut inputs = &sig.inputs[..];
|
||||
let extra_args = if abi == RustCall {
|
||||
assert!(!sig.variadic && extra_args.is_empty());
|
||||
|
||||
match inputs[inputs.len() - 1].sty {
|
||||
ty::TyTuple(ref tupled_arguments) => {
|
||||
inputs = &inputs[..inputs.len() - 1];
|
||||
&tupled_arguments[..]
|
||||
}
|
||||
_ => {
|
||||
unreachable!("argument to function with \"rust-call\" ABI \
|
||||
is not a tuple");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
assert!(sig.variadic || extra_args.is_empty());
|
||||
extra_args
|
||||
};
|
||||
|
||||
let mut args = Vec::with_capacity(inputs.len() + extra_args.len());
|
||||
for ty in inputs.iter().chain(extra_args.iter()) {
|
||||
let llty = c_type_of(ccx, ty);
|
||||
if type_is_fat_ptr(ccx.tcx(), ty) {
|
||||
args.extend(llty.field_types().into_iter().map(|llty| {
|
||||
@ -203,6 +215,35 @@ impl FnType {
|
||||
cconv: cconv
|
||||
};
|
||||
|
||||
if abi == Rust || abi == RustCall {
|
||||
let fixup = |arg: &mut ArgType| {
|
||||
if !arg.ty.is_aggregate() {
|
||||
// Scalars and vectors, always immediate.
|
||||
return;
|
||||
}
|
||||
let size = llsize_of_alloc(ccx, arg.ty);
|
||||
if size > llsize_of_alloc(ccx, ccx.int_type()) {
|
||||
arg.kind = Indirect;
|
||||
} else if size > 0 {
|
||||
// We want to pass small aggregates as immediates, but using
|
||||
// a LLVM aggregate type for this leads to bad optimizations,
|
||||
// so we pick an appropriately sized integer type instead.
|
||||
arg.cast = Some(Type::ix(ccx, size * 8));
|
||||
}
|
||||
};
|
||||
if let ty::FnConverging(ret_ty) = sig.output {
|
||||
// Fat pointers are returned by-value.
|
||||
if !type_is_fat_ptr(ccx.tcx(), ret_ty) &&
|
||||
fty.ret.ty != Type::void(ccx) {
|
||||
fixup(&mut fty.ret);
|
||||
}
|
||||
};
|
||||
for arg in &mut fty.args {
|
||||
fixup(arg);
|
||||
}
|
||||
return fty;
|
||||
}
|
||||
|
||||
match &ccx.sess().target.target.arch[..] {
|
||||
"x86" => cabi_x86::compute_abi_info(ccx, &mut fty),
|
||||
"x86_64" => if ccx.sess().target.target.options.is_like_windows {
|
||||
|
@ -31,7 +31,9 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
|
||||
}
|
||||
};
|
||||
|
||||
fixup(&mut fty.ret, Some(Attribute::StructRet));
|
||||
if fty.ret.ty != Type::void(ccx) {
|
||||
fixup(&mut fty.ret, Some(Attribute::StructRet));
|
||||
}
|
||||
for arg in &mut fty.args {
|
||||
fixup(arg, None);
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ use trans::abi::{Abi, FnType};
|
||||
use trans::attributes;
|
||||
use trans::context::CrateContext;
|
||||
use trans::type_::Type;
|
||||
use trans::type_of;
|
||||
|
||||
use std::ffi::CString;
|
||||
use libc::c_uint;
|
||||
@ -103,17 +102,8 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
|
||||
let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
|
||||
debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
|
||||
|
||||
let (cconv, llfty) = if f.abi == Abi::Rust || f.abi == Abi::RustCall {
|
||||
(llvm::CCallConv, type_of::type_of_rust_fn(ccx, &sig, f.abi))
|
||||
} else {
|
||||
let fty = FnType::new(ccx, f.abi, &sig, &[]);
|
||||
(fty.cconv, fty.to_llvm(ccx))
|
||||
};
|
||||
|
||||
// it is ok to directly access sig.0.output because we erased all
|
||||
// late-bound-regions above
|
||||
debug!("declare_rust_fn llfty={:?}", llfty);
|
||||
let llfn = declare_raw_fn(ccx, name, cconv, llfty);
|
||||
let fty = FnType::new(ccx, f.abi, &sig, &[]);
|
||||
let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.to_llvm(ccx));
|
||||
|
||||
if sig.output == ty::FnDiverging {
|
||||
llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoReturn);
|
||||
@ -122,7 +112,7 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
|
||||
if f.abi == Abi::Rust || f.abi == Abi::RustCall {
|
||||
attributes::from_fn_type(ccx, fn_type).apply_llfn(llfn);
|
||||
} else {
|
||||
FnType::new(ccx, f.abi, &sig, &[]).add_attributes(llfn);
|
||||
fty.add_attributes(llfn);
|
||||
}
|
||||
|
||||
llfn
|
||||
|
@ -13,7 +13,7 @@
|
||||
use middle::def_id::DefId;
|
||||
use middle::infer;
|
||||
use middle::subst;
|
||||
use trans::abi::{Abi, FnType};
|
||||
use trans::abi::FnType;
|
||||
use trans::adt;
|
||||
use trans::common::*;
|
||||
use trans::machine;
|
||||
@ -87,59 +87,6 @@ pub fn untuple_arguments<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
||||
result
|
||||
}
|
||||
|
||||
pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
|
||||
sig: &ty::FnSig<'tcx>,
|
||||
abi: Abi)
|
||||
-> Type
|
||||
{
|
||||
debug!("type_of_rust_fn(sig={:?}, abi={:?})", sig, abi);
|
||||
|
||||
assert!(!sig.variadic); // rust fns are never variadic
|
||||
|
||||
let mut atys: Vec<Type> = Vec::new();
|
||||
|
||||
// First, munge the inputs, if this has the `rust-call` ABI.
|
||||
let inputs_temp;
|
||||
let inputs = if abi == Abi::RustCall {
|
||||
inputs_temp = untuple_arguments(cx, &sig.inputs);
|
||||
&inputs_temp
|
||||
} else {
|
||||
&sig.inputs
|
||||
};
|
||||
|
||||
// Arg 0: Output pointer.
|
||||
// (if the output type is non-immediate)
|
||||
let lloutputtype = match sig.output {
|
||||
ty::FnConverging(output) => {
|
||||
let use_out_pointer = return_uses_outptr(cx, output);
|
||||
let lloutputtype = arg_type_of(cx, output);
|
||||
// Use the output as the actual return value if it's immediate.
|
||||
if use_out_pointer {
|
||||
atys.push(lloutputtype.ptr_to());
|
||||
Type::void(cx)
|
||||
} else if return_type_is_void(cx, output) {
|
||||
Type::void(cx)
|
||||
} else {
|
||||
lloutputtype
|
||||
}
|
||||
}
|
||||
ty::FnDiverging => Type::void(cx)
|
||||
};
|
||||
|
||||
// ... then explicit args.
|
||||
for input in inputs {
|
||||
let arg_ty = type_of_explicit_arg(cx, input);
|
||||
|
||||
if type_is_fat_ptr(cx.tcx(), input) {
|
||||
atys.extend(arg_ty.field_types());
|
||||
} else {
|
||||
atys.push(arg_ty);
|
||||
}
|
||||
}
|
||||
|
||||
Type::func(&atys[..], &lloutputtype)
|
||||
}
|
||||
|
||||
// A "sizing type" is an LLVM type, the size and alignment of which are
|
||||
// guaranteed to be equivalent to what you would get out of `type_of()`. It's
|
||||
// useful because:
|
||||
@ -375,11 +322,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
|
||||
ty::TyFnPtr(f) => {
|
||||
let sig = cx.tcx().erase_late_bound_regions(&f.sig);
|
||||
let sig = infer::normalize_associated_type(cx.tcx(), &sig);
|
||||
if f.abi == Abi::Rust || f.abi == Abi::RustCall {
|
||||
type_of_rust_fn(cx, &sig, f.abi).ptr_to()
|
||||
} else {
|
||||
FnType::new(cx, f.abi, &sig, &[]).to_llvm(cx).ptr_to()
|
||||
}
|
||||
FnType::new(cx, f.abi, &sig, &[]).to_llvm(cx).ptr_to()
|
||||
}
|
||||
ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx),
|
||||
ty::TyTuple(..) => {
|
||||
|
Loading…
Reference in New Issue
Block a user