Skip to content

Commit 6f633ef

Browse files
Ariel Ben-Yehudaarielb1
authored andcommitted
tuple arguments to overloaded calls
also fix translation of "rust-call" functions, although that could use more optimizations
1 parent b7cbbc3 commit 6f633ef

File tree

4 files changed

+179
-43
lines changed

4 files changed

+179
-43
lines changed

src/librustc_mir/hair/cx/expr.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,35 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
5454
// Find the actual method implementation being called and
5555
// build the appropriate UFCS call expression with the
5656
// callee-object as self parameter.
57+
58+
// rewrite f(u, v) into FnOnce::call_once(f, (u, v))
59+
5760
let method = method_callee(cx, self, ty::MethodCall::expr(self.id));
58-
let mut argrefs = vec![fun.to_ref()];
59-
argrefs.extend(args.iter().map(|a| a.to_ref()));
61+
62+
let sig = match method.ty.sty {
63+
ty::TyBareFn(_, fn_ty) => &fn_ty.sig,
64+
_ => cx.tcx.sess.span_bug(self.span, "type of method is not an fn")
65+
};
66+
67+
let sig = cx.tcx.no_late_bound_regions(sig).unwrap_or_else(|| {
68+
cx.tcx.sess.span_bug(self.span, "method call has late-bound regions")
69+
});
70+
71+
assert_eq!(sig.inputs.len(), 2);
72+
73+
let tupled_args = Expr {
74+
ty: sig.inputs[1],
75+
temp_lifetime: cx.tcx.region_maps.temporary_scope(self.id),
76+
span: self.span,
77+
kind: ExprKind::Tuple {
78+
fields: args.iter().map(ToRef::to_ref).collect()
79+
}
80+
};
6081

6182
ExprKind::Call {
6283
ty: method.ty,
6384
fun: method.to_ref(),
64-
args: argrefs,
85+
args: vec![fun.to_ref(), tupled_args.to_ref()]
6586
}
6687
} else {
6788
let adt_data = if let hir::ExprPath(..) = fun.node {

src/librustc_trans/trans/mir/block.rs

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
// except according to those terms.
1010

1111
use llvm::{BasicBlockRef, ValueRef, OperandBundleDef};
12-
use rustc::middle::ty;
12+
use rustc::middle::ty::{self, Ty};
1313
use rustc::mir::repr as mir;
1414
use syntax::abi::Abi;
1515
use trans::adt;
@@ -26,8 +26,55 @@ use trans::type_::Type;
2626

2727
use super::MirContext;
2828
use super::operand::OperandValue::{FatPtr, Immediate, Ref};
29+
use super::operand::OperandRef;
30+
31+
#[derive(PartialEq, Eq)]
32+
enum AbiStyle {
33+
Foreign,
34+
RustCall,
35+
Rust
36+
}
2937

3038
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
39+
fn abi_style(&self, fn_ty: Ty<'tcx>) -> AbiStyle {
40+
if let ty::TyBareFn(_, ref f) = fn_ty.sty {
41+
// We do not translate intrinsics here (they shouldn’t be functions)
42+
assert!(f.abi != Abi::RustIntrinsic && f.abi != Abi::PlatformIntrinsic);
43+
44+
match f.abi {
45+
Abi::Rust => AbiStyle::Rust,
46+
Abi::RustCall => AbiStyle::RustCall,
47+
_ => AbiStyle::Foreign
48+
}
49+
} else {
50+
unreachable!()
51+
}
52+
}
53+
54+
fn arg_operands(&mut self,
55+
bcx: &BlockAndBuilder<'bcx, 'tcx>,
56+
abi_style: AbiStyle,
57+
args: &[mir::Operand<'tcx>])
58+
-> Vec<OperandRef<'tcx>>
59+
{
60+
match abi_style {
61+
AbiStyle::Foreign | AbiStyle::Rust => {
62+
args.iter().map(|arg| self.trans_operand(bcx, arg)).collect()
63+
}
64+
AbiStyle::RustCall => match args.split_last() {
65+
None => vec![],
66+
Some((tup, self_ty)) => {
67+
// we can reorder safely because of MIR
68+
let untupled_args = self.trans_operand_untupled(bcx, tup);
69+
self_ty
70+
.iter().map(|arg| self.trans_operand(bcx, arg))
71+
.chain(untupled_args.into_iter())
72+
.collect()
73+
}
74+
}
75+
}
76+
}
77+
3178
pub fn trans_block(&mut self, bb: mir::BasicBlock) {
3279
debug!("trans_block({:?})", bb);
3380

@@ -159,13 +206,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
159206
let mut arg_tys = Vec::new();
160207

161208
// Foreign-ABI functions are translated differently
162-
let is_foreign = if let ty::TyBareFn(_, ref f) = callee.ty.sty {
163-
// We do not translate intrinsics here (they shouldn’t be functions)
164-
assert!(f.abi != Abi::RustIntrinsic && f.abi != Abi::PlatformIntrinsic);
165-
f.abi != Abi::Rust && f.abi != Abi::RustCall
166-
} else {
167-
false
168-
};
209+
let abi_style = self.abi_style(callee.ty);
210+
let is_foreign = abi_style == AbiStyle::Foreign;
169211

170212
// Prepare the return value destination
171213
let (ret_dest_ty, must_copy_dest) = if let Some((ref d, _)) = *destination {
@@ -182,8 +224,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
182224
};
183225

184226
// Process the rest of the args.
185-
for arg in args {
186-
let operand = self.trans_operand(&bcx, arg);
227+
for operand in self.arg_operands(&bcx, abi_style, args) {
187228
match operand.val {
188229
Ref(llval) | Immediate(llval) => llargs.push(llval),
189230
FatPtr(b, e) => {

src/librustc_trans/trans/mir/operand.rs

Lines changed: 73 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,16 @@
99
// except according to those terms.
1010

1111
use llvm::ValueRef;
12-
use rustc::middle::ty::{Ty, TypeFoldable};
12+
use rustc::middle::ty::{self, Ty};
1313
use rustc::mir::repr as mir;
14+
use trans::adt;
1415
use trans::base;
1516
use trans::common::{self, Block, BlockAndBuilder};
1617
use trans::datum;
18+
use trans::Disr;
1719

1820
use super::{MirContext, TempRef};
21+
use super::lvalue::LvalueRef;
1922

2023
/// The representation of a Rust value. The enum variant is in fact
2124
/// uniquely determined by the value's type, but is kept as a
@@ -90,6 +93,32 @@ impl<'tcx> OperandRef<'tcx> {
9093
}
9194

9295
impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
96+
pub fn trans_load(&mut self,
97+
bcx: &BlockAndBuilder<'bcx, 'tcx>,
98+
llval: ValueRef,
99+
ty: Ty<'tcx>)
100+
-> OperandRef<'tcx>
101+
{
102+
debug!("trans_load: {} @ {:?}", bcx.val_to_string(llval), ty);
103+
104+
let val = match datum::appropriate_rvalue_mode(bcx.ccx(), ty) {
105+
datum::ByValue => {
106+
bcx.with_block(|bcx| {
107+
OperandValue::Immediate(base::load_ty(bcx, llval, ty))
108+
})
109+
}
110+
datum::ByRef if common::type_is_fat_ptr(bcx.tcx(), ty) => {
111+
let (lldata, llextra) = bcx.with_block(|bcx| {
112+
base::load_fat_ptr(bcx, llval, ty)
113+
});
114+
OperandValue::FatPtr(lldata, llextra)
115+
}
116+
datum::ByRef => OperandValue::Ref(llval)
117+
};
118+
119+
OperandRef { val: val, ty: ty }
120+
}
121+
93122
pub fn trans_operand(&mut self,
94123
bcx: &BlockAndBuilder<'bcx, 'tcx>,
95124
operand: &mir::Operand<'tcx>)
@@ -120,30 +149,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
120149
// out from their home
121150
let tr_lvalue = self.trans_lvalue(bcx, lvalue);
122151
let ty = tr_lvalue.ty.to_ty(bcx.tcx());
123-
debug!("trans_operand: tr_lvalue={} @ {:?}",
124-
bcx.val_to_string(tr_lvalue.llval),
125-
ty);
126-
let val = match datum::appropriate_rvalue_mode(bcx.ccx(), ty) {
127-
datum::ByValue => {
128-
bcx.with_block(|bcx| {
129-
OperandValue::Immediate(base::load_ty(bcx, tr_lvalue.llval, ty))
130-
})
131-
}
132-
datum::ByRef if common::type_is_fat_ptr(bcx.tcx(), ty) => {
133-
let (lldata, llextra) = bcx.with_block(|bcx| {
134-
base::load_fat_ptr(bcx, tr_lvalue.llval, ty)
135-
});
136-
OperandValue::FatPtr(lldata, llextra)
137-
}
138-
datum::ByRef => OperandValue::Ref(tr_lvalue.llval)
139-
};
140-
141-
assert!(!ty.has_erasable_regions());
142-
143-
OperandRef {
144-
val: val,
145-
ty: ty
146-
}
152+
self.trans_load(bcx, tr_lvalue.llval, ty)
147153
}
148154

149155
mir::Operand::Constant(ref constant) => {
@@ -197,4 +203,46 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
197203
}
198204
}
199205
}
206+
207+
pub fn trans_operand_untupled(&mut self,
208+
bcx: &BlockAndBuilder<'bcx, 'tcx>,
209+
operand: &mir::Operand<'tcx>)
210+
-> Vec<OperandRef<'tcx>>
211+
{
212+
// FIXME: consider having some optimization to avoid tupling/untupling
213+
// (and storing/loading in the case of immediates)
214+
215+
// avoid trans_operand for pointless copying
216+
let lv = match *operand {
217+
mir::Operand::Consume(ref lvalue) => self.trans_lvalue(bcx, lvalue),
218+
mir::Operand::Constant(ref constant) => {
219+
// FIXME: consider being less pessimized
220+
if constant.ty.is_nil() {
221+
return vec![];
222+
}
223+
224+
let ty = bcx.monomorphize(&constant.ty);
225+
let lv = LvalueRef::alloca(bcx, ty, "__untuple_alloca");
226+
let constant = self.trans_constant(bcx, constant);
227+
self.store_operand(bcx, lv.llval, constant);
228+
lv
229+
}
230+
};
231+
232+
let lv_ty = lv.ty.to_ty(bcx.tcx());
233+
let result_types = match lv_ty.sty {
234+
ty::TyTuple(ref tys) => tys,
235+
_ => bcx.tcx().sess.span_bug(
236+
self.mir.span,
237+
&format!("bad final argument to \"rust-call\" fn {:?}", lv_ty))
238+
};
239+
240+
let base_repr = adt::represent_type(bcx.ccx(), lv_ty);
241+
let base = adt::MaybeSizedValue::sized(lv.llval);
242+
result_types.iter().enumerate().map(|(n, &ty)| {
243+
self.trans_load(bcx, bcx.with_block(|bcx| {
244+
adt::trans_field_ptr(bcx, &base_repr, base, Disr(0), n)
245+
}), ty)
246+
}).collect()
247+
}
200248
}

src/test/run-pass/mir_trans_calls.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(rustc_attrs)]
11+
#![feature(rustc_attrs, unboxed_closures, fn_traits)]
1212

1313
#[rustc_mir]
1414
fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) {
@@ -117,6 +117,27 @@ fn test_fn_impl(f: &&Fn(i32, i32) -> i32, x: i32, y: i32) -> i32 {
117117
f(x, y)
118118
}
119119

120+
#[rustc_mir]
121+
fn test_fn_direct_call<F>(f: &F, x: i32, y: i32) -> i32
122+
where F: Fn(i32, i32) -> i32
123+
{
124+
f.call((x, y))
125+
}
126+
127+
#[rustc_mir]
128+
fn test_fn_const_call<F>(f: &F) -> i32
129+
where F: Fn(i32, i32) -> i32
130+
{
131+
f.call((100, -1))
132+
}
133+
134+
#[rustc_mir]
135+
fn test_fn_nil_call<F>(f: &F) -> i32
136+
where F: Fn() -> i32
137+
{
138+
f()
139+
}
140+
120141
fn main() {
121142
assert_eq!(test1(1, (2, 3), &[4, 5, 6]), (1, (2, 3), &[4, 5, 6][..]));
122143
assert_eq!(test2(98), 98);
@@ -128,9 +149,14 @@ fn main() {
128149
assert_eq!(test8(), 2);
129150
assert_eq!(test9(), 41 + 42 * 43);
130151

131-
let closure = |x: i32, y: i32| { x + y };
132-
assert_eq!(test_closure(&closure, 100, 1), 101);
152+
let r = 3;
153+
let closure = |x: i32, y: i32| { r*(x + (y*2)) };
154+
assert_eq!(test_fn_const_call(&closure), 294);
155+
assert_eq!(test_closure(&closure, 100, 1), 306);
133156
let function_object = &closure as &Fn(i32, i32) -> i32;
134-
assert_eq!(test_fn_object(function_object, 100, 2), 102);
135-
assert_eq!(test_fn_impl(&function_object, 100, 3), 103);
157+
assert_eq!(test_fn_object(function_object, 100, 2), 312);
158+
assert_eq!(test_fn_impl(&function_object, 100, 3), 318);
159+
assert_eq!(test_fn_direct_call(&closure, 100, 4), 324);
160+
161+
assert_eq!(test_fn_nil_call(&(|| 42)), 42);
136162
}

0 commit comments

Comments
 (0)