]> git.lizzy.rs Git - rust.git/blob - src/abi.rs
Merge remote-tracking branch 'sunfishcode/master'
[rust.git] / src / abi.rs
1 use std::iter;
2
3 use rustc::hir;
4 use rustc_target::spec::abi::Abi;
5
6 use crate::prelude::*;
7
8 #[derive(Debug)]
9 enum PassMode {
10     NoPass,
11     ByVal(Type),
12     ByRef,
13 }
14
15 impl PassMode {
16     fn get_param_ty(self, fx: &FunctionCx<impl Backend>) -> Type {
17         match self {
18             PassMode::NoPass => unimplemented!("pass mode nopass"),
19             PassMode::ByVal(clif_type) => clif_type,
20             PassMode::ByRef => fx.pointer_type,
21         }
22     }
23 }
24
25 fn get_pass_mode<'a, 'tcx: 'a>(
26     tcx: TyCtxt<'a, 'tcx, 'tcx>,
27     abi: Abi,
28     ty: Ty<'tcx>,
29     is_return: bool,
30 ) -> PassMode {
31     assert!(!tcx
32         .layout_of(ParamEnv::reveal_all().and(ty))
33         .unwrap()
34         .is_unsized());
35     if let ty::Never = ty.sty {
36         if is_return {
37             PassMode::NoPass
38         } else {
39             PassMode::ByRef
40         }
41     } else if ty.sty == tcx.mk_unit().sty {
42         if is_return {
43             PassMode::NoPass
44         } else {
45             PassMode::ByRef
46         }
47     } else if let Some(ret_ty) = crate::common::clif_type_from_ty(tcx, ty) {
48         PassMode::ByVal(ret_ty)
49     } else {
50         if abi == Abi::C {
51             unimpl!(
52                 "Non scalars are not yet supported for \"C\" abi ({:?}) is_return: {:?}",
53                 ty,
54                 is_return
55             );
56         }
57         PassMode::ByRef
58     }
59 }
60
61 fn adjust_arg_for_abi<'a, 'tcx: 'a>(
62     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
63     sig: FnSig<'tcx>,
64     arg: CValue<'tcx>,
65 ) -> Value {
66     match get_pass_mode(fx.tcx, sig.abi, arg.layout().ty, false) {
67         PassMode::NoPass => unimplemented!("pass mode nopass"),
68         PassMode::ByVal(_) => arg.load_value(fx),
69         PassMode::ByRef => arg.force_stack(fx),
70     }
71 }
72
73 pub fn clif_sig_from_fn_ty<'a, 'tcx: 'a>(
74     tcx: TyCtxt<'a, 'tcx, 'tcx>,
75     fn_ty: Ty<'tcx>,
76 ) -> Signature {
77     let sig = ty_fn_sig(tcx, fn_ty);
78     assert!(!sig.variadic, "Variadic function are not yet supported");
79     let (call_conv, inputs, output): (CallConv, Vec<Ty>, Ty) = match sig.abi {
80         Abi::Rust => (CallConv::Fast, sig.inputs().to_vec(), sig.output()),
81         Abi::C => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()),
82         Abi::RustCall => {
83             assert_eq!(sig.inputs().len(), 2);
84             let extra_args = match sig.inputs().last().unwrap().sty {
85                 ty::Tuple(ref tupled_arguments) => tupled_arguments,
86                 _ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
87             };
88             let mut inputs: Vec<Ty> = vec![sig.inputs()[0]];
89             inputs.extend(extra_args.into_iter());
90             (CallConv::Fast, inputs, sig.output())
91         }
92         Abi::System => bug!("system abi should be selected elsewhere"),
93         Abi::RustIntrinsic => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()),
94         _ => unimplemented!("unsupported abi {:?}", sig.abi),
95     };
96
97     let inputs = inputs
98         .into_iter()
99         .filter_map(|ty| match get_pass_mode(tcx, sig.abi, ty, false) {
100             PassMode::ByVal(clif_ty) => Some(clif_ty),
101             PassMode::NoPass => unimplemented!("pass mode nopass"),
102             PassMode::ByRef => Some(pointer_ty(tcx)),
103         });
104
105     let (params, returns) = match get_pass_mode(tcx, sig.abi, output, true) {
106         PassMode::NoPass => (inputs.map(AbiParam::new).collect(), vec![]),
107         PassMode::ByVal(ret_ty) => (
108             inputs.map(AbiParam::new).collect(),
109             vec![AbiParam::new(ret_ty)],
110         ),
111         PassMode::ByRef => {
112             (
113                 Some(pointer_ty(tcx)) // First param is place to put return val
114                     .into_iter()
115                     .chain(inputs)
116                     .map(AbiParam::new)
117                     .collect(),
118                 vec![],
119             )
120         }
121     };
122
123     Signature {
124         params,
125         returns,
126         call_conv,
127     }
128 }
129
130 fn ty_fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> ty::FnSig<'tcx> {
131     let sig = match ty.sty {
132         ty::FnDef(..) |
133         // Shims currently have type TyFnPtr. Not sure this should remain.
134         ty::FnPtr(_) => ty.fn_sig(tcx),
135         ty::Closure(def_id, substs) => {
136             let sig = substs.closure_sig(def_id, tcx);
137
138             let env_ty = tcx.closure_env_ty(def_id, substs).unwrap();
139             sig.map_bound(|sig| tcx.mk_fn_sig(
140                 iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()),
141                 sig.output(),
142                 sig.variadic,
143                 sig.unsafety,
144                 sig.abi
145             ))
146         }
147         ty::Generator(def_id, substs, _) => {
148             let sig = substs.poly_sig(def_id, tcx);
149
150             let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
151             let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
152
153             sig.map_bound(|sig| {
154                 let state_did = tcx.lang_items().gen_state().unwrap();
155                 let state_adt_ref = tcx.adt_def(state_did);
156                 let state_substs = tcx.intern_substs(&[
157                     sig.yield_ty.into(),
158                     sig.return_ty.into(),
159                 ]);
160                 let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
161
162                 tcx.mk_fn_sig(iter::once(env_ty),
163                     ret_ty,
164                     false,
165                     hir::Unsafety::Normal,
166                     Abi::Rust
167                 )
168             })
169         }
170         _ => bug!("unexpected type {:?} to ty_fn_sig", ty)
171     };
172     tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &sig)
173 }
174
175 pub fn get_function_name_and_sig<'a, 'tcx>(
176     tcx: TyCtxt<'a, 'tcx, 'tcx>,
177     inst: Instance<'tcx>,
178 ) -> (String, Signature) {
179     assert!(!inst.substs.needs_infer() && !inst.substs.has_param_types());
180     let fn_ty = inst.ty(tcx);
181     let sig = clif_sig_from_fn_ty(tcx, fn_ty);
182     (tcx.symbol_name(inst).as_str().to_string(), sig)
183 }
184
185 impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
186     /// Instance must be monomorphized
187     pub fn get_function_id(&mut self, inst: Instance<'tcx>) -> FuncId {
188         let (name, sig) = get_function_name_and_sig(self.tcx, inst);
189         self.module
190             .declare_function(&name, Linkage::Import, &sig)
191             .unwrap()
192     }
193
194     /// Instance must be monomorphized
195     pub fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
196         let func_id = self.get_function_id(inst);
197         self.module
198             .declare_func_in_func(func_id, &mut self.bcx.func)
199     }
200
201     fn lib_call(
202         &mut self,
203         name: &str,
204         input_tys: Vec<types::Type>,
205         output_ty: Option<types::Type>,
206         args: &[Value],
207     ) -> Option<Value> {
208         let sig = Signature {
209             params: input_tys.iter().cloned().map(AbiParam::new).collect(),
210             returns: output_ty
211                 .map(|output_ty| vec![AbiParam::new(output_ty)])
212                 .unwrap_or(Vec::new()),
213             call_conv: CallConv::SystemV,
214         };
215         let func_id = self
216             .module
217             .declare_function(&name, Linkage::Import, &sig)
218             .unwrap();
219         let func_ref = self
220             .module
221             .declare_func_in_func(func_id, &mut self.bcx.func);
222         let call_inst = self.bcx.ins().call(func_ref, args);
223         if output_ty.is_none() {
224             return None;
225         }
226         let results = self.bcx.inst_results(call_inst);
227         assert_eq!(results.len(), 1);
228         Some(results[0])
229     }
230
231     pub fn easy_call(
232         &mut self,
233         name: &str,
234         args: &[CValue<'tcx>],
235         return_ty: Ty<'tcx>,
236     ) -> CValue<'tcx> {
237         let (input_tys, args): (Vec<_>, Vec<_>) = args
238             .into_iter()
239             .map(|arg| {
240                 (
241                     self.clif_type(arg.layout().ty).unwrap(),
242                     arg.load_value(self),
243                 )
244             })
245             .unzip();
246         let return_layout = self.layout_of(return_ty);
247         let return_ty = if let ty::Tuple(tup) = return_ty.sty {
248             if !tup.is_empty() {
249                 bug!("easy_call( (...) -> <non empty tuple> ) is not allowed");
250             }
251             None
252         } else {
253             Some(self.clif_type(return_ty).unwrap())
254         };
255         if let Some(val) = self.lib_call(name, input_tys, return_ty, &args) {
256             CValue::ByVal(val, return_layout)
257         } else {
258             CValue::ByRef(self.bcx.ins().iconst(self.pointer_type, 0), return_layout)
259         }
260     }
261
262     fn self_sig(&self) -> FnSig<'tcx> {
263         ty_fn_sig(self.tcx, self.instance.ty(self.tcx))
264     }
265
266     fn return_type(&self) -> Ty<'tcx> {
267         self.self_sig().output()
268     }
269 }
270
271 pub fn codegen_fn_prelude<'a, 'tcx: 'a>(
272     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
273     start_ebb: Ebb,
274 ) {
275     let ssa_analyzed = crate::analyze::analyze(fx);
276
277     let ret_layout = fx.layout_of(fx.return_type());
278     let output_pass_mode = get_pass_mode(fx.tcx, fx.self_sig().abi, fx.return_type(), true);
279     let ret_param = match output_pass_mode {
280         PassMode::NoPass => None,
281         PassMode::ByVal(_) => None,
282         PassMode::ByRef => Some(fx.bcx.append_ebb_param(start_ebb, fx.pointer_type)),
283     };
284
285     enum ArgKind {
286         Normal(Value),
287         Spread(Vec<Value>),
288     }
289
290     let func_params = fx
291         .mir
292         .args_iter()
293         .map(|local| {
294             let arg_ty = fx.monomorphize(&fx.mir.local_decls[local].ty);
295
296             // Adapted from https://github.com/rust-lang/rust/blob/145155dc96757002c7b2e9de8489416e2fdbbd57/src/librustc_codegen_llvm/mir/mod.rs#L442-L482
297             if Some(local) == fx.mir.spread_arg {
298                 // This argument (e.g. the last argument in the "rust-call" ABI)
299                 // is a tuple that was spread at the ABI level and now we have
300                 // to reconstruct it into a tuple local variable, from multiple
301                 // individual function arguments.
302
303                 let tupled_arg_tys = match arg_ty.sty {
304                     ty::Tuple(ref tys) => tys,
305                     _ => bug!("spread argument isn't a tuple?! but {:?}", arg_ty),
306                 };
307
308                 let mut ebb_params = Vec::new();
309                 for arg_ty in tupled_arg_tys.iter() {
310                     let clif_type =
311                         get_pass_mode(fx.tcx, fx.self_sig().abi, arg_ty, false).get_param_ty(fx);
312                     ebb_params.push(fx.bcx.append_ebb_param(start_ebb, clif_type));
313                 }
314
315                 (local, ArgKind::Spread(ebb_params), arg_ty)
316             } else {
317                 let clif_type =
318                     get_pass_mode(fx.tcx, fx.self_sig().abi, arg_ty, false).get_param_ty(fx);
319                 (
320                     local,
321                     ArgKind::Normal(fx.bcx.append_ebb_param(start_ebb, clif_type)),
322                     arg_ty,
323                 )
324             }
325         })
326         .collect::<Vec<(Local, ArgKind, Ty)>>();
327
328     fx.bcx.switch_to_block(start_ebb);
329
330     fx.top_nop = Some(fx.bcx.ins().nop());
331     fx.add_global_comment(format!("ssa {:?}", ssa_analyzed));
332
333     for local in fx.mir.args_iter() {
334         let arg_ty = fx.monomorphize(&fx.mir.local_decls[local].ty);
335         let pass_mode = get_pass_mode(fx.tcx, fx.self_sig().abi, arg_ty, false);
336         fx.add_global_comment(format!("pass {:?}: {:?} {:?}", local, arg_ty, pass_mode));
337     }
338
339     match output_pass_mode {
340         PassMode::NoPass => {
341             let null = fx.bcx.ins().iconst(fx.pointer_type, 0);
342             //unimplemented!("pass mode nopass");
343             fx.local_map.insert(
344                 RETURN_PLACE,
345                 CPlace::Addr(null, None, fx.layout_of(fx.return_type())),
346             );
347         }
348         PassMode::ByVal(ret_ty) => {
349             fx.bcx.declare_var(mir_var(RETURN_PLACE), ret_ty);
350             fx.local_map
351                 .insert(RETURN_PLACE, CPlace::Var(RETURN_PLACE, ret_layout));
352         }
353         PassMode::ByRef => {
354             fx.local_map.insert(
355                 RETURN_PLACE,
356                 CPlace::Addr(ret_param.unwrap(), None, ret_layout),
357             );
358         }
359     }
360
361     for (local, arg_kind, ty) in func_params {
362         let layout = fx.layout_of(ty);
363
364         if let ArgKind::Normal(ebb_param) = arg_kind {
365             if !ssa_analyzed
366                 .get(&local)
367                 .unwrap()
368                 .contains(crate::analyze::Flags::NOT_SSA)
369             {
370                 fx.bcx
371                     .declare_var(mir_var(local), fx.clif_type(ty).unwrap());
372                 match get_pass_mode(fx.tcx, fx.self_sig().abi, ty, false) {
373                     PassMode::NoPass => unimplemented!("pass mode nopass"),
374                     PassMode::ByVal(_) => fx.bcx.def_var(mir_var(local), ebb_param),
375                     PassMode::ByRef => {
376                         let val = CValue::ByRef(ebb_param, fx.layout_of(ty)).load_value(fx);
377                         fx.bcx.def_var(mir_var(local), val);
378                     }
379                 }
380                 fx.local_map.insert(local, CPlace::Var(local, layout));
381                 continue;
382             }
383         }
384
385         let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
386             kind: StackSlotKind::ExplicitSlot,
387             size: layout.size.bytes() as u32,
388             offset: None,
389         });
390
391         let place = CPlace::from_stack_slot(fx, stack_slot, ty);
392
393         match arg_kind {
394             ArgKind::Normal(ebb_param) => match get_pass_mode(fx.tcx, fx.self_sig().abi, ty, false)
395             {
396                 PassMode::NoPass => unimplemented!("pass mode nopass"),
397                 PassMode::ByVal(_) => {
398                     place.write_cvalue(fx, CValue::ByVal(ebb_param, place.layout()))
399                 }
400                 PassMode::ByRef => place.write_cvalue(fx, CValue::ByRef(ebb_param, place.layout())),
401             },
402             ArgKind::Spread(ebb_params) => {
403                 for (i, ebb_param) in ebb_params.into_iter().enumerate() {
404                     let sub_place = place.place_field(fx, mir::Field::new(i));
405                     match get_pass_mode(fx.tcx, fx.self_sig().abi, sub_place.layout().ty, false) {
406                         PassMode::NoPass => unimplemented!("pass mode nopass"),
407                         PassMode::ByVal(_) => {
408                             sub_place.write_cvalue(fx, CValue::ByVal(ebb_param, sub_place.layout()))
409                         }
410                         PassMode::ByRef => {
411                             sub_place.write_cvalue(fx, CValue::ByRef(ebb_param, sub_place.layout()))
412                         }
413                     }
414                 }
415             }
416         }
417         fx.local_map.insert(local, place);
418     }
419
420     for local in fx.mir.vars_and_temps_iter() {
421         let ty = fx.mir.local_decls[local].ty;
422         let layout = fx.layout_of(ty);
423
424         let place = if ssa_analyzed
425             .get(&local)
426             .unwrap()
427             .contains(crate::analyze::Flags::NOT_SSA)
428         {
429             let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
430                 kind: StackSlotKind::ExplicitSlot,
431                 size: layout.size.bytes() as u32,
432                 offset: None,
433             });
434             CPlace::from_stack_slot(fx, stack_slot, ty)
435         } else {
436             fx.bcx
437                 .declare_var(mir_var(local), fx.clif_type(ty).unwrap());
438             CPlace::Var(local, layout)
439         };
440
441         fx.local_map.insert(local, place);
442     }
443
444     fx.bcx
445         .ins()
446         .jump(*fx.ebb_map.get(&START_BLOCK).unwrap(), &[]);
447 }
448
449 pub fn codegen_terminator_call<'a, 'tcx: 'a>(
450     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
451     func: &Operand<'tcx>,
452     args: &[Operand<'tcx>],
453     destination: &Option<(Place<'tcx>, BasicBlock)>,
454 ) {
455     let fn_ty = fx.monomorphize(&func.ty(fx.mir, fx.tcx));
456     let sig = ty_fn_sig(fx.tcx, fn_ty);
457
458     // Unpack arguments tuple for closures
459     let args = if sig.abi == Abi::RustCall {
460         assert_eq!(args.len(), 2, "rust-call abi requires two arguments");
461         let self_arg = trans_operand(fx, &args[0]);
462         let pack_arg = trans_operand(fx, &args[1]);
463         let mut args = Vec::new();
464         args.push(self_arg);
465         match pack_arg.layout().ty.sty {
466             ty::Tuple(ref tupled_arguments) => {
467                 for (i, _) in tupled_arguments.iter().enumerate() {
468                     args.push(pack_arg.value_field(fx, mir::Field::new(i)));
469                 }
470             }
471             _ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
472         }
473         args
474     } else {
475         args.into_iter()
476             .map(|arg| trans_operand(fx, arg))
477             .collect::<Vec<_>>()
478     };
479
480     let destination = destination
481         .as_ref()
482         .map(|&(ref place, bb)| (trans_place(fx, place), bb));
483
484     if let ty::FnDef(def_id, substs) = fn_ty.sty {
485         let sig = ty_fn_sig(fx.tcx, fn_ty);
486
487         if sig.abi == Abi::RustIntrinsic {
488             crate::intrinsics::codegen_intrinsic_call(fx, def_id, substs, args, destination);
489             return;
490         }
491     }
492
493     codegen_call_inner(
494         fx,
495         Some(func),
496         fn_ty,
497         args,
498         destination.map(|(place, _)| place),
499     );
500
501     if let Some((_, dest)) = destination {
502         let ret_ebb = fx.get_ebb(dest);
503         fx.bcx.ins().jump(ret_ebb, &[]);
504     } else {
505         fx.bcx.ins().trap(TrapCode::User(!0));
506     }
507 }
508
509 pub fn codegen_call_inner<'a, 'tcx: 'a>(
510     fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
511     func: Option<&Operand<'tcx>>,
512     fn_ty: Ty<'tcx>,
513     args: Vec<CValue<'tcx>>,
514     ret_place: Option<CPlace<'tcx>>,
515 ) {
516     let sig = ty_fn_sig(fx.tcx, fn_ty);
517
518     let ret_layout = fx.layout_of(sig.output());
519
520     let output_pass_mode = get_pass_mode(fx.tcx, sig.abi, sig.output(), true);
521     let return_ptr = match output_pass_mode {
522         PassMode::NoPass => None,
523         PassMode::ByRef => match ret_place {
524             Some(ret_place) => Some(ret_place.expect_addr()),
525             None => Some(fx.bcx.ins().iconst(fx.pointer_type, 0)),
526         },
527         PassMode::ByVal(_) => None,
528     };
529
530     let instance = match fn_ty.sty {
531         ty::FnDef(def_id, substs) => {
532             Some(Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap())
533         }
534         _ => None,
535     };
536
537     let func_ref: Option<Value>; // Indirect call target
538
539     let first_arg = {
540         if let Some(Instance {
541             def: InstanceDef::Virtual(_, idx),
542             ..
543         }) = instance
544         {
545             let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0], idx);
546             func_ref = Some(method);
547             Some(ptr)
548         } else {
549             func_ref = if instance.is_none() {
550                 let func = trans_operand(fx, func.expect("indirect call without func Operand"));
551                 Some(func.load_value(fx))
552             } else {
553                 None
554             };
555
556             args.get(0).map(|arg| adjust_arg_for_abi(fx, sig, *arg))
557         }
558         .into_iter()
559     };
560
561     let call_args: Vec<Value> = return_ptr
562         .into_iter()
563         .chain(first_arg)
564         .chain(
565             args.into_iter()
566                 .skip(1)
567                 .map(|arg| adjust_arg_for_abi(fx, sig, arg)),
568         )
569         .collect::<Vec<_>>();
570
571     let sig = fx.bcx.import_signature(clif_sig_from_fn_ty(fx.tcx, fn_ty));
572     let call_inst = if let Some(func_ref) = func_ref {
573         fx.bcx.ins().call_indirect(sig, func_ref, &call_args)
574     } else {
575         let func_ref = fx.get_function_ref(instance.expect("non-indirect call on non-FnDef type"));
576         fx.bcx.ins().call(func_ref, &call_args)
577     };
578
579     match output_pass_mode {
580         PassMode::NoPass => {}
581         PassMode::ByVal(_) => {
582             if let Some(ret_place) = ret_place {
583                 let results = fx.bcx.inst_results(call_inst);
584                 ret_place.write_cvalue(fx, CValue::ByVal(results[0], ret_layout));
585             }
586         }
587         PassMode::ByRef => {}
588     }
589 }
590
591 pub fn codegen_return(fx: &mut FunctionCx<impl Backend>) {
592     match get_pass_mode(fx.tcx, fx.self_sig().abi, fx.return_type(), true) {
593         PassMode::NoPass | PassMode::ByRef => {
594             fx.bcx.ins().return_(&[]);
595         }
596         PassMode::ByVal(_) => {
597             let place = fx.get_local_place(RETURN_PLACE);
598             let ret_val = place.to_cvalue(fx).load_value(fx);
599             fx.bcx.ins().return_(&[ret_val]);
600         }
601     }
602 }