#[cfg(debug_assertions)]
mod comments;
-mod returning;
mod pass_mode;
+mod returning;
use rustc_target::spec::abi::Abi;
-use crate::prelude::*;
use self::pass_mode::*;
+use crate::prelude::*;
pub use self::returning::codegen_return;
-fn clif_sig_from_fn_sig<'tcx>(tcx: TyCtxt<'tcx>, sig: FnSig<'tcx>, is_vtable_fn: bool) -> Signature {
+fn clif_sig_from_fn_sig<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ sig: FnSig<'tcx>,
+ is_vtable_fn: bool,
+) -> Signature {
let abi = match sig.abi {
Abi::System => {
if tcx.sess.target.target.options.is_like_windows {
abi => abi,
};
let (call_conv, inputs, output): (CallConv, Vec<Ty>, Ty) = match abi {
- Abi::Rust => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()),
- Abi::C => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()),
+ Abi::Rust => (crate::default_call_conv(tcx.sess), sig.inputs().to_vec(), sig.output()),
+ Abi::C => (crate::default_call_conv(tcx.sess), sig.inputs().to_vec(), sig.output()),
Abi::RustCall => {
assert_eq!(sig.inputs().len(), 2);
- let extra_args = match sig.inputs().last().unwrap().sty {
+ let extra_args = match sig.inputs().last().unwrap().kind {
ty::Tuple(ref tupled_arguments) => tupled_arguments,
_ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
};
let mut inputs: Vec<Ty> = vec![sig.inputs()[0]];
inputs.extend(extra_args.types());
- (CallConv::SystemV, inputs, sig.output())
+ (crate::default_call_conv(tcx.sess), inputs, sig.output())
}
Abi::System => unreachable!(),
- Abi::RustIntrinsic => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()),
+ Abi::RustIntrinsic => (crate::default_call_conv(tcx.sess), sig.inputs().to_vec(), sig.output()),
_ => unimplemented!("unsupported abi {:?}", sig.abi),
};
if i == 0 && is_vtable_fn {
// Virtual calls turn their self param into a thin pointer.
// See https://github.com/rust-lang/rust/blob/37b6a5e5e82497caf5353d9d856e4eb5d14cbe06/src/librustc/ty/layout.rs#L2519-L2572 for more info
- layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.mk_mut_ptr(tcx.mk_unit()))).unwrap();
+ layout = tcx
+ .layout_of(ParamEnv::reveal_all().and(tcx.mk_mut_ptr(tcx.mk_unit())))
+ .unwrap();
}
get_pass_mode(tcx, layout).get_param_ty(tcx).into_iter()
- }).flatten();
+ })
+ .flatten();
- let (params, returns) = match get_pass_mode(tcx, tcx.layout_of(ParamEnv::reveal_all().and(output)).unwrap()) {
+ let (params, returns) = match get_pass_mode(
+ tcx,
+ tcx.layout_of(ParamEnv::reveal_all().and(output)).unwrap(),
+ ) {
PassMode::NoPass => (inputs.map(AbiParam::new).collect(), vec![]),
PassMode::ByVal(ret_ty) => (
inputs.map(AbiParam::new).collect(),
support_vararg: bool,
) -> (String, Signature) {
assert!(!inst.substs.needs_infer() && !inst.substs.has_param_types());
- let fn_sig = tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &inst.fn_sig(tcx));
+ let fn_sig =
+ tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &inst.fn_sig(tcx));
if fn_sig.c_variadic && !support_vararg {
unimpl!("Variadic function definitions are not yet supported");
}
let sig = clif_sig_from_fn_sig(tcx, fn_sig, false);
- (tcx.symbol_name(inst).as_str().to_string(), sig)
+ (tcx.symbol_name(inst).name.as_str().to_string(), sig)
}
/// Instance must be monomorphized
let sig = Signature {
params: input_tys.iter().cloned().map(AbiParam::new).collect(),
returns: output_tys.iter().cloned().map(AbiParam::new).collect(),
- call_conv: CallConv::SystemV,
+ call_conv: crate::default_call_conv(self.tcx.sess),
};
let func_id = self
.module
.module
.declare_func_in_func(func_id, &mut self.bcx.func);
let call_inst = self.bcx.ins().call(func_ref, args);
- #[cfg(debug_assertions)] {
+ #[cfg(debug_assertions)]
+ {
self.add_comment(call_inst, format!("easy_call {}", name));
}
let results = self.bcx.inst_results(call_inst);
})
.unzip();
let return_layout = self.layout_of(return_ty);
- let return_tys = if let ty::Tuple(tup) = return_ty.sty {
+ let return_tys = if let ty::Tuple(tup) = return_ty.kind {
tup.types().map(|ty| self.clif_type(ty).unwrap()).collect()
} else {
vec![self.clif_type(return_ty).unwrap()]
}
fn self_sig(&self) -> FnSig<'tcx> {
- self.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &self.instance.fn_sig(self.tcx))
+ self.tcx.normalize_erasing_late_bound_regions(
+ ParamEnv::reveal_all(),
+ &self.instance.fn_sig(self.tcx),
+ )
}
fn return_layout(&self) -> TyLayout<'tcx> {
fx.local_map[&local]
}
-pub fn codegen_fn_prelude(
- fx: &mut FunctionCx<'_, '_, impl Backend>,
- start_ebb: Ebb,
-) {
+pub fn codegen_fn_prelude(fx: &mut FunctionCx<'_, '_, impl Backend>, start_ebb: Ebb) {
let ssa_analyzed = crate::analyze::analyze(fx);
#[cfg(debug_assertions)]
// to reconstruct it into a tuple local variable, from multiple
// individual function arguments.
- let tupled_arg_tys = match arg_ty.sty {
+ let tupled_arg_tys = match arg_ty.kind {
ty::Tuple(ref tys) => tys,
_ => bug!("spread argument isn't a tuple?! but {:?}", arg_ty),
};
let mut params = Vec::new();
for (i, arg_ty) in tupled_arg_tys.types().enumerate() {
- let param = cvalue_for_param(
- fx,
- start_ebb,
- local,
- Some(i),
- arg_ty,
- );
+ let param = cvalue_for_param(fx, start_ebb, local, Some(i), arg_ty);
params.push(param);
}
(local, ArgKind::Spread(params), arg_ty)
} else {
- let param =
- cvalue_for_param(fx, start_ebb, local, None, arg_ty);
+ let param = cvalue_for_param(fx, start_ebb, local, None, arg_ty);
(local, ArgKind::Normal(param), arg_ty)
}
})
for (local, arg_kind, ty) in func_params {
let layout = fx.layout_of(ty);
- let is_ssa = !ssa_analyzed
- .get(&local)
- .unwrap()
- .contains(crate::analyze::Flags::NOT_SSA);
+ let is_ssa = *ssa_analyzed.get(&local).unwrap() == crate::analyze::SsaKind::Ssa;
+
+ match arg_kind {
+ ArgKind::Normal(Some(val)) => {
+ if let Some(addr) = val.try_to_addr() {
+ let local_decl = &fx.mir.local_decls[local];
+ // v this ! is important
+ let internally_mutable = !val.layout().ty.is_freeze(
+ fx.tcx,
+ ParamEnv::reveal_all(),
+ local_decl.source_info.span,
+ );
+ if local_decl.mutability == mir::Mutability::Not && internally_mutable {
+ // We wont mutate this argument, so it is fine to borrow the backing storage
+ // of this argument, to prevent a copy.
+
+ let place = CPlace::for_addr(addr, val.layout());
+
+ #[cfg(debug_assertions)]
+ self::comments::add_local_place_comments(fx, place, local);
+
+ let prev_place = fx.local_map.insert(local, place);
+ debug_assert!(prev_place.is_none());
+ continue;
+ }
+ }
+ }
+ _ => {}
+ }
let place = local_place(fx, local, layout, is_ssa);
let ty = fx.mir.local_decls[local].ty;
let layout = fx.layout_of(ty);
- let is_ssa = !ssa_analyzed
- .get(&local)
- .unwrap()
- .contains(crate::analyze::Flags::NOT_SSA);
+ let is_ssa = *ssa_analyzed.get(&local).unwrap() == crate::analyze::SsaKind::Ssa;
local_place(fx, local, layout, is_ssa);
}
func: &Operand<'tcx>,
args: &[Operand<'tcx>],
destination: &Option<(Place<'tcx>, BasicBlock)>,
+ span: Span,
) {
let fn_ty = fx.monomorphize(&func.ty(fx.mir, fx.tcx));
- let sig = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &fn_ty.fn_sig(fx.tcx));
+ let sig = fx
+ .tcx
+ .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &fn_ty.fn_sig(fx.tcx));
let destination = destination
.as_ref()
.map(|&(ref place, bb)| (trans_place(fx, place), bb));
- if let ty::FnDef(def_id, substs) = fn_ty.sty {
+ if let ty::FnDef(def_id, substs) = fn_ty.kind {
let instance =
ty::Instance::resolve(fx.tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap();
- if fx.tcx.symbol_name(instance).as_str().starts_with("llvm.") {
- crate::llvm_intrinsics::codegen_llvm_intrinsic_call(fx, &fx.tcx.symbol_name(instance).as_str(), substs, args, destination);
+ if fx.tcx.symbol_name(instance).name.as_str().starts_with("llvm.") {
+ crate::llvm_intrinsics::codegen_llvm_intrinsic_call(
+ fx,
+ &fx.tcx.symbol_name(instance).name.as_str(),
+ substs,
+ args,
+ destination,
+ );
return;
}
match instance.def {
InstanceDef::Intrinsic(_) => {
- crate::intrinsics::codegen_intrinsic_call(fx, def_id, substs, args, destination);
+ crate::intrinsics::codegen_intrinsic_call(fx, instance, args, destination, span);
return;
}
InstanceDef::DropGlue(_, None) => {
let pack_arg = trans_operand(fx, &args[1]);
let mut args = Vec::new();
args.push(self_arg);
- match pack_arg.layout().ty.sty {
+ match pack_arg.layout().ty.kind {
ty::Tuple(ref tupled_arguments) => {
for (i, _) in tupled_arguments.iter().enumerate() {
args.push(pack_arg.value_field(fx, mir::Field::new(i)));
args: Vec<CValue<'tcx>>,
ret_place: Option<CPlace<'tcx>>,
) {
- let fn_sig = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &fn_ty.fn_sig(fx.tcx));
+ let fn_sig = fx
+ .tcx
+ .normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &fn_ty.fn_sig(fx.tcx));
- let instance = match fn_ty.sty {
+ let instance = match fn_ty.kind {
ty::FnDef(def_id, substs) => {
Some(Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap())
}
let nop_inst = fx.bcx.ins().nop();
fx.add_comment(
nop_inst,
- format!("virtual call; self arg pass mode: {:?}", get_pass_mode(fx.tcx, args[0].layout())),
+ format!(
+ "virtual call; self arg pass mode: {:?}",
+ get_pass_mode(fx.tcx, args[0].layout())
+ ),
);
}
let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0], idx);
}
// Normal call
- Some(_) => (None, args.get(0).map(|arg| adjust_arg_for_abi(fx, *arg)).unwrap_or(Empty), false),
+ Some(_) => (
+ None,
+ args.get(0)
+ .map(|arg| adjust_arg_for_abi(fx, *arg))
+ .unwrap_or(Empty),
+ false,
+ ),
// Indirect call
None => {
.load_scalar(fx);
(
Some(func),
- args.get(0).map(|arg| adjust_arg_for_abi(fx, *arg)).unwrap_or(Empty),
+ args.get(0)
+ .map(|arg| adjust_arg_for_abi(fx, *arg))
+ .unwrap_or(Empty),
false,
)
}
};
- let (call_inst, call_args) = self::returning::codegen_with_call_return_arg(fx, fn_sig, ret_place, |fx, return_ptr| {
- let call_args: Vec<Value> = return_ptr
- .into_iter()
- .chain(first_arg.into_iter())
- .chain(
- args.into_iter()
- .skip(1)
- .map(|arg| adjust_arg_for_abi(fx, arg).into_iter())
- .flatten(),
- )
- .collect::<Vec<_>>();
+ let (call_inst, call_args) =
+ self::returning::codegen_with_call_return_arg(fx, fn_sig, ret_place, |fx, return_ptr| {
+ let call_args: Vec<Value> = return_ptr
+ .into_iter()
+ .chain(first_arg.into_iter())
+ .chain(
+ args.into_iter()
+ .skip(1)
+ .map(|arg| adjust_arg_for_abi(fx, arg).into_iter())
+ .flatten(),
+ )
+ .collect::<Vec<_>>();
- let call_inst = if let Some(func_ref) = func_ref {
- let sig = fx
- .bcx
- .import_signature(clif_sig_from_fn_sig(fx.tcx, fn_sig, is_virtual_call));
- fx.bcx.ins().call_indirect(sig, func_ref, &call_args)
- } else {
- let func_ref = fx.get_function_ref(instance.expect("non-indirect call on non-FnDef type"));
- fx.bcx.ins().call(func_ref, &call_args)
- };
+ let call_inst = if let Some(func_ref) = func_ref {
+ let sig =
+ fx.bcx
+ .import_signature(clif_sig_from_fn_sig(fx.tcx, fn_sig, is_virtual_call));
+ fx.bcx.ins().call_indirect(sig, func_ref, &call_args)
+ } else {
+ let func_ref =
+ fx.get_function_ref(instance.expect("non-indirect call on non-FnDef type"));
+ fx.bcx.ins().call(func_ref, &call_args)
+ };
- (call_inst, call_args)
- });
+ (call_inst, call_args)
+ });
// FIXME find a cleaner way to support varargs
if fn_sig.c_variadic {
}
}
-pub fn codegen_drop<'tcx>(
- fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
- drop_place: CPlace<'tcx>,
-) {
+pub fn codegen_drop<'tcx>(fx: &mut FunctionCx<'_, 'tcx, impl Backend>, drop_place: CPlace<'tcx>) {
let ty = drop_place.layout().ty;
let drop_fn = Instance::resolve_drop_in_place(fx.tcx, ty);
// we don't actually need to drop anything
} else {
let drop_fn_ty = drop_fn.ty(fx.tcx);
- match ty.sty {
+ match ty.kind {
ty::Dynamic(..) => {
let (ptr, vtable) = drop_place.to_addr_maybe_unsized(fx);
let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable.unwrap());
- let fn_sig = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &drop_fn_ty.fn_sig(fx.tcx));
+ let fn_sig = fx.tcx.normalize_erasing_late_bound_regions(
+ ParamEnv::reveal_all(),
+ &drop_fn_ty.fn_sig(fx.tcx),
+ );
assert_eq!(fn_sig.output(), fx.tcx.mk_unit());
);
drop_place.write_place_ref(fx, arg_place);
let arg_value = arg_place.to_cvalue(fx);
- codegen_call_inner(
- fx,
- None,
- drop_fn_ty,
- vec![arg_value],
- None,
- );
+ codegen_call_inner(fx, None, drop_fn_ty, vec![arg_value], None);
}
}
}