Skip to content

Commit 54af95a

Browse files
committed
[MIR] Implement extern call support
1 parent 1586005 commit 54af95a

File tree

2 files changed

+78
-11
lines changed

2 files changed

+78
-11
lines changed

src/librustc_trans/trans/mir/block.rs

+49-11
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@
99
// except according to those terms.
1010

1111
use llvm::{BasicBlockRef, ValueRef};
12+
use rustc::middle::ty;
1213
use rustc::mir::repr as mir;
14+
use syntax::abi::Abi;
1315
use trans::adt;
16+
use trans::attributes;
1417
use trans::base;
1518
use trans::build;
16-
use trans::attributes;
1719
use trans::common::{self, Block};
1820
use trans::debuginfo::DebugLoc;
21+
use trans::foreign;
1922
use trans::type_of;
2023
use trans::type_::Type;
2124

@@ -98,12 +101,24 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
98101
let debugloc = DebugLoc::None;
99102
// The arguments we'll be passing. Plus one to account for outptr, if used.
100103
let mut llargs = Vec::with_capacity(args.len() + 1);
104+
// Types of the arguments. We do not preallocate, because this vector is only
105+
// filled when `is_foreign` is `true` and foreign calls are minority of the cases.
106+
let mut arg_tys = Vec::new();
107+
108+
// Foreign-ABI functions are translated differently
109+
let is_foreign = if let ty::TyBareFn(_, ref f) = callee.ty.sty {
110+
// We do not translate intrinsics here (they shouldn’t be functions)
111+
assert!(f.abi != Abi::RustIntrinsic && f.abi != Abi::PlatformIntrinsic);
112+
f.abi != Abi::Rust && f.abi != Abi::RustCall
113+
} else {
114+
false
115+
};
101116

102117
// Prepare the return value destination
103118
let (ret_dest_ty, must_copy_dest) = if let Some(ref d) = kind.destination() {
104119
let dest = self.trans_lvalue(bcx, d);
105120
let ret_ty = dest.ty.to_ty(bcx.tcx());
106-
if type_of::return_uses_outptr(bcx.ccx(), ret_ty) {
121+
if !is_foreign && type_of::return_uses_outptr(bcx.ccx(), ret_ty) {
107122
llargs.push(dest.llval);
108123
(Some((dest, ret_ty)), false)
109124
} else {
@@ -115,19 +130,23 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
115130

116131
// Process the rest of the args.
117132
for arg in args {
118-
match self.trans_operand(bcx, arg).val {
133+
let operand = self.trans_operand(bcx, arg);
134+
match operand.val {
119135
Ref(llval) | Immediate(llval) => llargs.push(llval),
120136
FatPtr(b, e) => {
121137
llargs.push(b);
122138
llargs.push(e);
123139
}
124140
}
141+
if is_foreign {
142+
arg_tys.push(operand.ty);
143+
}
125144
}
126145

127146
// Many different ways to call a function handled here
128-
match (base::avoid_invoke(bcx), kind) {
147+
match (is_foreign, base::avoid_invoke(bcx), kind) {
129148
// The two cases below are the only ones to use LLVM’s `invoke`.
130-
(false, &mir::CallKind::DivergingCleanup(cleanup)) => {
149+
(false, false, &mir::CallKind::DivergingCleanup(cleanup)) => {
131150
let cleanup = self.bcx(cleanup);
132151
let landingpad = self.make_landing_pad(cleanup);
133152
build::Invoke(bcx,
@@ -138,7 +157,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
138157
Some(attrs),
139158
debugloc);
140159
},
141-
(false, &mir::CallKind::ConvergingCleanup { ref targets, .. }) => {
160+
(false, false, &mir::CallKind::ConvergingCleanup { ref targets, .. }) => {
142161
let cleanup = self.bcx(targets.1);
143162
let landingpad = self.make_landing_pad(cleanup);
144163
let (target, postinvoke) = if must_copy_dest {
@@ -184,14 +203,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
184203
build::Br(target, postinvoketarget.llbb, debugloc);
185204
}
186205
},
187-
(_, &mir::CallKind::DivergingCleanup(_)) |
188-
(_, &mir::CallKind::Diverging) => {
206+
(false, _, &mir::CallKind::DivergingCleanup(_)) |
207+
(false, _, &mir::CallKind::Diverging) => {
189208
build::Call(bcx, callee.immediate(), &llargs[..], Some(attrs), debugloc);
190209
build::Unreachable(bcx);
191210
}
192-
(_, k@&mir::CallKind::ConvergingCleanup { .. }) |
193-
(_, k@&mir::CallKind::Converging { .. }) => {
194-
// Bug #20046
211+
(false, _, k@&mir::CallKind::ConvergingCleanup { .. }) |
212+
(false, _, k@&mir::CallKind::Converging { .. }) => {
213+
// FIXME: Bug #20046
195214
let target = match *k {
196215
mir::CallKind::ConvergingCleanup { targets, .. } => targets.0,
197216
mir::CallKind::Converging { target, .. } => target,
@@ -209,6 +228,25 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
209228
}
210229
build::Br(bcx, self.llblock(target), debugloc);
211230
}
231+
// Foreign functions
232+
(true, _, k) => {
233+
let (dest, _) = ret_dest_ty
234+
.expect("return destination is not set");
235+
bcx = foreign::trans_native_call(bcx,
236+
callee.ty,
237+
callee.immediate(),
238+
dest.llval,
239+
&llargs[..],
240+
arg_tys,
241+
debugloc);
242+
match *k {
243+
mir::CallKind::ConvergingCleanup { targets, .. } =>
244+
build::Br(bcx, self.llblock(targets.0), debugloc),
245+
mir::CallKind::Converging { target, .. } =>
246+
build::Br(bcx, self.llblock(target), debugloc),
247+
_ => ()
248+
};
249+
},
212250
}
213251
}
214252
}

src/test/run-pass/mir_trans_calls.rs

+29
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
// except according to those terms.
1010

1111
#![feature(rustc_attrs)]
12+
use std::os::raw;
1213

1314
#[rustc_mir]
1415
fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) {
@@ -88,6 +89,32 @@ fn test8() -> isize {
8889
Two::two()
8990
}
9091

92+
extern fn simple_extern(x: u32, y: (u32, u32)) -> u32 {
93+
x + y.0 * y.1
94+
}
95+
96+
#[rustc_mir]
97+
fn test9() -> u32 {
98+
simple_extern(41, (42, 43))
99+
}
100+
101+
extern {
102+
#[cfg_attr(windows, link_name="wsprintfA")]
103+
fn sprintf(_: *mut raw::c_char, _: *const raw::c_char, ...) -> raw::c_int;
104+
}
105+
106+
#[rustc_mir]
107+
fn test10(i: i32, j: i32, k: i32) -> Vec<raw::c_char> {
108+
let mut x: Vec<raw::c_char> = Vec::with_capacity(512);
109+
unsafe {
110+
let out = sprintf(x.as_mut_ptr(), b"%d %d %d\0".as_ptr() as *const raw::c_char, i, j, k);
111+
assert!(out > 0);
112+
x.set_len(out as usize);
113+
}
114+
x
115+
}
116+
117+
91118
#[rustc_mir]
92119
fn test_closure<F>(f: &F, x: i32, y: i32) -> i32
93120
where F: Fn(i32, i32) -> i32
@@ -117,6 +144,8 @@ fn main() {
117144
assert_eq!(test6(&Foo, 12367), 12367);
118145
assert_eq!(test7(), 1);
119146
assert_eq!(test8(), 2);
147+
assert_eq!(test9(), 41 + 42 * 43);
148+
assert_eq!(&test10(0, 42, 31415), &[48, 32, 52, 50, 32, 51, 49, 52, 49, 53]);
120149

121150
let closure = |x: i32, y: i32| { x + y };
122151
assert_eq!(test_closure(&closure, 100, 1), 101);

0 commit comments

Comments
 (0)