Skip to content

Commit 41b74b1

Browse files
committed
Auto merge of #30845 - nagisa:mir-extern-calls, r=dotdash
Supersedes #30517 Fixes #29575 cc @luqmana r? @nikomatsakis
2 parents f6dd66e + 99e8b4d commit 41b74b1

File tree

4 files changed

+109
-13
lines changed

4 files changed

+109
-13
lines changed

src/librustc_trans/trans/mir/block.rs

+51-13
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
use trans::Disr;
@@ -57,7 +60,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
5760
// The else branch of the Switch can't be hit, so branch to an unreachable
5861
// instruction so LLVM knows that
5962
let unreachable_blk = self.unreachable_block();
60-
6163
let switch = build::Switch(bcx, discr, unreachable_blk.llbb, targets.len());
6264
assert_eq!(adt_def.variants.len(), targets.len());
6365
for (adt_variant, target) in adt_def.variants.iter().zip(targets) {
@@ -98,12 +100,24 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
98100
let debugloc = DebugLoc::None;
99101
// The arguments we'll be passing. Plus one to account for outptr, if used.
100102
let mut llargs = Vec::with_capacity(args.len() + 1);
103+
// Types of the arguments. We do not preallocate, because this vector is only
104+
// filled when `is_foreign` is `true` and foreign calls are minority of the cases.
105+
let mut arg_tys = Vec::new();
106+
107+
// Foreign-ABI functions are translated differently
108+
let is_foreign = if let ty::TyBareFn(_, ref f) = callee.ty.sty {
109+
// We do not translate intrinsics here (they shouldn’t be functions)
110+
assert!(f.abi != Abi::RustIntrinsic && f.abi != Abi::PlatformIntrinsic);
111+
f.abi != Abi::Rust && f.abi != Abi::RustCall
112+
} else {
113+
false
114+
};
101115

102116
// Prepare the return value destination
103117
let (ret_dest_ty, must_copy_dest) = if let Some(d) = kind.destination() {
104118
let dest = self.trans_lvalue(bcx, d);
105119
let ret_ty = dest.ty.to_ty(bcx.tcx());
106-
if type_of::return_uses_outptr(bcx.ccx(), ret_ty) {
120+
if !is_foreign && type_of::return_uses_outptr(bcx.ccx(), ret_ty) {
107121
llargs.push(dest.llval);
108122
(Some((dest, ret_ty)), false)
109123
} else {
@@ -115,30 +129,35 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
115129

116130
// Process the rest of the args.
117131
for arg in args {
118-
match self.trans_operand(bcx, arg).val {
132+
let operand = self.trans_operand(bcx, arg);
133+
match operand.val {
119134
Ref(llval) | Immediate(llval) => llargs.push(llval),
120135
FatPtr(b, e) => {
121136
llargs.push(b);
122137
llargs.push(e);
123138
}
124139
}
140+
if is_foreign {
141+
arg_tys.push(operand.ty);
142+
}
125143
}
126144

127145
// Many different ways to call a function handled here
128-
match (base::avoid_invoke(bcx), kind) {
146+
match (is_foreign, base::avoid_invoke(bcx), kind) {
129147
// The two cases below are the only ones to use LLVM’s `invoke`.
130-
(false, &mir::CallKind::DivergingCleanup(cleanup)) => {
148+
(false, false, &mir::CallKind::DivergingCleanup(cleanup)) => {
131149
let cleanup = self.bcx(cleanup);
132150
let landingpad = self.make_landing_pad(cleanup);
151+
let unreachable_blk = self.unreachable_block();
133152
build::Invoke(bcx,
134153
callee.immediate(),
135154
&llargs[..],
136-
self.unreachable_block().llbb,
155+
unreachable_blk.llbb,
137156
landingpad.llbb,
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/rt/rust_test_helpers.c

+16
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <stdint.h>
1414
#include <assert.h>
15+
#include <stdarg.h>
1516

1617
// These functions are used in the unit tests for C ABI calls.
1718

@@ -222,3 +223,18 @@ uint64_t get_z(struct S s) {
222223
uint64_t get_c_many_params(void *a, void *b, void *c, void *d, struct quad f) {
223224
return f.c;
224225
}
226+
227+
// Calculates the average of `(x + y) / n` where x: i64, y: f64. There must be exactly n pairs
228+
// passed as variadic arguments.
229+
double rust_interesting_average(uint64_t n, ...) {
230+
va_list pairs;
231+
double sum = 0.0;
232+
int i;
233+
va_start(pairs, n);
234+
for(i = 0; i < n; i += 1) {
235+
sum += (double)va_arg(pairs, int64_t);
236+
sum += va_arg(pairs, double);
237+
}
238+
va_end(pairs);
239+
return sum / n;
240+
}

src/test/run-pass/mir_trans_calls.rs

+10
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,15 @@ fn test8() -> isize {
8888
Two::two()
8989
}
9090

91+
extern fn simple_extern(x: u32, y: (u32, u32)) -> u32 {
92+
x + y.0 * y.1
93+
}
94+
95+
#[rustc_mir]
96+
fn test9() -> u32 {
97+
simple_extern(41, (42, 43))
98+
}
99+
91100
#[rustc_mir]
92101
fn test_closure<F>(f: &F, x: i32, y: i32) -> i32
93102
where F: Fn(i32, i32) -> i32
@@ -117,6 +126,7 @@ fn main() {
117126
assert_eq!(test6(&Foo, 12367), 12367);
118127
assert_eq!(test7(), 1);
119128
assert_eq!(test8(), 2);
129+
assert_eq!(test9(), 41 + 42 * 43);
120130

121131
let closure = |x: i32, y: i32| { x + y };
122132
assert_eq!(test_closure(&closure, 100, 1), 101);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(rustc_attrs)]
12+
13+
#[link(name = "rust_test_helpers")]
14+
extern {
15+
fn rust_interesting_average(_: i64, ...) -> f64;
16+
}
17+
18+
#[rustc_mir]
19+
fn test(a: i64, b: i64, c: i64, d: i64, e: i64, f: i64) -> i64 {
20+
unsafe {
21+
rust_interesting_average(6, a, a as f64,
22+
b, b as f64,
23+
c, c as f64,
24+
d, d as f64,
25+
e, e as f64,
26+
f, f as f64) as i64
27+
}
28+
}
29+
30+
fn main(){
31+
assert_eq!(test(10, 20, 30, 40, 50, 60), 70);
32+
}

0 commit comments

Comments
 (0)