]> git.lizzy.rs Git - rust.git/blob - src/abi.rs
Use anonymous lifetimes where possible
[rust.git] / src / abi.rs
1 use std::borrow::Cow;
2
3 use rustc::ty::layout::{FloatTy, Integer, Primitive, Scalar};
4 use rustc_target::spec::abi::Abi;
5
6 use crate::prelude::*;
7
8 #[derive(Copy, Clone, Debug)]
9 enum PassMode {
10     NoPass,
11     ByVal(Type),
12     ByValPair(Type, Type),
13     ByRef,
14 }
15
16 #[derive(Copy, Clone, Debug)]
17 enum EmptySinglePair<T> {
18     Empty,
19     Single(T),
20     Pair(T, T),
21 }
22
23 impl<T> EmptySinglePair<T> {
24     fn into_iter(self) -> EmptySinglePairIter<T> {
25         EmptySinglePairIter(self)
26     }
27
28     fn map<U>(self, mut f: impl FnMut(T) -> U) -> EmptySinglePair<U> {
29         match self {
30             Empty => Empty,
31             Single(v) => Single(f(v)),
32             Pair(a, b) => Pair(f(a), f(b)),
33         }
34     }
35 }
36
37 struct EmptySinglePairIter<T>(EmptySinglePair<T>);
38
39 impl<T> Iterator for EmptySinglePairIter<T> {
40     type Item = T;
41
42     fn next(&mut self) -> Option<T> {
43         match std::mem::replace(&mut self.0, Empty) {
44             Empty => None,
45             Single(v) => Some(v),
46             Pair(a, b) => {
47                 self.0 = Single(b);
48                 Some(a)
49             }
50         }
51     }
52 }
53
54 impl<T: std::fmt::Debug> EmptySinglePair<T> {
55     fn assert_single(self) -> T {
56         match self {
57             Single(v) => v,
58             _ => panic!("Called assert_single on {:?}", self)
59         }
60     }
61
62     fn assert_pair(self) -> (T, T) {
63         match self {
64             Pair(a, b) => (a, b),
65             _ => panic!("Called assert_pair on {:?}", self)
66         }
67     }
68 }
69
70 use EmptySinglePair::*;
71
72 impl PassMode {
73     fn get_param_ty(self, fx: &FunctionCx<impl Backend>) -> EmptySinglePair<Type> {
74         match self {
75             PassMode::NoPass => Empty,
76             PassMode::ByVal(clif_type) => Single(clif_type),
77             PassMode::ByValPair(a, b) => Pair(a, b),
78             PassMode::ByRef => Single(fx.pointer_type),
79         }
80     }
81 }
82
83 pub fn scalar_to_clif_type(tcx: TyCtxt, scalar: Scalar) -> Type {
84     match scalar.value {
85         Primitive::Int(int, _sign) => match int {
86             Integer::I8 => types::I8,
87             Integer::I16 => types::I16,
88             Integer::I32 => types::I32,
89             Integer::I64 => types::I64,
90             Integer::I128 => types::I128,
91         },
92         Primitive::Float(flt) => match flt {
93             FloatTy::F32 => types::F32,
94             FloatTy::F64 => types::F64,
95         },
96         Primitive::Pointer => pointer_ty(tcx),
97     }
98 }
99
100 fn get_pass_mode<'tcx>(
101     tcx: TyCtxt<'tcx>,
102     layout: TyLayout<'tcx>,
103 ) -> PassMode {
104     assert!(!layout.is_unsized());
105
106     if layout.is_zst() {
107         // WARNING zst arguments must never be passed, as that will break CastKind::ClosureFnPointer
108         PassMode::NoPass
109     } else {
110         match &layout.abi {
111             layout::Abi::Uninhabited => PassMode::NoPass,
112             layout::Abi::Scalar(scalar) => {
113                 PassMode::ByVal(scalar_to_clif_type(tcx, scalar.clone()))
114             }
115             layout::Abi::ScalarPair(a, b) => {
116                 let a = scalar_to_clif_type(tcx, a.clone());
117                 let b = scalar_to_clif_type(tcx, b.clone());
118                 if a == types::I128 && b == types::I128 {
119                     // Returning (i128, i128) by-val-pair would take 4 regs, while only 3 are
120                     // available on x86_64. Cranelift gets confused when too many return params
121                     // are used.
122                     PassMode::ByRef
123                 } else {
124                     PassMode::ByValPair(a, b)
125                 }
126             }
127
128             // FIXME implement Vector Abi in a cg_llvm compatible way
129             layout::Abi::Vector { .. } => PassMode::ByRef,
130
131             layout::Abi::Aggregate { .. } => PassMode::ByRef,
132         }
133     }
134 }
135
136 fn adjust_arg_for_abi<'tcx>(
137     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
138     arg: CValue<'tcx>,
139 ) -> EmptySinglePair<Value> {
140     match get_pass_mode(fx.tcx, arg.layout()) {
141         PassMode::NoPass => Empty,
142         PassMode::ByVal(_) => Single(arg.load_scalar(fx)),
143         PassMode::ByValPair(_, _) => {
144             let (a, b) = arg.load_scalar_pair(fx);
145             Pair(a, b)
146         }
147         PassMode::ByRef => Single(arg.force_stack(fx)),
148     }
149 }
150
151 fn clif_sig_from_fn_sig<'tcx>(tcx: TyCtxt<'tcx>, sig: FnSig<'tcx>, is_vtable_fn: bool) -> Signature {
152     let abi = match sig.abi {
153         Abi::System => {
154             if tcx.sess.target.target.options.is_like_windows {
155                 unimplemented!()
156             } else {
157                 Abi::C
158             }
159         }
160         abi => abi,
161     };
162     let (call_conv, inputs, output): (CallConv, Vec<Ty>, Ty) = match abi {
163         Abi::Rust => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()),
164         Abi::C => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()),
165         Abi::RustCall => {
166             assert_eq!(sig.inputs().len(), 2);
167             let extra_args = match sig.inputs().last().unwrap().sty {
168                 ty::Tuple(ref tupled_arguments) => tupled_arguments,
169                 _ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
170             };
171             let mut inputs: Vec<Ty> = vec![sig.inputs()[0]];
172             inputs.extend(extra_args.types());
173             (CallConv::SystemV, inputs, sig.output())
174         }
175         Abi::System => unreachable!(),
176         Abi::RustIntrinsic => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()),
177         _ => unimplemented!("unsupported abi {:?}", sig.abi),
178     };
179
180     let inputs = inputs
181         .into_iter()
182         .enumerate()
183         .map(|(i, ty)| {
184             let mut layout = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap();
185             if i == 0 && is_vtable_fn {
186                 // Virtual calls turn their self param into a thin pointer.
187                 // See https://github.com/rust-lang/rust/blob/37b6a5e5e82497caf5353d9d856e4eb5d14cbe06/src/librustc/ty/layout.rs#L2519-L2572 for more info
188                 layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.mk_mut_ptr(tcx.mk_unit()))).unwrap();
189             }
190             match get_pass_mode(tcx, layout) {
191                 PassMode::NoPass => Empty,
192                 PassMode::ByVal(clif_ty) => Single(clif_ty),
193                 PassMode::ByValPair(clif_ty_a, clif_ty_b) => Pair(clif_ty_a, clif_ty_b),
194                 PassMode::ByRef => Single(pointer_ty(tcx)),
195             }.into_iter()
196         }).flatten();
197
198     let (params, returns) = match get_pass_mode(tcx, tcx.layout_of(ParamEnv::reveal_all().and(output)).unwrap()) {
199         PassMode::NoPass => (inputs.map(AbiParam::new).collect(), vec![]),
200         PassMode::ByVal(ret_ty) => (
201             inputs.map(AbiParam::new).collect(),
202             vec![AbiParam::new(ret_ty)],
203         ),
204         PassMode::ByValPair(ret_ty_a, ret_ty_b) => (
205             inputs.map(AbiParam::new).collect(),
206             vec![AbiParam::new(ret_ty_a), AbiParam::new(ret_ty_b)],
207         ),
208         PassMode::ByRef => {
209             (
210                 Some(pointer_ty(tcx)) // First param is place to put return val
211                     .into_iter()
212                     .chain(inputs)
213                     .map(AbiParam::new)
214                     .collect(),
215                 vec![],
216             )
217         }
218     };
219
220     Signature {
221         params,
222         returns,
223         call_conv,
224     }
225 }
226
227 pub fn get_function_name_and_sig<'tcx>(
228     tcx: TyCtxt<'tcx>,
229     inst: Instance<'tcx>,
230     support_vararg: bool,
231 ) -> (String, Signature) {
232     assert!(!inst.substs.needs_infer() && !inst.substs.has_param_types());
233     let fn_sig = tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &inst.fn_sig(tcx));
234     if fn_sig.c_variadic && !support_vararg {
235         unimpl!("Variadic function definitions are not yet supported");
236     }
237     let sig = clif_sig_from_fn_sig(tcx, fn_sig, false);
238     (tcx.symbol_name(inst).as_str().to_string(), sig)
239 }
240
241 /// Instance must be monomorphized
242 pub fn import_function<'tcx>(
243     tcx: TyCtxt<'tcx>,
244     module: &mut Module<impl Backend>,
245     inst: Instance<'tcx>,
246 ) -> FuncId {
247     let (name, sig) = get_function_name_and_sig(tcx, inst, true);
248     module
249         .declare_function(&name, Linkage::Import, &sig)
250         .unwrap()
251 }
252
253 impl<'tcx, B: Backend + 'static> FunctionCx<'_, 'tcx, B> {
254     /// Instance must be monomorphized
255     pub fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
256         let func_id = import_function(self.tcx, self.module, inst);
257         let func_ref = self
258             .module
259             .declare_func_in_func(func_id, &mut self.bcx.func);
260
261         #[cfg(debug_assertions)]
262         self.add_entity_comment(func_ref, format!("{:?}", inst));
263
264         func_ref
265     }
266
267     fn lib_call(
268         &mut self,
269         name: &str,
270         input_tys: Vec<types::Type>,
271         output_tys: Vec<types::Type>,
272         args: &[Value],
273     ) -> &[Value] {
274         let sig = Signature {
275             params: input_tys.iter().cloned().map(AbiParam::new).collect(),
276             returns: output_tys.iter().cloned().map(AbiParam::new).collect(),
277             call_conv: CallConv::SystemV,
278         };
279         let func_id = self
280             .module
281             .declare_function(&name, Linkage::Import, &sig)
282             .unwrap();
283         let func_ref = self
284             .module
285             .declare_func_in_func(func_id, &mut self.bcx.func);
286         let call_inst = self.bcx.ins().call(func_ref, args);
287         #[cfg(debug_assertions)] {
288             self.add_comment(call_inst, format!("easy_call {}", name));
289         }
290         let results = self.bcx.inst_results(call_inst);
291         assert!(results.len() <= 2, "{}", results.len());
292         results
293     }
294
295     pub fn easy_call(
296         &mut self,
297         name: &str,
298         args: &[CValue<'tcx>],
299         return_ty: Ty<'tcx>,
300     ) -> CValue<'tcx> {
301         let (input_tys, args): (Vec<_>, Vec<_>) = args
302             .into_iter()
303             .map(|arg| {
304                 (
305                     self.clif_type(arg.layout().ty).unwrap(),
306                     arg.load_scalar(self),
307                 )
308             })
309             .unzip();
310         let return_layout = self.layout_of(return_ty);
311         let return_tys = if let ty::Tuple(tup) = return_ty.sty {
312             tup.types().map(|ty| self.clif_type(ty).unwrap()).collect()
313         } else {
314             vec![self.clif_type(return_ty).unwrap()]
315         };
316         let ret_vals = self.lib_call(name, input_tys, return_tys, &args);
317         match *ret_vals {
318             [] => CValue::by_ref(
319                 self.bcx
320                     .ins()
321                     .iconst(self.pointer_type, self.pointer_type.bytes() as i64),
322                 return_layout,
323             ),
324             [val] => CValue::by_val(val, return_layout),
325             [val, extra] => CValue::by_val_pair(val, extra, return_layout),
326             _ => unreachable!(),
327         }
328     }
329
330     fn self_sig(&self) -> FnSig<'tcx> {
331         self.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &self.instance.fn_sig(self.tcx))
332     }
333
334     fn return_layout(&self) -> TyLayout<'tcx> {
335         self.layout_of(self.self_sig().output())
336     }
337 }
338
339 #[cfg(debug_assertions)]
340 fn add_arg_comment<'tcx>(
341     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
342     msg: &str,
343     local: mir::Local,
344     local_field: Option<usize>,
345     params: EmptySinglePair<Value>,
346     pass_mode: PassMode,
347     ssa: crate::analyze::Flags,
348     ty: Ty<'tcx>,
349 ) {
350     let local_field = if let Some(local_field) = local_field {
351         Cow::Owned(format!(".{}", local_field))
352     } else {
353         Cow::Borrowed("")
354     };
355     let params = match params {
356         Empty => Cow::Borrowed("-"),
357         Single(param) => Cow::Owned(format!("= {:?}", param)),
358         Pair(param_a, param_b) => Cow::Owned(format!("= {:?}, {:?}", param_a, param_b)),
359     };
360     let pass_mode = format!("{:?}", pass_mode);
361     fx.add_global_comment(format!(
362         "{msg:5} {local:>3}{local_field:<5} {params:10} {pass_mode:36} {ssa:10} {ty:?}",
363         msg = msg,
364         local = format!("{:?}", local),
365         local_field = local_field,
366         params = params,
367         pass_mode = pass_mode,
368         ssa = format!("{:?}", ssa),
369         ty = ty,
370     ));
371 }
372
373 #[cfg(debug_assertions)]
374 fn add_local_header_comment(fx: &mut FunctionCx<impl Backend>) {
375     fx.add_global_comment(format!(
376         "msg   loc.idx    param    pass mode                            ssa flags  ty"
377     ));
378 }
379
380 fn local_place<'tcx>(
381     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
382     local: Local,
383     layout: TyLayout<'tcx>,
384     is_ssa: bool,
385 ) -> CPlace<'tcx> {
386     let place = if is_ssa {
387         CPlace::new_var(fx, local, layout)
388     } else {
389         let place = CPlace::new_stack_slot(fx, layout.ty);
390
391         #[cfg(debug_assertions)]
392         {
393             let TyLayout { ty, details } = layout;
394             let ty::layout::LayoutDetails {
395                 size,
396                 align,
397                 abi: _,
398                 variants: _,
399                 fields: _,
400                 largest_niche: _,
401             } = details;
402             match place {
403                 CPlace::Stack(stack_slot, _) => fx.add_entity_comment(
404                     stack_slot,
405                     format!(
406                         "{:?}: {:?} size={} align={},{}",
407                         local,
408                         ty,
409                         size.bytes(),
410                         align.abi.bytes(),
411                         align.pref.bytes(),
412                     ),
413                 ),
414                 CPlace::NoPlace(_) => fx.add_global_comment(format!(
415                     "zst    {:?}: {:?} size={} align={}, {}",
416                     local,
417                     ty,
418                     size.bytes(),
419                     align.abi.bytes(),
420                     align.pref.bytes(),
421                 )),
422                 _ => unreachable!(),
423             }
424         }
425
426         // Take stack_addr in advance to avoid many duplicate instructions
427         CPlace::for_addr(place.to_addr(fx), layout)
428     };
429
430     let prev_place = fx.local_map.insert(local, place);
431     debug_assert!(prev_place.is_none());
432     fx.local_map[&local]
433 }
434
435 fn cvalue_for_param<'tcx>(
436     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
437     start_ebb: Ebb,
438     local: mir::Local,
439     local_field: Option<usize>,
440     arg_ty: Ty<'tcx>,
441     ssa_flags: crate::analyze::Flags,
442 ) -> Option<CValue<'tcx>> {
443     let layout = fx.layout_of(arg_ty);
444     let pass_mode = get_pass_mode(fx.tcx, fx.layout_of(arg_ty));
445
446     if let PassMode::NoPass = pass_mode {
447         return None;
448     }
449
450     let clif_types = pass_mode.get_param_ty(fx);
451     let ebb_params = clif_types.map(|t| fx.bcx.append_ebb_param(start_ebb, t));
452
453     #[cfg(debug_assertions)]
454     add_arg_comment(
455         fx,
456         "arg",
457         local,
458         local_field,
459         ebb_params,
460         pass_mode,
461         ssa_flags,
462         arg_ty,
463     );
464
465     match pass_mode {
466         PassMode::NoPass => unreachable!(),
467         PassMode::ByVal(_) => Some(CValue::by_val(ebb_params.assert_single(), layout)),
468         PassMode::ByValPair(_, _) => {
469             let (a, b) = ebb_params.assert_pair();
470             Some(CValue::by_val_pair(a, b, layout))
471         }
472         PassMode::ByRef => Some(CValue::by_ref(ebb_params.assert_single(), layout)),
473     }
474 }
475
476 pub fn codegen_fn_prelude(
477     fx: &mut FunctionCx<'_, '_, impl Backend>,
478     start_ebb: Ebb,
479 ) {
480     let ssa_analyzed = crate::analyze::analyze(fx);
481
482     #[cfg(debug_assertions)]
483     fx.add_global_comment(format!("ssa {:?}", ssa_analyzed));
484
485     let ret_layout = fx.return_layout();
486     let output_pass_mode = get_pass_mode(fx.tcx, fx.return_layout());
487     let ret_param = match output_pass_mode {
488         PassMode::NoPass | PassMode::ByVal(_) | PassMode::ByValPair(_, _) => None,
489         PassMode::ByRef => Some(fx.bcx.append_ebb_param(start_ebb, fx.pointer_type)),
490     };
491
492     #[cfg(debug_assertions)]
493     {
494         add_local_header_comment(fx);
495         let ret_param = match ret_param {
496             Some(param) => Single(param),
497             None => Empty,
498         };
499         add_arg_comment(
500             fx,
501             "ret",
502             RETURN_PLACE,
503             None,
504             ret_param,
505             output_pass_mode,
506             ssa_analyzed[&RETURN_PLACE],
507             ret_layout.ty,
508         );
509     }
510
511     // None means pass_mode == NoPass
512     enum ArgKind<'tcx> {
513         Normal(Option<CValue<'tcx>>),
514         Spread(Vec<Option<CValue<'tcx>>>),
515     }
516
517     let func_params = fx
518         .mir
519         .args_iter()
520         .map(|local| {
521             let arg_ty = fx.monomorphize(&fx.mir.local_decls[local].ty);
522
523             // Adapted from https://github.com/rust-lang/rust/blob/145155dc96757002c7b2e9de8489416e2fdbbd57/src/librustc_codegen_llvm/mir/mod.rs#L442-L482
524             if Some(local) == fx.mir.spread_arg {
525                 // This argument (e.g. the last argument in the "rust-call" ABI)
526                 // is a tuple that was spread at the ABI level and now we have
527                 // to reconstruct it into a tuple local variable, from multiple
528                 // individual function arguments.
529
530                 let tupled_arg_tys = match arg_ty.sty {
531                     ty::Tuple(ref tys) => tys,
532                     _ => bug!("spread argument isn't a tuple?! but {:?}", arg_ty),
533                 };
534
535                 let mut params = Vec::new();
536                 for (i, arg_ty) in tupled_arg_tys.types().enumerate() {
537                     let param = cvalue_for_param(
538                         fx,
539                         start_ebb,
540                         local,
541                         Some(i),
542                         arg_ty,
543                         ssa_analyzed[&local],
544                     );
545                     params.push(param);
546                 }
547
548                 (local, ArgKind::Spread(params), arg_ty)
549             } else {
550                 let param =
551                     cvalue_for_param(fx, start_ebb, local, None, arg_ty, ssa_analyzed[&local]);
552                 (local, ArgKind::Normal(param), arg_ty)
553             }
554         })
555         .collect::<Vec<(Local, ArgKind, Ty)>>();
556
557     fx.bcx.switch_to_block(start_ebb);
558
559     match output_pass_mode {
560         PassMode::NoPass => {
561             fx.local_map
562                 .insert(RETURN_PLACE, CPlace::no_place(ret_layout));
563         }
564         PassMode::ByVal(_) | PassMode::ByValPair(_, _) => {
565             let is_ssa = !ssa_analyzed
566                 .get(&RETURN_PLACE)
567                 .unwrap()
568                 .contains(crate::analyze::Flags::NOT_SSA);
569
570             local_place(fx, RETURN_PLACE, ret_layout, is_ssa);
571         }
572         PassMode::ByRef => {
573             fx.local_map.insert(
574                 RETURN_PLACE,
575                 CPlace::for_addr(ret_param.unwrap(), ret_layout),
576             );
577         }
578     }
579
580     for (local, arg_kind, ty) in func_params {
581         let layout = fx.layout_of(ty);
582
583         let is_ssa = !ssa_analyzed
584             .get(&local)
585             .unwrap()
586             .contains(crate::analyze::Flags::NOT_SSA);
587
588         let place = local_place(fx, local, layout, is_ssa);
589
590         match arg_kind {
591             ArgKind::Normal(param) => {
592                 if let Some(param) = param {
593                     place.write_cvalue(fx, param);
594                 }
595             }
596             ArgKind::Spread(params) => {
597                 for (i, param) in params.into_iter().enumerate() {
598                     if let Some(param) = param {
599                         place
600                             .place_field(fx, mir::Field::new(i))
601                             .write_cvalue(fx, param);
602                     }
603                 }
604             }
605         }
606     }
607
608     for local in fx.mir.vars_and_temps_iter() {
609         let ty = fx.mir.local_decls[local].ty;
610         let layout = fx.layout_of(ty);
611
612         let is_ssa = !ssa_analyzed
613             .get(&local)
614             .unwrap()
615             .contains(crate::analyze::Flags::NOT_SSA);
616
617         local_place(fx, local, layout, is_ssa);
618     }
619
620     fx.bcx
621         .ins()
622         .jump(*fx.ebb_map.get(&START_BLOCK).unwrap(), &[]);
623 }
624
625 pub fn codegen_terminator_call<'tcx>(
626     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
627     func: &Operand<'tcx>,
628     args: &[Operand<'tcx>],
629     destination: &Option<(Place<'tcx>, BasicBlock)>,
630 ) {
631     let fn_ty = fx.monomorphize(&func.ty(fx.mir, fx.tcx));
632     let sig = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &fn_ty.fn_sig(fx.tcx));
633
634     let destination = destination
635         .as_ref()
636         .map(|&(ref place, bb)| (trans_place(fx, place), bb));
637
638     if let ty::FnDef(def_id, substs) = fn_ty.sty {
639         let instance =
640             ty::Instance::resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap();
641
642         if fx.tcx.symbol_name(instance).as_str().starts_with("llvm.") {
643             crate::llvm_intrinsics::codegen_llvm_intrinsic_call(fx, &fx.tcx.symbol_name(instance).as_str(), substs, args, destination);
644             return;
645         }
646
647         match instance.def {
648             InstanceDef::Intrinsic(_) => {
649                 crate::intrinsics::codegen_intrinsic_call(fx, def_id, substs, args, destination);
650                 return;
651             }
652             InstanceDef::DropGlue(_, None) => {
653                 // empty drop glue - a nop.
654                 let (_, dest) = destination.expect("Non terminating drop_in_place_real???");
655                 let ret_ebb = fx.get_ebb(dest);
656                 fx.bcx.ins().jump(ret_ebb, &[]);
657                 return;
658             }
659             _ => {}
660         }
661     }
662
663     // Unpack arguments tuple for closures
664     let args = if sig.abi == Abi::RustCall {
665         assert_eq!(args.len(), 2, "rust-call abi requires two arguments");
666         let self_arg = trans_operand(fx, &args[0]);
667         let pack_arg = trans_operand(fx, &args[1]);
668         let mut args = Vec::new();
669         args.push(self_arg);
670         match pack_arg.layout().ty.sty {
671             ty::Tuple(ref tupled_arguments) => {
672                 for (i, _) in tupled_arguments.iter().enumerate() {
673                     args.push(pack_arg.value_field(fx, mir::Field::new(i)));
674                 }
675             }
676             _ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
677         }
678         args
679     } else {
680         args.into_iter()
681             .map(|arg| trans_operand(fx, arg))
682             .collect::<Vec<_>>()
683     };
684
685     codegen_call_inner(
686         fx,
687         Some(func),
688         fn_ty,
689         args,
690         destination.map(|(place, _)| place),
691     );
692
693     if let Some((_, dest)) = destination {
694         let ret_ebb = fx.get_ebb(dest);
695         fx.bcx.ins().jump(ret_ebb, &[]);
696     } else {
697         trap_unreachable(fx, "[corruption] Diverging function returned");
698     }
699 }
700
701 fn codegen_call_inner<'tcx>(
702     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
703     func: Option<&Operand<'tcx>>,
704     fn_ty: Ty<'tcx>,
705     args: Vec<CValue<'tcx>>,
706     ret_place: Option<CPlace<'tcx>>,
707 ) {
708     let fn_sig = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &fn_ty.fn_sig(fx.tcx));
709
710     let ret_layout = fx.layout_of(fn_sig.output());
711
712     let output_pass_mode = get_pass_mode(fx.tcx, fx.layout_of(fn_sig.output()));
713     let return_ptr = match output_pass_mode {
714         PassMode::NoPass => None,
715         PassMode::ByRef => match ret_place {
716             Some(ret_place) => Some(ret_place.to_addr(fx)),
717             None => Some(fx.bcx.ins().iconst(fx.pointer_type, 43)),
718         },
719         PassMode::ByVal(_) | PassMode::ByValPair(_, _) => None,
720     };
721
722     let instance = match fn_ty.sty {
723         ty::FnDef(def_id, substs) => {
724             Some(Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap())
725         }
726         _ => None,
727     };
728
729     //   | indirect call target
730     //   |         | the first argument to be passed
731     //   v         v          v virtual calls are special cased below
732     let (func_ref, first_arg, is_virtual_call) = match instance {
733         // Trait object call
734         Some(Instance {
735             def: InstanceDef::Virtual(_, idx),
736             ..
737         }) => {
738             #[cfg(debug_assertions)]
739             {
740                 let nop_inst = fx.bcx.ins().nop();
741                 fx.add_comment(
742                     nop_inst,
743                     format!("virtual call; self arg pass mode: {:?}", get_pass_mode(fx.tcx, args[0].layout())),
744                 );
745             }
746             let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0], idx);
747             (Some(method), Single(ptr), true)
748         }
749
750         // Normal call
751         Some(_) => (None, args.get(0).map(|arg| adjust_arg_for_abi(fx, *arg)).unwrap_or(Empty), false),
752
753         // Indirect call
754         None => {
755             #[cfg(debug_assertions)]
756             {
757                 let nop_inst = fx.bcx.ins().nop();
758                 fx.add_comment(nop_inst, "indirect call");
759             }
760             let func = trans_operand(fx, func.expect("indirect call without func Operand"))
761                 .load_scalar(fx);
762             (
763                 Some(func),
764                 args.get(0).map(|arg| adjust_arg_for_abi(fx, *arg)).unwrap_or(Empty),
765                 false,
766             )
767         }
768     };
769
770     let call_args: Vec<Value> = return_ptr
771         .into_iter()
772         .chain(first_arg.into_iter())
773         .chain(
774             args.into_iter()
775                 .skip(1)
776                 .map(|arg| adjust_arg_for_abi(fx, arg).into_iter())
777                 .flatten(),
778         )
779         .collect::<Vec<_>>();
780
781     let call_inst = if let Some(func_ref) = func_ref {
782         let sig = fx
783             .bcx
784             .import_signature(clif_sig_from_fn_sig(fx.tcx, fn_sig, is_virtual_call));
785         fx.bcx.ins().call_indirect(sig, func_ref, &call_args)
786     } else {
787         let func_ref = fx.get_function_ref(instance.expect("non-indirect call on non-FnDef type"));
788         fx.bcx.ins().call(func_ref, &call_args)
789     };
790
791     // FIXME find a cleaner way to support varargs
792     if fn_sig.c_variadic {
793         if fn_sig.abi != Abi::C {
794             unimpl!("Variadic call for non-C abi {:?}", fn_sig.abi);
795         }
796         let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap();
797         let abi_params = call_args
798             .into_iter()
799             .map(|arg| {
800                 let ty = fx.bcx.func.dfg.value_type(arg);
801                 if !ty.is_int() {
802                     // FIXME set %al to upperbound on float args once floats are supported
803                     unimpl!("Non int ty {:?} for variadic call", ty);
804                 }
805                 AbiParam::new(ty)
806             })
807             .collect::<Vec<AbiParam>>();
808         fx.bcx.func.dfg.signatures[sig_ref].params = abi_params;
809     }
810
811     match output_pass_mode {
812         PassMode::NoPass => {}
813         PassMode::ByVal(_) => {
814             if let Some(ret_place) = ret_place {
815                 let ret_val = fx.bcx.inst_results(call_inst)[0];
816                 ret_place.write_cvalue(fx, CValue::by_val(ret_val, ret_layout));
817             }
818         }
819         PassMode::ByValPair(_, _) => {
820             if let Some(ret_place) = ret_place {
821                 let ret_val_a = fx.bcx.inst_results(call_inst)[0];
822                 let ret_val_b = fx.bcx.inst_results(call_inst)[1];
823                 ret_place.write_cvalue(fx, CValue::by_val_pair(ret_val_a, ret_val_b, ret_layout));
824             }
825         }
826         PassMode::ByRef => {}
827     }
828 }
829
830 pub fn codegen_drop<'tcx>(
831     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
832     drop_place: CPlace<'tcx>,
833 ) {
834     let ty = drop_place.layout().ty;
835     let drop_fn = Instance::resolve_drop_in_place(fx.tcx, ty);
836
837     if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def {
838         // we don't actually need to drop anything
839     } else {
840         let drop_fn_ty = drop_fn.ty(fx.tcx);
841         match ty.sty {
842             ty::Dynamic(..) => {
843                 let (ptr, vtable) = drop_place.to_addr_maybe_unsized(fx);
844                 let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable.unwrap());
845
846                 let fn_sig = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &drop_fn_ty.fn_sig(fx.tcx));
847
848                 assert_eq!(fn_sig.output(), fx.tcx.mk_unit());
849
850                 let sig = fx
851                     .bcx
852                     .import_signature(clif_sig_from_fn_sig(fx.tcx, fn_sig, true));
853                 fx.bcx.ins().call_indirect(sig, drop_fn, &[ptr]);
854             }
855             _ => {
856                 let arg_place = CPlace::new_stack_slot(
857                     fx,
858                     fx.tcx.mk_ref(
859                         &ty::RegionKind::ReErased,
860                         TypeAndMut {
861                             ty,
862                             mutbl: crate::rustc::hir::Mutability::MutMutable,
863                         },
864                     ),
865                 );
866                 drop_place.write_place_ref(fx, arg_place);
867                 let arg_value = arg_place.to_cvalue(fx);
868                 codegen_call_inner(
869                     fx,
870                     None,
871                     drop_fn_ty,
872                     vec![arg_value],
873                     None,
874                 );
875             }
876         }
877     }
878 }
879
880 pub fn codegen_return(fx: &mut FunctionCx<impl Backend>) {
881     match get_pass_mode(fx.tcx, fx.return_layout()) {
882         PassMode::NoPass | PassMode::ByRef => {
883             fx.bcx.ins().return_(&[]);
884         }
885         PassMode::ByVal(_) => {
886             let place = fx.get_local_place(RETURN_PLACE);
887             let ret_val = place.to_cvalue(fx).load_scalar(fx);
888             fx.bcx.ins().return_(&[ret_val]);
889         }
890         PassMode::ByValPair(_, _) => {
891             let place = fx.get_local_place(RETURN_PLACE);
892             let (ret_val_a, ret_val_b) = place.to_cvalue(fx).load_scalar_pair(fx);
893             fx.bcx.ins().return_(&[ret_val_a, ret_val_b]);
894         }
895     }
896 }