Skip to content

Commit 0394205

Browse files
committed
trans: Handle type_of for Rust fn's via abi::FnType.
1 parent f6bbbe1 commit 0394205

File tree

4 files changed

+62
-86
lines changed

4 files changed

+62
-86
lines changed

src/librustc_trans/trans/abi.rs

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use trans::cabi_powerpc;
2323
use trans::cabi_powerpc64;
2424
use trans::cabi_mips;
2525
use trans::cabi_asmjs;
26+
use trans::machine::llsize_of_alloc;
2627
use trans::type_::Type;
2728
use trans::type_of;
2829

@@ -146,22 +147,14 @@ impl FnType {
146147
let cconv = match ccx.sess().target.target.adjust_abi(abi) {
147148
RustIntrinsic => {
148149
// Intrinsics are emitted at the call site
149-
ccx.sess().bug("asked to register intrinsic fn");
150+
ccx.sess().bug("asked to compute FnType of intrinsic");
150151
}
151152
PlatformIntrinsic => {
152153
// Intrinsics are emitted at the call site
153-
ccx.sess().bug("asked to register platform intrinsic fn");
154+
ccx.sess().bug("asked to compute FnType of platform intrinsic");
154155
}
155156

156-
Rust => {
157-
// FIXME(#3678) Implement linking to foreign fns with Rust ABI
158-
ccx.sess().unimpl("foreign functions with Rust ABI");
159-
}
160-
161-
RustCall => {
162-
// FIXME(#3678) Implement linking to foreign fns with Rust ABI
163-
ccx.sess().unimpl("foreign functions with RustCall ABI");
164-
}
157+
Rust | RustCall => llvm::CCallConv,
165158

166159
// It's the ABI's job to select this, not us.
167160
System => ccx.sess().bug("system abi should be selected elsewhere"),
@@ -184,8 +177,27 @@ impl FnType {
184177
_ => Type::void(ccx)
185178
};
186179

187-
let mut args = Vec::with_capacity(sig.inputs.len() + extra_args.len());
188-
for ty in sig.inputs.iter().chain(extra_args.iter()) {
180+
let mut inputs = &sig.inputs[..];
181+
let extra_args = if abi == RustCall {
182+
assert!(!sig.variadic && extra_args.is_empty());
183+
184+
match inputs[inputs.len() - 1].sty {
185+
ty::TyTuple(ref tupled_arguments) => {
186+
inputs = &inputs[..inputs.len() - 1];
187+
&tupled_arguments[..]
188+
}
189+
_ => {
190+
unreachable!("argument to function with \"rust-call\" ABI \
191+
is not a tuple");
192+
}
193+
}
194+
} else {
195+
assert!(sig.variadic || extra_args.is_empty());
196+
extra_args
197+
};
198+
199+
let mut args = Vec::with_capacity(inputs.len() + extra_args.len());
200+
for ty in inputs.iter().chain(extra_args.iter()) {
189201
let llty = c_type_of(ccx, ty);
190202
if type_is_fat_ptr(ccx.tcx(), ty) {
191203
args.extend(llty.field_types().into_iter().map(|llty| {
@@ -203,6 +215,35 @@ impl FnType {
203215
cconv: cconv
204216
};
205217

218+
if abi == Rust || abi == RustCall {
219+
let fixup = |arg: &mut ArgType| {
220+
if !arg.ty.is_aggregate() {
221+
// Scalars and vectors, always immediate.
222+
return;
223+
}
224+
let size = llsize_of_alloc(ccx, arg.ty);
225+
if size > llsize_of_alloc(ccx, ccx.int_type()) {
226+
arg.kind = Indirect;
227+
} else if size > 0 {
228+
// We want to pass small aggregates as immediates, but using
229+
// a LLVM aggregate type for this leads to bad optimizations,
230+
// so we pick an appropriately sized integer type instead.
231+
arg.cast = Some(Type::ix(ccx, size * 8));
232+
}
233+
};
234+
if let ty::FnConverging(ret_ty) = sig.output {
235+
// Fat pointers are returned by-value.
236+
if !type_is_fat_ptr(ccx.tcx(), ret_ty) &&
237+
fty.ret.ty != Type::void(ccx) {
238+
fixup(&mut fty.ret);
239+
}
240+
};
241+
for arg in &mut fty.args {
242+
fixup(arg);
243+
}
244+
return fty;
245+
}
246+
206247
match &ccx.sess().target.target.arch[..] {
207248
"x86" => cabi_x86::compute_abi_info(ccx, &mut fty),
208249
"x86_64" => if ccx.sess().target.target.options.is_like_windows {

src/librustc_trans/trans/cabi_x86_win64.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
3131
}
3232
};
3333

34-
fixup(&mut fty.ret, Some(Attribute::StructRet));
34+
if fty.ret.ty != Type::void(ccx) {
35+
fixup(&mut fty.ret, Some(Attribute::StructRet));
36+
}
3537
for arg in &mut fty.args {
3638
fixup(arg, None);
3739
}

src/librustc_trans/trans/declare.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ use trans::abi::{Abi, FnType};
2626
use trans::attributes;
2727
use trans::context::CrateContext;
2828
use trans::type_::Type;
29-
use trans::type_of;
3029

3130
use std::ffi::CString;
3231
use libc::c_uint;
@@ -103,17 +102,8 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
103102
let sig = infer::normalize_associated_type(ccx.tcx(), &sig);
104103
debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
105104

106-
let (cconv, llfty) = if f.abi == Abi::Rust || f.abi == Abi::RustCall {
107-
(llvm::CCallConv, type_of::type_of_rust_fn(ccx, &sig, f.abi))
108-
} else {
109-
let fty = FnType::new(ccx, f.abi, &sig, &[]);
110-
(fty.cconv, fty.to_llvm(ccx))
111-
};
112-
113-
// it is ok to directly access sig.0.output because we erased all
114-
// late-bound-regions above
115-
debug!("declare_rust_fn llfty={:?}", llfty);
116-
let llfn = declare_raw_fn(ccx, name, cconv, llfty);
105+
let fty = FnType::new(ccx, f.abi, &sig, &[]);
106+
let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.to_llvm(ccx));
117107

118108
if sig.output == ty::FnDiverging {
119109
llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoReturn);
@@ -122,7 +112,7 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
122112
if f.abi == Abi::Rust || f.abi == Abi::RustCall {
123113
attributes::from_fn_type(ccx, fn_type).apply_llfn(llfn);
124114
} else {
125-
FnType::new(ccx, f.abi, &sig, &[]).add_attributes(llfn);
115+
fty.add_attributes(llfn);
126116
}
127117

128118
llfn

src/librustc_trans/trans/type_of.rs

Lines changed: 2 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
use middle::def_id::DefId;
1414
use middle::infer;
1515
use middle::subst;
16-
use trans::abi::{Abi, FnType};
16+
use trans::abi::FnType;
1717
use trans::adt;
1818
use trans::common::*;
1919
use trans::machine;
@@ -87,59 +87,6 @@ pub fn untuple_arguments<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
8787
result
8888
}
8989

90-
pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
91-
sig: &ty::FnSig<'tcx>,
92-
abi: Abi)
93-
-> Type
94-
{
95-
debug!("type_of_rust_fn(sig={:?}, abi={:?})", sig, abi);
96-
97-
assert!(!sig.variadic); // rust fns are never variadic
98-
99-
let mut atys: Vec<Type> = Vec::new();
100-
101-
// First, munge the inputs, if this has the `rust-call` ABI.
102-
let inputs_temp;
103-
let inputs = if abi == Abi::RustCall {
104-
inputs_temp = untuple_arguments(cx, &sig.inputs);
105-
&inputs_temp
106-
} else {
107-
&sig.inputs
108-
};
109-
110-
// Arg 0: Output pointer.
111-
// (if the output type is non-immediate)
112-
let lloutputtype = match sig.output {
113-
ty::FnConverging(output) => {
114-
let use_out_pointer = return_uses_outptr(cx, output);
115-
let lloutputtype = arg_type_of(cx, output);
116-
// Use the output as the actual return value if it's immediate.
117-
if use_out_pointer {
118-
atys.push(lloutputtype.ptr_to());
119-
Type::void(cx)
120-
} else if return_type_is_void(cx, output) {
121-
Type::void(cx)
122-
} else {
123-
lloutputtype
124-
}
125-
}
126-
ty::FnDiverging => Type::void(cx)
127-
};
128-
129-
// ... then explicit args.
130-
for input in inputs {
131-
let arg_ty = type_of_explicit_arg(cx, input);
132-
133-
if type_is_fat_ptr(cx.tcx(), input) {
134-
atys.extend(arg_ty.field_types());
135-
} else {
136-
atys.push(arg_ty);
137-
}
138-
}
139-
140-
Type::func(&atys[..], &lloutputtype)
141-
}
142-
14390
// A "sizing type" is an LLVM type, the size and alignment of which are
14491
// guaranteed to be equivalent to what you would get out of `type_of()`. It's
14592
// useful because:
@@ -375,11 +322,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
375322
ty::TyFnPtr(f) => {
376323
let sig = cx.tcx().erase_late_bound_regions(&f.sig);
377324
let sig = infer::normalize_associated_type(cx.tcx(), &sig);
378-
if f.abi == Abi::Rust || f.abi == Abi::RustCall {
379-
type_of_rust_fn(cx, &sig, f.abi).ptr_to()
380-
} else {
381-
FnType::new(cx, f.abi, &sig, &[]).to_llvm(cx).ptr_to()
382-
}
325+
FnType::new(cx, f.abi, &sig, &[]).to_llvm(cx).ptr_to()
383326
}
384327
ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx),
385328
ty::TyTuple(..) => {

0 commit comments

Comments
 (0)