]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/src/abi/mod.rs
Auto merge of #95144 - RalfJung:miri, r=RalfJung
[rust.git] / compiler / rustc_codegen_cranelift / src / abi / mod.rs
1 //! Handling of everything related to the calling convention. Also fills `fx.local_map`.
2
3 mod comments;
4 mod pass_mode;
5 mod returning;
6
7 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
8 use rustc_middle::ty::layout::FnAbiOf;
9 use rustc_target::abi::call::{Conv, FnAbi};
10 use rustc_target::spec::abi::Abi;
11
12 use cranelift_codegen::ir::{AbiParam, SigRef};
13
14 use self::pass_mode::*;
15 use crate::prelude::*;
16
17 pub(crate) use self::returning::codegen_return;
18
19 fn clif_sig_from_fn_abi<'tcx>(
20     tcx: TyCtxt<'tcx>,
21     default_call_conv: CallConv,
22     fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
23 ) -> Signature {
24     let call_conv = match fn_abi.conv {
25         Conv::Rust | Conv::C => default_call_conv,
26         Conv::X86_64SysV => CallConv::SystemV,
27         Conv::X86_64Win64 => CallConv::WindowsFastcall,
28         Conv::ArmAapcs
29         | Conv::CCmseNonSecureCall
30         | Conv::Msp430Intr
31         | Conv::PtxKernel
32         | Conv::X86Fastcall
33         | Conv::X86Intr
34         | Conv::X86Stdcall
35         | Conv::X86ThisCall
36         | Conv::X86VectorCall
37         | Conv::AmdGpuKernel
38         | Conv::AvrInterrupt
39         | Conv::AvrNonBlockingInterrupt => todo!("{:?}", fn_abi.conv),
40     };
41     let inputs = fn_abi.args.iter().map(|arg_abi| arg_abi.get_abi_param(tcx).into_iter()).flatten();
42
43     let (return_ptr, returns) = fn_abi.ret.get_abi_return(tcx);
44     // Sometimes the first param is an pointer to the place where the return value needs to be stored.
45     let params: Vec<_> = return_ptr.into_iter().chain(inputs).collect();
46
47     Signature { params, returns, call_conv }
48 }
49
50 pub(crate) fn get_function_sig<'tcx>(
51     tcx: TyCtxt<'tcx>,
52     triple: &target_lexicon::Triple,
53     inst: Instance<'tcx>,
54 ) -> Signature {
55     assert!(!inst.substs.needs_infer());
56     clif_sig_from_fn_abi(
57         tcx,
58         CallConv::triple_default(triple),
59         &RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()),
60     )
61 }
62
63 /// Instance must be monomorphized
64 pub(crate) fn import_function<'tcx>(
65     tcx: TyCtxt<'tcx>,
66     module: &mut dyn Module,
67     inst: Instance<'tcx>,
68 ) -> FuncId {
69     let name = tcx.symbol_name(inst).name;
70     let sig = get_function_sig(tcx, module.isa().triple(), inst);
71     module.declare_function(name, Linkage::Import, &sig).unwrap()
72 }
73
74 impl<'tcx> FunctionCx<'_, '_, 'tcx> {
75     /// Instance must be monomorphized
76     pub(crate) fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
77         let func_id = import_function(self.tcx, self.module, inst);
78         let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
79
80         if self.clif_comments.enabled() {
81             self.add_comment(func_ref, format!("{:?}", inst));
82         }
83
84         func_ref
85     }
86
87     pub(crate) fn lib_call(
88         &mut self,
89         name: &str,
90         params: Vec<AbiParam>,
91         returns: Vec<AbiParam>,
92         args: &[Value],
93     ) -> &[Value] {
94         let sig = Signature { params, returns, call_conv: self.target_config.default_call_conv };
95         let func_id = self.module.declare_function(name, Linkage::Import, &sig).unwrap();
96         let func_ref = self.module.declare_func_in_func(func_id, &mut self.bcx.func);
97         if self.clif_comments.enabled() {
98             self.add_comment(func_ref, format!("{:?}", name));
99         }
100         let call_inst = self.bcx.ins().call(func_ref, args);
101         if self.clif_comments.enabled() {
102             self.add_comment(call_inst, format!("easy_call {}", name));
103         }
104         let results = self.bcx.inst_results(call_inst);
105         assert!(results.len() <= 2, "{}", results.len());
106         results
107     }
108
109     pub(crate) fn easy_call(
110         &mut self,
111         name: &str,
112         args: &[CValue<'tcx>],
113         return_ty: Ty<'tcx>,
114     ) -> CValue<'tcx> {
115         let (input_tys, args): (Vec<_>, Vec<_>) = args
116             .iter()
117             .map(|arg| {
118                 (AbiParam::new(self.clif_type(arg.layout().ty).unwrap()), arg.load_scalar(self))
119             })
120             .unzip();
121         let return_layout = self.layout_of(return_ty);
122         let return_tys = if let ty::Tuple(tup) = return_ty.kind() {
123             tup.iter().map(|ty| AbiParam::new(self.clif_type(ty).unwrap())).collect()
124         } else {
125             vec![AbiParam::new(self.clif_type(return_ty).unwrap())]
126         };
127         let ret_vals = self.lib_call(name, input_tys, return_tys, &args);
128         match *ret_vals {
129             [] => CValue::by_ref(
130                 Pointer::const_addr(self, i64::from(self.pointer_type.bytes())),
131                 return_layout,
132             ),
133             [val] => CValue::by_val(val, return_layout),
134             [val, extra] => CValue::by_val_pair(val, extra, return_layout),
135             _ => unreachable!(),
136         }
137     }
138 }
139
140 /// Make a [`CPlace`] capable of holding value of the specified type.
141 fn make_local_place<'tcx>(
142     fx: &mut FunctionCx<'_, '_, 'tcx>,
143     local: Local,
144     layout: TyAndLayout<'tcx>,
145     is_ssa: bool,
146 ) -> CPlace<'tcx> {
147     let place = if is_ssa {
148         if let rustc_target::abi::Abi::ScalarPair(_, _) = layout.abi {
149             CPlace::new_var_pair(fx, local, layout)
150         } else {
151             CPlace::new_var(fx, local, layout)
152         }
153     } else {
154         CPlace::new_stack_slot(fx, layout)
155     };
156
157     self::comments::add_local_place_comments(fx, place, local);
158
159     place
160 }
161
162 pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_block: Block) {
163     fx.bcx.append_block_params_for_function_params(start_block);
164
165     fx.bcx.switch_to_block(start_block);
166     fx.bcx.ins().nop();
167
168     let ssa_analyzed = crate::analyze::analyze(fx);
169
170     self::comments::add_args_header_comment(fx);
171
172     let mut block_params_iter = fx.bcx.func.dfg.block_params(start_block).to_vec().into_iter();
173     let ret_place =
174         self::returning::codegen_return_param(fx, &ssa_analyzed, &mut block_params_iter);
175     assert_eq!(fx.local_map.push(ret_place), RETURN_PLACE);
176
177     // None means pass_mode == NoPass
178     enum ArgKind<'tcx> {
179         Normal(Option<CValue<'tcx>>),
180         Spread(Vec<Option<CValue<'tcx>>>),
181     }
182
183     let fn_abi = fx.fn_abi.take().unwrap();
184     let mut arg_abis_iter = fn_abi.args.iter();
185
186     let func_params = fx
187         .mir
188         .args_iter()
189         .map(|local| {
190             let arg_ty = fx.monomorphize(fx.mir.local_decls[local].ty);
191
192             // Adapted from https://github.com/rust-lang/rust/blob/145155dc96757002c7b2e9de8489416e2fdbbd57/src/librustc_codegen_llvm/mir/mod.rs#L442-L482
193             if Some(local) == fx.mir.spread_arg {
194                 // This argument (e.g. the last argument in the "rust-call" ABI)
195                 // is a tuple that was spread at the ABI level and now we have
196                 // to reconstruct it into a tuple local variable, from multiple
197                 // individual function arguments.
198
199                 let tupled_arg_tys = match arg_ty.kind() {
200                     ty::Tuple(ref tys) => tys,
201                     _ => bug!("spread argument isn't a tuple?! but {:?}", arg_ty),
202                 };
203
204                 let mut params = Vec::new();
205                 for (i, _arg_ty) in tupled_arg_tys.iter().enumerate() {
206                     let arg_abi = arg_abis_iter.next().unwrap();
207                     let param =
208                         cvalue_for_param(fx, Some(local), Some(i), arg_abi, &mut block_params_iter);
209                     params.push(param);
210                 }
211
212                 (local, ArgKind::Spread(params), arg_ty)
213             } else {
214                 let arg_abi = arg_abis_iter.next().unwrap();
215                 let param =
216                     cvalue_for_param(fx, Some(local), None, arg_abi, &mut block_params_iter);
217                 (local, ArgKind::Normal(param), arg_ty)
218             }
219         })
220         .collect::<Vec<(Local, ArgKind<'tcx>, Ty<'tcx>)>>();
221
222     assert!(fx.caller_location.is_none());
223     if fx.instance.def.requires_caller_location(fx.tcx) {
224         // Store caller location for `#[track_caller]`.
225         let arg_abi = arg_abis_iter.next().unwrap();
226         fx.caller_location =
227             Some(cvalue_for_param(fx, None, None, arg_abi, &mut block_params_iter).unwrap());
228     }
229
230     assert!(arg_abis_iter.next().is_none(), "ArgAbi left behind");
231     fx.fn_abi = Some(fn_abi);
232     assert!(block_params_iter.next().is_none(), "arg_value left behind");
233
234     self::comments::add_locals_header_comment(fx);
235
236     for (local, arg_kind, ty) in func_params {
237         let layout = fx.layout_of(ty);
238
239         let is_ssa = ssa_analyzed[local] == crate::analyze::SsaKind::Ssa;
240
241         // While this is normally an optimization to prevent an unnecessary copy when an argument is
242         // not mutated by the current function, this is necessary to support unsized arguments.
243         if let ArgKind::Normal(Some(val)) = arg_kind {
244             if let Some((addr, meta)) = val.try_to_ptr() {
245                 // Ownership of the value at the backing storage for an argument is passed to the
246                 // callee per the ABI, so it is fine to borrow the backing storage of this argument
247                 // to prevent a copy.
248
249                 let place = if let Some(meta) = meta {
250                     CPlace::for_ptr_with_extra(addr, meta, val.layout())
251                 } else {
252                     CPlace::for_ptr(addr, val.layout())
253                 };
254
255                 self::comments::add_local_place_comments(fx, place, local);
256
257                 assert_eq!(fx.local_map.push(place), local);
258                 continue;
259             }
260         }
261
262         let place = make_local_place(fx, local, layout, is_ssa);
263         assert_eq!(fx.local_map.push(place), local);
264
265         match arg_kind {
266             ArgKind::Normal(param) => {
267                 if let Some(param) = param {
268                     place.write_cvalue(fx, param);
269                 }
270             }
271             ArgKind::Spread(params) => {
272                 for (i, param) in params.into_iter().enumerate() {
273                     if let Some(param) = param {
274                         place.place_field(fx, mir::Field::new(i)).write_cvalue(fx, param);
275                     }
276                 }
277             }
278         }
279     }
280
281     for local in fx.mir.vars_and_temps_iter() {
282         let ty = fx.monomorphize(fx.mir.local_decls[local].ty);
283         let layout = fx.layout_of(ty);
284
285         let is_ssa = ssa_analyzed[local] == crate::analyze::SsaKind::Ssa;
286
287         let place = make_local_place(fx, local, layout, is_ssa);
288         assert_eq!(fx.local_map.push(place), local);
289     }
290
291     fx.bcx.ins().jump(*fx.block_map.get(START_BLOCK).unwrap(), &[]);
292 }
293
294 struct CallArgument<'tcx> {
295     value: CValue<'tcx>,
296     is_owned: bool,
297 }
298
299 // FIXME avoid intermediate `CValue` before calling `adjust_arg_for_abi`
300 fn codegen_call_argument_operand<'tcx>(
301     fx: &mut FunctionCx<'_, '_, 'tcx>,
302     operand: &Operand<'tcx>,
303 ) -> CallArgument<'tcx> {
304     CallArgument {
305         value: codegen_operand(fx, operand),
306         is_owned: matches!(operand, Operand::Move(_)),
307     }
308 }
309
310 pub(crate) fn codegen_terminator_call<'tcx>(
311     fx: &mut FunctionCx<'_, '_, 'tcx>,
312     span: Span,
313     func: &Operand<'tcx>,
314     args: &[Operand<'tcx>],
315     mir_dest: Option<(Place<'tcx>, BasicBlock)>,
316 ) {
317     let fn_ty = fx.monomorphize(func.ty(fx.mir, fx.tcx));
318     let fn_sig =
319         fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), fn_ty.fn_sig(fx.tcx));
320
321     let destination = mir_dest.map(|(place, bb)| (codegen_place(fx, place), bb));
322
323     // Handle special calls like instrinsics and empty drop glue.
324     let instance = if let ty::FnDef(def_id, substs) = *fn_ty.kind() {
325         let instance = ty::Instance::resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs)
326             .unwrap()
327             .unwrap()
328             .polymorphize(fx.tcx);
329
330         if fx.tcx.symbol_name(instance).name.starts_with("llvm.") {
331             crate::intrinsics::codegen_llvm_intrinsic_call(
332                 fx,
333                 &fx.tcx.symbol_name(instance).name,
334                 substs,
335                 args,
336                 destination,
337             );
338             return;
339         }
340
341         match instance.def {
342             InstanceDef::Intrinsic(_) => {
343                 crate::intrinsics::codegen_intrinsic_call(fx, instance, args, destination, span);
344                 return;
345             }
346             InstanceDef::DropGlue(_, None) => {
347                 // empty drop glue - a nop.
348                 let (_, dest) = destination.expect("Non terminating drop_in_place_real???");
349                 let ret_block = fx.get_block(dest);
350                 fx.bcx.ins().jump(ret_block, &[]);
351                 return;
352             }
353             _ => Some(instance),
354         }
355     } else {
356         None
357     };
358
359     let extra_args = &args[fn_sig.inputs().len()..];
360     let extra_args = fx
361         .tcx
362         .mk_type_list(extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))));
363     let fn_abi = if let Some(instance) = instance {
364         RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
365     } else {
366         RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_ty.fn_sig(fx.tcx), extra_args)
367     };
368
369     let is_cold = instance
370         .map(|inst| fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD))
371         .unwrap_or(false);
372     if is_cold {
373         fx.bcx.set_cold_block(fx.bcx.current_block().unwrap());
374         if let Some((_place, destination_block)) = destination {
375             fx.bcx.set_cold_block(fx.get_block(destination_block));
376         }
377     }
378
379     // Unpack arguments tuple for closures
380     let mut args = if fn_sig.abi == Abi::RustCall {
381         assert_eq!(args.len(), 2, "rust-call abi requires two arguments");
382         let self_arg = codegen_call_argument_operand(fx, &args[0]);
383         let pack_arg = codegen_call_argument_operand(fx, &args[1]);
384
385         let tupled_arguments = match pack_arg.value.layout().ty.kind() {
386             ty::Tuple(ref tupled_arguments) => tupled_arguments,
387             _ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
388         };
389
390         let mut args = Vec::with_capacity(1 + tupled_arguments.len());
391         args.push(self_arg);
392         for i in 0..tupled_arguments.len() {
393             args.push(CallArgument {
394                 value: pack_arg.value.value_field(fx, mir::Field::new(i)),
395                 is_owned: pack_arg.is_owned,
396             });
397         }
398         args
399     } else {
400         args.iter().map(|arg| codegen_call_argument_operand(fx, arg)).collect::<Vec<_>>()
401     };
402
403     // Pass the caller location for `#[track_caller]`.
404     if instance.map(|inst| inst.def.requires_caller_location(fx.tcx)).unwrap_or(false) {
405         let caller_location = fx.get_caller_location(span);
406         args.push(CallArgument { value: caller_location, is_owned: false });
407     }
408
409     let args = args;
410     assert_eq!(fn_abi.args.len(), args.len());
411
412     enum CallTarget {
413         Direct(FuncRef),
414         Indirect(SigRef, Value),
415     }
416
417     let (func_ref, first_arg_override) = match instance {
418         // Trait object call
419         Some(Instance { def: InstanceDef::Virtual(_, idx), .. }) => {
420             if fx.clif_comments.enabled() {
421                 let nop_inst = fx.bcx.ins().nop();
422                 fx.add_comment(
423                     nop_inst,
424                     format!("virtual call; self arg pass mode: {:?}", &fn_abi.args[0]),
425                 );
426             }
427
428             let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0].value, idx);
429             let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
430             let sig = fx.bcx.import_signature(sig);
431
432             (CallTarget::Indirect(sig, method), Some(ptr))
433         }
434
435         // Normal call
436         Some(instance) => {
437             let func_ref = fx.get_function_ref(instance);
438             (CallTarget::Direct(func_ref), None)
439         }
440
441         // Indirect call
442         None => {
443             if fx.clif_comments.enabled() {
444                 let nop_inst = fx.bcx.ins().nop();
445                 fx.add_comment(nop_inst, "indirect call");
446             }
447
448             let func = codegen_operand(fx, func).load_scalar(fx);
449             let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
450             let sig = fx.bcx.import_signature(sig);
451
452             (CallTarget::Indirect(sig, func), None)
453         }
454     };
455
456     let ret_place = destination.map(|(place, _)| place);
457     self::returning::codegen_with_call_return_arg(fx, &fn_abi.ret, ret_place, |fx, return_ptr| {
458         let call_args = return_ptr
459             .into_iter()
460             .chain(first_arg_override.into_iter())
461             .chain(
462                 args.into_iter()
463                     .enumerate()
464                     .skip(if first_arg_override.is_some() { 1 } else { 0 })
465                     .map(|(i, arg)| {
466                         adjust_arg_for_abi(fx, arg.value, &fn_abi.args[i], arg.is_owned).into_iter()
467                     })
468                     .flatten(),
469             )
470             .collect::<Vec<Value>>();
471
472         let call_inst = match func_ref {
473             CallTarget::Direct(func_ref) => fx.bcx.ins().call(func_ref, &call_args),
474             CallTarget::Indirect(sig, func_ptr) => {
475                 fx.bcx.ins().call_indirect(sig, func_ptr, &call_args)
476             }
477         };
478
479         // FIXME find a cleaner way to support varargs
480         if fn_sig.c_variadic {
481             if !matches!(fn_sig.abi, Abi::C { .. }) {
482                 fx.tcx
483                     .sess
484                     .span_fatal(span, &format!("Variadic call for non-C abi {:?}", fn_sig.abi));
485             }
486             let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap();
487             let abi_params = call_args
488                 .into_iter()
489                 .map(|arg| {
490                     let ty = fx.bcx.func.dfg.value_type(arg);
491                     if !ty.is_int() {
492                         // FIXME set %al to upperbound on float args once floats are supported
493                         fx.tcx
494                             .sess
495                             .span_fatal(span, &format!("Non int ty {:?} for variadic call", ty));
496                     }
497                     AbiParam::new(ty)
498                 })
499                 .collect::<Vec<AbiParam>>();
500             fx.bcx.func.dfg.signatures[sig_ref].params = abi_params;
501         }
502
503         call_inst
504     });
505
506     if let Some((_, dest)) = destination {
507         let ret_block = fx.get_block(dest);
508         fx.bcx.ins().jump(ret_block, &[]);
509     } else {
510         fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
511     }
512 }
513
514 pub(crate) fn codegen_drop<'tcx>(
515     fx: &mut FunctionCx<'_, '_, 'tcx>,
516     span: Span,
517     drop_place: CPlace<'tcx>,
518 ) {
519     let ty = drop_place.layout().ty;
520     let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx);
521
522     if let ty::InstanceDef::DropGlue(_, None) = drop_instance.def {
523         // we don't actually need to drop anything
524     } else {
525         match ty.kind() {
526             ty::Dynamic(..) => {
527                 let (ptr, vtable) = drop_place.to_ptr_maybe_unsized();
528                 let ptr = ptr.get_addr(fx);
529                 let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable.unwrap());
530
531                 // FIXME(eddyb) perhaps move some of this logic into
532                 // `Instance::resolve_drop_in_place`?
533                 let virtual_drop = Instance {
534                     def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0),
535                     substs: drop_instance.substs,
536                 };
537                 let fn_abi =
538                     RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty());
539
540                 let sig = clif_sig_from_fn_abi(fx.tcx, fx.target_config.default_call_conv, &fn_abi);
541                 let sig = fx.bcx.import_signature(sig);
542                 fx.bcx.ins().call_indirect(sig, drop_fn, &[ptr]);
543             }
544             _ => {
545                 assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _)));
546
547                 let fn_abi =
548                     RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, ty::List::empty());
549
550                 let arg_value = drop_place.place_ref(
551                     fx,
552                     fx.layout_of(fx.tcx.mk_ref(
553                         fx.tcx.lifetimes.re_erased,
554                         TypeAndMut { ty, mutbl: crate::rustc_hir::Mutability::Mut },
555                     )),
556                 );
557                 let arg_value = adjust_arg_for_abi(fx, arg_value, &fn_abi.args[0], true);
558
559                 let mut call_args: Vec<Value> = arg_value.into_iter().collect::<Vec<_>>();
560
561                 if drop_instance.def.requires_caller_location(fx.tcx) {
562                     // Pass the caller location for `#[track_caller]`.
563                     let caller_location = fx.get_caller_location(span);
564                     call_args.extend(
565                         adjust_arg_for_abi(fx, caller_location, &fn_abi.args[1], false).into_iter(),
566                     );
567                 }
568
569                 let func_ref = fx.get_function_ref(drop_instance);
570                 fx.bcx.ins().call(func_ref, &call_args);
571             }
572         }
573     }
574 }