+use std::borrow::Cow;
use std::iter;
use rustc::hir;
+use rustc::ty::layout::{Scalar, Primitive, Integer, FloatTy};
use rustc_target::spec::abi::Abi;
use crate::prelude::*;
-#[derive(Debug)]
+#[derive(Copy, Clone, Debug)]
enum PassMode {
NoPass,
ByVal(Type),
}
impl PassMode {
- fn get_param_ty(self, _fx: &FunctionCx) -> Type {
+ fn get_param_ty(self, fx: &FunctionCx<impl Backend>) -> Type {
match self {
PassMode::NoPass => unimplemented!("pass mode nopass"),
- PassMode::ByVal(cton_type) => cton_type,
- PassMode::ByRef => types::I64,
+ PassMode::ByVal(clif_type) => clif_type,
+ PassMode::ByRef => fx.pointer_type,
}
}
}
+pub fn scalar_to_clif_type(tcx: TyCtxt, scalar: Scalar) -> Type {
+ match scalar.value {
+ Primitive::Int(int, _sign) => match int {
+ Integer::I8 => types::I8,
+ Integer::I16 => types::I16,
+ Integer::I32 => types::I32,
+ Integer::I64 => types::I64,
+ Integer::I128 => unimpl!("u/i128"),
+ }
+ Primitive::Float(flt) => match flt {
+ FloatTy::F32 => types::F32,
+ FloatTy::F64 => types::F64,
+ }
+ Primitive::Pointer => pointer_ty(tcx),
+ }
+}
+
fn get_pass_mode<'a, 'tcx: 'a>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- abi: Abi,
ty: Ty<'tcx>,
is_return: bool,
) -> PassMode {
- if ty.sty == tcx.mk_nil().sty {
+ let layout = tcx
+ .layout_of(ParamEnv::reveal_all().and(ty))
+ .unwrap();
+ assert!(!layout.is_unsized());
+
+ if layout.size.bytes() == 0 {
if is_return {
- //if false {
PassMode::NoPass
} else {
PassMode::ByRef
}
- } else if let Some(ret_ty) = crate::common::cton_type_from_ty(tcx, ty) {
- PassMode::ByVal(ret_ty)
} else {
- if abi == Abi::C {
- unimplemented!("Non scalars are not yet supported for \"C\" abi");
+ match &layout.abi {
+ layout::Abi::Uninhabited => {
+ if is_return {
+ PassMode::NoPass
+ } else {
+ PassMode::ByRef
+ }
+ }
+ layout::Abi::Scalar(scalar) => PassMode::ByVal(scalar_to_clif_type(tcx, scalar.clone())),
+
+ // FIXME implement ScalarPair and Vector Abi in a cg_llvm compatible way
+ layout::Abi::ScalarPair(_, _) => PassMode::ByRef,
+ layout::Abi::Vector { .. } => PassMode::ByRef,
+
+ layout::Abi::Aggregate { .. } => PassMode::ByRef,
}
- PassMode::ByRef
}
}
-pub fn cton_sig_from_fn_ty<'a, 'tcx: 'a>(
+fn adjust_arg_for_abi<'a, 'tcx: 'a>(
+ fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
+ arg: CValue<'tcx>,
+) -> Value {
+ match get_pass_mode(fx.tcx, arg.layout().ty, false) {
+ PassMode::NoPass => unimplemented!("pass mode nopass"),
+ PassMode::ByVal(_) => arg.load_scalar(fx),
+ PassMode::ByRef => arg.force_stack(fx),
+ }
+}
+
+fn clif_sig_from_fn_sig<'a, 'tcx: 'a>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- fn_ty: Ty<'tcx>,
+ sig: FnSig<'tcx>,
) -> Signature {
- let sig = ty_fn_sig(tcx, fn_ty);
- assert!(!sig.variadic, "Variadic function are not yet supported");
let (call_conv, inputs, output): (CallConv, Vec<Ty>, Ty) = match sig.abi {
- Abi::Rust => (CallConv::Fast, sig.inputs().to_vec(), sig.output()),
+ Abi::Rust => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()),
Abi::C => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()),
Abi::RustCall => {
- println!(
- "rust-call sig: {:?} inputs: {:?} output: {:?}",
- sig,
- sig.inputs(),
- sig.output()
- );
assert_eq!(sig.inputs().len(), 2);
let extra_args = match sig.inputs().last().unwrap().sty {
- ty::TyTuple(ref tupled_arguments) => tupled_arguments,
+ 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.into_iter());
- (CallConv::Fast, inputs, sig.output())
+ (CallConv::SystemV, inputs, sig.output())
}
Abi::System => bug!("system abi should be selected elsewhere"),
Abi::RustIntrinsic => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()),
let inputs = inputs
.into_iter()
- .filter_map(|ty| match get_pass_mode(tcx, sig.abi, ty, false) {
- PassMode::ByVal(cton_ty) => Some(cton_ty),
+ .filter_map(|ty| match get_pass_mode(tcx, ty, false) {
+ PassMode::ByVal(clif_ty) => Some(clif_ty),
PassMode::NoPass => unimplemented!("pass mode nopass"),
- PassMode::ByRef => Some(types::I64),
+ PassMode::ByRef => Some(pointer_ty(tcx)),
});
- let (params, returns) = match get_pass_mode(tcx, sig.abi, output, true) {
+ let (params, returns) = match get_pass_mode(tcx, output, true) {
PassMode::NoPass => (inputs.map(AbiParam::new).collect(), vec![]),
PassMode::ByVal(ret_ty) => (
inputs.map(AbiParam::new).collect(),
),
PassMode::ByRef => {
(
- Some(types::I64).into_iter() // First param is place to put return val
+ Some(pointer_ty(tcx)) // First param is place to put return val
+ .into_iter()
.chain(inputs)
.map(AbiParam::new)
.collect(),
params,
returns,
call_conv,
- argument_bytes: None,
}
}
-fn ty_fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> ty::FnSig<'tcx> {
+pub fn ty_fn_sig<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> ty::FnSig<'tcx> {
let sig = match ty.sty {
- ty::TyFnDef(..) |
+ ty::FnDef(..) |
// Shims currently have type TyFnPtr. Not sure this should remain.
- ty::TyFnPtr(_) => ty.fn_sig(tcx),
- ty::TyClosure(def_id, substs) => {
+ ty::FnPtr(_) => ty.fn_sig(tcx),
+ ty::Closure(def_id, substs) => {
let sig = substs.closure_sig(def_id, tcx);
let env_ty = tcx.closure_env_ty(def_id, substs).unwrap();
sig.abi
))
}
- ty::TyGenerator(def_id, substs, _) => {
+ ty::Generator(def_id, substs, _) => {
let sig = substs.poly_sig(def_id, tcx);
let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &sig)
}
-fn get_function_name_and_sig<'a, 'tcx>(
+pub fn get_function_name_and_sig<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
inst: Instance<'tcx>,
) -> (String, Signature) {
assert!(!inst.substs.needs_infer() && !inst.substs.has_param_types());
let fn_ty = inst.ty(tcx);
- let sig = cton_sig_from_fn_ty(tcx, fn_ty);
- let def_path_based_names =
- ::rustc_mir::monomorphize::item::DefPathBasedNames::new(tcx, false, false);
- let mut name = String::new();
- def_path_based_names.push_instance_as_string(inst, &mut name);
- (name, sig)
+ let fn_sig = ty_fn_sig(tcx, fn_ty);
+ if fn_sig.variadic {
+ unimpl!("Variadic functions are not yet supported");
+ }
+ let sig = clif_sig_from_fn_sig(tcx, fn_sig);
+ (tcx.symbol_name(inst).as_str().to_string(), sig)
}
-impl<'a, 'tcx: 'a> CodegenCx<'a, 'tcx, CurrentBackend> {
- pub fn predefine_function(&mut self, inst: Instance<'tcx>) -> (FuncId, Function) {
- let (name, sig) = crate::abi::get_function_name_and_sig(self.tcx, inst);
- let func_id = self
- .module
- .declare_function(&name, Linkage::Export, &sig)
- .unwrap();
- let func =
- Function::with_name_signature(ExternalName::user(0, func_id.index() as u32), sig);
- (func_id, func)
- }
+/// Instance must be monomorphized
+pub fn import_function<'a, 'tcx: 'a>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ module: &mut Module<impl Backend>,
+ inst: Instance<'tcx>,
+) -> FuncId {
+ let (name, sig) = get_function_name_and_sig(tcx, inst);
+ module
+ .declare_function(&name, Linkage::Import, &sig)
+ .unwrap()
}
-impl<'a, 'tcx: 'a> FunctionCx<'a, 'tcx> {
+impl<'a, 'tcx: 'a, B: Backend + 'a> FunctionCx<'a, 'tcx, B> {
/// Instance must be monomorphized
pub fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
- let (name, sig) = get_function_name_and_sig(self.tcx, inst);
- let func_id = self
- .module
- .declare_function(&name, Linkage::Import, &sig)
- .unwrap();
- self.module
- .declare_func_in_func(func_id, &mut self.bcx.func)
+ let func_id = import_function(self.tcx, self.module, inst);
+ let func_ref = self.module
+ .declare_func_in_func(func_id, &mut self.bcx.func);
+
+ #[cfg(debug_assertions)]
+ self.add_entity_comment(func_ref, format!("{:?}", inst));
+
+ func_ref
}
fn lib_call(
) -> Option<Value> {
let sig = Signature {
params: input_tys.iter().cloned().map(AbiParam::new).collect(),
- returns: vec![AbiParam::new(output_ty.unwrap_or(types::VOID))],
+ returns: output_ty
+ .map(|output_ty| vec![AbiParam::new(output_ty)])
+ .unwrap_or(Vec::new()),
call_conv: CallConv::SystemV,
- argument_bytes: None,
};
let func_id = self
.module
.into_iter()
.map(|arg| {
(
- self.cton_type(arg.layout().ty).unwrap(),
- arg.load_value(self),
+ self.clif_type(arg.layout().ty).unwrap(),
+ arg.load_scalar(self),
)
- }).unzip();
+ })
+ .unzip();
let return_layout = self.layout_of(return_ty);
- let return_ty = if let TypeVariants::TyTuple(tup) = return_ty.sty {
+ let return_ty = if let ty::Tuple(tup) = return_ty.sty {
if !tup.is_empty() {
bug!("easy_call( (...) -> <non empty tuple> ) is not allowed");
}
None
} else {
- Some(self.cton_type(return_ty).unwrap())
+ Some(self.clif_type(return_ty).unwrap())
};
if let Some(val) = self.lib_call(name, input_tys, return_ty, &args) {
CValue::ByVal(val, return_layout)
} else {
- CValue::ByRef(self.bcx.ins().iconst(types::I64, 0), return_layout)
+ CValue::ByRef(self.bcx.ins().iconst(self.pointer_type, 0), return_layout)
}
}
}
}
-pub fn codegen_fn_prelude<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx>, start_ebb: Ebb) {
- let ssa_analyzed = crate::analyze::analyze(fx);
- fx.tcx.sess.warn(&format!("ssa {:?}", ssa_analyzed));
+#[cfg(debug_assertions)]
+fn add_arg_comment<'a, 'tcx: 'a>(
+ fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
+ msg: &str,
+ local: mir::Local,
+ local_field: Option<usize>,
+ param: Option<Value>,
+ pass_mode: PassMode,
+ ssa: crate::analyze::Flags,
+ ty: Ty<'tcx>,
+) {
+ let local_field = if let Some(local_field) = local_field {
+ Cow::Owned(format!(".{}", local_field))
+ } else {
+ Cow::Borrowed("")
+ };
+ let param = if let Some(param) = param {
+ Cow::Owned(format!("= {:?}", param))
+ } else {
+ Cow::Borrowed("-")
+ };
+ let pass_mode = format!("{:?}", pass_mode);
+ fx.add_global_comment(format!(
+ "{msg:5} {local:>3}{local_field:<5} {param:10} {pass_mode:20} {ssa:10} {ty:?}",
+ msg=msg, local=format!("{:?}", local), local_field=local_field, param=param, pass_mode=pass_mode, ssa=format!("{:?}", ssa), ty=ty,
+ ));
+}
+
+#[cfg(debug_assertions)]
+fn add_local_header_comment(fx: &mut FunctionCx<impl Backend>) {
+ fx.add_global_comment(format!("msg loc.idx param pass mode ssa flags ty"));
+}
+
+fn local_place<'a, 'tcx: 'a>(
+ fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
+ local: Local,
+ layout: TyLayout<'tcx>,
+ is_ssa: bool,
+) -> CPlace<'tcx> {
+ let place = if is_ssa {
+ fx.bcx.declare_var(mir_var(local), fx.clif_type(layout.ty).unwrap());
+ CPlace::Var(local, layout)
+ } else {
+ let place = CPlace::new_stack_slot(fx, layout.ty);
+
+ #[cfg(debug_assertions)]
+ {
+ let TyLayout { ty, details } = layout;
+ let ty::layout::LayoutDetails { size, align, abi: _, variants: _, fields: _ } = details;
+ match place {
+ CPlace::Stack(stack_slot, _) => fx.add_entity_comment(stack_slot, format!(
+ "{:?}: {:?} size={} align={},{}",
+ local, ty, size.bytes(), align.abi.bytes(), align.pref.bytes(),
+ )),
+ CPlace::NoPlace(_) => fx.add_global_comment(format!(
+ "zst {:?}: {:?} size={} align={}, {}",
+ local, ty, size.bytes(), align.abi.bytes(), align.pref.bytes(),
+ )),
+ _ => unreachable!(),
+ }
+ }
+
+ // Take stack_addr in advance to avoid many duplicate instructions
+ CPlace::Addr(place.to_addr(fx), None, layout)
+ };
+
+ let prev_place = fx.local_map.insert(local, place);
+ debug_assert!(prev_place.is_none());
+ fx.local_map[&local]
+}
- match fx.self_sig().abi {
- Abi::Rust | Abi::RustCall => {}
- _ => unimplemented!("declared function with non \"rust\" or \"rust-call\" abi"),
+fn cvalue_for_param<'a, 'tcx: 'a>(
+ fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
+ start_ebb: Ebb,
+ local: mir::Local,
+ local_field: Option<usize>,
+ arg_ty: Ty<'tcx>,
+ ssa_flags: crate::analyze::Flags,
+) -> CValue<'tcx> {
+ let layout = fx.layout_of(arg_ty);
+ let pass_mode = get_pass_mode(fx.tcx, arg_ty, false);
+ let clif_type = pass_mode.get_param_ty(fx);
+ let ebb_param = fx.bcx.append_ebb_param(start_ebb, clif_type);
+
+ #[cfg(debug_assertions)]
+ add_arg_comment(fx, "arg", local, local_field, Some(ebb_param), pass_mode, ssa_flags, arg_ty);
+
+ match pass_mode {
+ PassMode::NoPass => unimplemented!("pass mode nopass"),
+ PassMode::ByVal(_) => CValue::ByVal(ebb_param, layout),
+ PassMode::ByRef => CValue::ByRef(ebb_param, layout),
}
+}
+
+pub fn codegen_fn_prelude<'a, 'tcx: 'a>(
+ fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
+ start_ebb: Ebb,
+) {
+ let ssa_analyzed = crate::analyze::analyze(fx);
+
+ #[cfg(debug_assertions)]
+ fx.add_global_comment(format!("ssa {:?}", ssa_analyzed));
let ret_layout = fx.layout_of(fx.return_type());
- let output_pass_mode = get_pass_mode(fx.tcx, fx.self_sig().abi, fx.return_type(), true);
+ let output_pass_mode = get_pass_mode(fx.tcx, fx.return_type(), true);
let ret_param = match output_pass_mode {
PassMode::NoPass => None,
- PassMode::ByVal(ret_ty) => None,
- PassMode::ByRef => Some(fx.bcx.append_ebb_param(start_ebb, types::I64)),
+ PassMode::ByVal(_) => None,
+ PassMode::ByRef => Some(fx.bcx.append_ebb_param(start_ebb, fx.pointer_type)),
};
- enum ArgKind {
- Normal(Value),
- Spread(Vec<Value>),
+ #[cfg(debug_assertions)]
+ {
+ add_local_header_comment(fx);
+ add_arg_comment(fx, "ret", RETURN_PLACE, None, ret_param, output_pass_mode, ssa_analyzed[&RETURN_PLACE], ret_layout.ty);
}
- let func_params = fx.mir.args_iter().map(|local| {
- let arg_ty = fx.monomorphize(&fx.mir.local_decls[local].ty);
-
- // Adapted from https://github.com/rust-lang/rust/blob/145155dc96757002c7b2e9de8489416e2fdbbd57/src/librustc_codegen_llvm/mir/mod.rs#L442-L482
- if Some(local) == fx.mir.spread_arg {
- // This argument (e.g. the last argument in the "rust-call" ABI)
- // is a tuple that was spread at the ABI level and now we have
- // to reconstruct it into a tuple local variable, from multiple
- // individual function arguments.
+ enum ArgKind<'tcx> {
+ Normal(CValue<'tcx>),
+ Spread(Vec<CValue<'tcx>>),
+ }
- let tupled_arg_tys = match arg_ty.sty {
- ty::TyTuple(ref tys) => tys,
- _ => bug!("spread argument isn't a tuple?! but {:?}", arg_ty),
- };
+ let func_params = fx
+ .mir
+ .args_iter()
+ .map(|local| {
+ let arg_ty = fx.monomorphize(&fx.mir.local_decls[local].ty);
+
+ // Adapted from https://github.com/rust-lang/rust/blob/145155dc96757002c7b2e9de8489416e2fdbbd57/src/librustc_codegen_llvm/mir/mod.rs#L442-L482
+ if Some(local) == fx.mir.spread_arg {
+ // This argument (e.g. the last argument in the "rust-call" ABI)
+ // is a tuple that was spread at the ABI level and now we have
+ // to reconstruct it into a tuple local variable, from multiple
+ // individual function arguments.
+
+ let tupled_arg_tys = match arg_ty.sty {
+ 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.iter().enumerate() {
+ let param = cvalue_for_param(fx, start_ebb, local, Some(i), arg_ty, ssa_analyzed[&local]);
+ params.push(param);
+ }
- let mut ebb_params = Vec::new();
- for arg_ty in tupled_arg_tys.iter() {
- let cton_type = get_pass_mode(fx.tcx, fx.self_sig().abi, arg_ty, false).get_param_ty(fx);
- ebb_params.push(fx.bcx.append_ebb_param(start_ebb, cton_type));
+ (local, ArgKind::Spread(params), arg_ty)
+ } else {
+ let param = cvalue_for_param(fx, start_ebb, local, None, arg_ty, ssa_analyzed[&local]);
+ (
+ local,
+ ArgKind::Normal(param),
+ arg_ty,
+ )
}
+ })
+ .collect::<Vec<(Local, ArgKind, Ty)>>();
- (local, ArgKind::Spread(ebb_params), arg_ty)
- } else {
- let cton_type = get_pass_mode(fx.tcx, fx.self_sig().abi, arg_ty, false).get_param_ty(fx);
- (local, ArgKind::Normal(fx.bcx.append_ebb_param(start_ebb, cton_type)), arg_ty)
- }
- }).collect::<Vec<(Local, ArgKind, Ty)>>();
+ fx.bcx.switch_to_block(start_ebb);
match output_pass_mode {
PassMode::NoPass => {
- let null = fx.bcx.ins().iconst(types::I64, 0);
- //unimplemented!("pass mode nopass");
- fx.local_map.insert(
- RETURN_PLACE,
- CPlace::Addr(null, fx.layout_of(fx.return_type())),
- );
+ fx.local_map.insert(RETURN_PLACE, CPlace::NoPlace(ret_layout));
}
- PassMode::ByVal(ret_ty) => {
- let var = Variable(RETURN_PLACE);
- fx.bcx.declare_var(var, ret_ty);
- fx.local_map
- .insert(RETURN_PLACE, CPlace::Var(var, ret_layout));
+ PassMode::ByVal(_) => {
+ let is_ssa = !ssa_analyzed
+ .get(&RETURN_PLACE)
+ .unwrap()
+ .contains(crate::analyze::Flags::NOT_SSA);
+
+ local_place(fx, RETURN_PLACE, ret_layout, is_ssa);
}
PassMode::ByRef => {
- fx.local_map
- .insert(RETURN_PLACE, CPlace::Addr(ret_param.unwrap(), ret_layout));
+ fx.local_map.insert(
+ RETURN_PLACE,
+ CPlace::Addr(ret_param.unwrap(), None, ret_layout),
+ );
}
}
for (local, arg_kind, ty) in func_params {
let layout = fx.layout_of(ty);
- if let ArgKind::Normal(ebb_param) = arg_kind {
- if !ssa_analyzed
- .get(&local)
- .unwrap()
- .contains(crate::analyze::Flags::NOT_SSA)
- {
- let var = Variable(local);
- fx.bcx.declare_var(var, fx.cton_type(ty).unwrap());
- match get_pass_mode(fx.tcx, fx.self_sig().abi, ty, false) {
- PassMode::NoPass => unimplemented!("pass mode nopass"),
- PassMode::ByVal(_) => fx.bcx.def_var(var, ebb_param),
- PassMode::ByRef => {
- let val = CValue::ByRef(ebb_param, fx.layout_of(ty)).load_value(fx);
- fx.bcx.def_var(var, val);
- }
- }
- fx.local_map.insert(local, CPlace::Var(var, layout));
- continue;
- }
- }
-
- let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
- kind: StackSlotKind::ExplicitSlot,
- size: layout.size.bytes() as u32,
- offset: None,
- });
+ let is_ssa = !ssa_analyzed
+ .get(&local)
+ .unwrap()
+ .contains(crate::analyze::Flags::NOT_SSA);
- let place = CPlace::from_stack_slot(fx, stack_slot, ty);
+ let place = local_place(fx, local, layout, is_ssa);
match arg_kind {
- ArgKind::Normal(ebb_param) => match get_pass_mode(fx.tcx, fx.self_sig().abi, ty, false)
- {
- PassMode::NoPass => unimplemented!("pass mode nopass"),
- PassMode::ByVal(_) => {
- place.write_cvalue(fx, CValue::ByVal(ebb_param, place.layout()))
- }
- PassMode::ByRef => place.write_cvalue(fx, CValue::ByRef(ebb_param, place.layout())),
- },
- ArgKind::Spread(ebb_params) => {
- for (i, ebb_param) in ebb_params.into_iter().enumerate() {
- let sub_place = place.place_field(fx, mir::Field::new(i));
- match get_pass_mode(fx.tcx, fx.self_sig().abi, sub_place.layout().ty, false) {
- PassMode::NoPass => unimplemented!("pass mode nopass"),
- PassMode::ByVal(_) => {
- sub_place.write_cvalue(fx, CValue::ByVal(ebb_param, sub_place.layout()))
- }
- PassMode::ByRef => {
- sub_place.write_cvalue(fx, CValue::ByRef(ebb_param, sub_place.layout()))
- }
- }
+ ArgKind::Normal(param) => {
+ place.write_cvalue(fx, param);
+ }
+ ArgKind::Spread(params) => {
+ for (i, param) in params.into_iter().enumerate() {
+ place.place_field(fx, mir::Field::new(i)).write_cvalue(fx, param);
}
}
}
- fx.local_map.insert(local, place);
}
for local in fx.mir.vars_and_temps_iter() {
let ty = fx.mir.local_decls[local].ty;
let layout = fx.layout_of(ty);
- let place = if ssa_analyzed
+ let is_ssa = !ssa_analyzed
.get(&local)
.unwrap()
- .contains(crate::analyze::Flags::NOT_SSA)
- {
- let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
- kind: StackSlotKind::ExplicitSlot,
- size: layout.size.bytes() as u32,
- offset: None,
- });
- CPlace::from_stack_slot(fx, stack_slot, ty)
- } else {
- let var = Variable(local);
- fx.bcx.declare_var(var, fx.cton_type(ty).unwrap());
- CPlace::Var(var, layout)
- };
+ .contains(crate::analyze::Flags::NOT_SSA);
- fx.local_map.insert(local, place);
+ local_place(fx, local, layout, is_ssa);
}
+
+ fx.bcx
+ .ins()
+ .jump(*fx.ebb_map.get(&START_BLOCK).unwrap(), &[]);
}
-pub fn codegen_call<'a, 'tcx: 'a>(
- fx: &mut FunctionCx<'a, 'tcx>,
+pub fn codegen_terminator_call<'a, 'tcx: 'a>(
+ fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
func: &Operand<'tcx>,
args: &[Operand<'tcx>],
destination: &Option<(Place<'tcx>, BasicBlock)>,
) {
- let func = trans_operand(fx, func);
- let fn_ty = func.layout().ty;
+ let fn_ty = fx.monomorphize(&func.ty(fx.mir, fx.tcx));
let sig = ty_fn_sig(fx.tcx, fn_ty);
// Unpack arguments tuple for closures
let mut args = Vec::new();
args.push(self_arg);
match pack_arg.layout().ty.sty {
- ty::TyTuple(ref tupled_arguments) => {
+ ty::Tuple(ref tupled_arguments) => {
for (i, _) in tupled_arguments.iter().enumerate() {
args.push(pack_arg.value_field(fx, mir::Field::new(i)));
}
}
_ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
}
- println!(
- "{:?} {:?}",
- pack_arg.layout().ty,
- args.iter().map(|a| a.layout().ty).collect::<Vec<_>>()
- );
args
} else {
args.into_iter()
let destination = destination
.as_ref()
- .map(|(place, bb)| (trans_place(fx, place), *bb));
+ .map(|&(ref place, bb)| (trans_place(fx, place), bb));
+
+ if let ty::FnDef(def_id, substs) = fn_ty.sty {
+ let instance = ty::Instance::resolve(
+ fx.tcx,
+ ty::ParamEnv::reveal_all(),
+ def_id,
+ substs,
+ ).unwrap();
+
+ match instance.def {
+ InstanceDef::Intrinsic(_) => {
+ crate::intrinsics::codegen_intrinsic_call(fx, def_id, substs, args, destination);
+ return;
+ }
+ InstanceDef::DropGlue(_, None) => {
+ // empty drop glue - a nop.
+ let (_, dest) = destination.expect("Non terminating drop_in_place_real???");
+ let ret_ebb = fx.get_ebb(dest);
+ fx.bcx.ins().jump(ret_ebb, &[]);
+ return;
+ }
+ _ => {}
+ }
+ }
- if codegen_intrinsic_call(fx, fn_ty, sig, &args, destination) {
- return;
+ codegen_call_inner(
+ fx,
+ Some(func),
+ fn_ty,
+ args,
+ destination.map(|(place, _)| place),
+ );
+
+ if let Some((_, dest)) = destination {
+ let ret_ebb = fx.get_ebb(dest);
+ fx.bcx.ins().jump(ret_ebb, &[]);
+ } else {
+ trap_unreachable(&mut fx.bcx);
}
+}
- let ret_layout = fx.layout_of(sig.output());
+pub fn codegen_call_inner<'a, 'tcx: 'a>(
+ fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
+ func: Option<&Operand<'tcx>>,
+ fn_ty: Ty<'tcx>,
+ args: Vec<CValue<'tcx>>,
+ ret_place: Option<CPlace<'tcx>>,
+) {
+ let fn_sig = ty_fn_sig(fx.tcx, fn_ty);
- let output_pass_mode = get_pass_mode(fx.tcx, sig.abi, sig.output(), true);
- println!("{:?}", output_pass_mode);
+ let ret_layout = fx.layout_of(fn_sig.output());
+
+ let output_pass_mode = get_pass_mode(fx.tcx, fn_sig.output(), true);
let return_ptr = match output_pass_mode {
PassMode::NoPass => None,
- PassMode::ByRef => match destination {
- Some((place, _)) => Some(place.expect_addr()),
- None => Some(fx.bcx.ins().iconst(types::I64, 0)),
+ PassMode::ByRef => match ret_place {
+ Some(ret_place) => Some(ret_place.to_addr(fx)),
+ None => Some(fx.bcx.ins().iconst(fx.pointer_type, 0)),
},
PassMode::ByVal(_) => None,
};
+ let instance = match fn_ty.sty {
+ ty::FnDef(def_id, substs) => {
+ Some(Instance::resolve(fx.tcx, ParamEnv::reveal_all(), def_id, substs).unwrap())
+ }
+ _ => None,
+ };
+
+ let func_ref: Option<Value>; // Indirect call target
+
+ let first_arg = {
+ if let Some(Instance {
+ def: InstanceDef::Virtual(_, idx),
+ ..
+ }) = instance
+ {
+ let (ptr, method) = crate::vtable::get_ptr_and_method_ref(fx, args[0], idx);
+ func_ref = Some(method);
+ Some(ptr)
+ } else {
+ func_ref = if instance.is_none() {
+ let func = trans_operand(fx, func.expect("indirect call without func Operand"));
+ Some(func.load_scalar(fx))
+ } else {
+ None
+ };
+
+ args.get(0).map(|arg| adjust_arg_for_abi(fx, *arg))
+ }
+ .into_iter()
+ };
+
let call_args: Vec<Value> = return_ptr
.into_iter()
- .chain(args.into_iter().map(|arg| {
- match get_pass_mode(fx.tcx, sig.abi, arg.layout().ty, false) {
- PassMode::NoPass => unimplemented!("pass mode nopass"),
- PassMode::ByVal(_) => arg.load_value(fx),
- PassMode::ByRef => arg.force_stack(fx),
- }
- })).collect::<Vec<_>>();
-
- let inst = match func {
- CValue::Func(func, _) => fx.bcx.ins().call(func, &call_args),
- func => {
- let func = func.load_value(fx);
- let sig = fx.bcx.import_signature(cton_sig_from_fn_ty(fx.tcx, fn_ty));
- fx.bcx.ins().call_indirect(sig, func, &call_args)
- }
+ .chain(first_arg)
+ .chain(
+ args.into_iter()
+ .skip(1)
+ .map(|arg| adjust_arg_for_abi(fx, arg)),
+ )
+ .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));
+ 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)
};
match output_pass_mode {
PassMode::NoPass => {}
PassMode::ByVal(_) => {
- if let Some((ret_place, _)) = destination {
- let results = fx.bcx.inst_results(inst);
+ if let Some(ret_place) = ret_place {
+ let results = fx.bcx.inst_results(call_inst);
ret_place.write_cvalue(fx, CValue::ByVal(results[0], ret_layout));
}
}
PassMode::ByRef => {}
}
- if let Some((_, dest)) = destination {
- let ret_ebb = fx.get_ebb(dest);
- fx.bcx.ins().jump(ret_ebb, &[]);
- } else {
- fx.bcx.ins().trap(TrapCode::User(!0));
- }
}
-pub fn codegen_return(fx: &mut FunctionCx) {
- match get_pass_mode(fx.tcx, fx.self_sig().abi, fx.return_type(), true) {
+pub fn codegen_return(fx: &mut FunctionCx<impl Backend>) {
+ match get_pass_mode(fx.tcx, fx.return_type(), true) {
PassMode::NoPass | PassMode::ByRef => {
fx.bcx.ins().return_(&[]);
}
PassMode::ByVal(_) => {
let place = fx.get_local_place(RETURN_PLACE);
- let ret_val = place.to_cvalue(fx).load_value(fx);
+ let ret_val = place.to_cvalue(fx).load_scalar(fx);
fx.bcx.ins().return_(&[ret_val]);
}
}
}
-
-fn codegen_intrinsic_call<'a, 'tcx: 'a>(
- fx: &mut FunctionCx<'a, 'tcx>,
- fn_ty: Ty<'tcx>,
- sig: FnSig<'tcx>,
- args: &[CValue<'tcx>],
- destination: Option<(CPlace<'tcx>, BasicBlock)>,
-) -> bool {
- if let TypeVariants::TyFnDef(def_id, substs) = fn_ty.sty {
- if sig.abi == Abi::RustIntrinsic {
- let intrinsic = fx.tcx.item_name(def_id).as_str();
- let intrinsic = &intrinsic[..];
-
- let ret = match destination {
- Some((place, _)) => place,
- None => {
- println!("codegen_call(fx, _, {:?}, {:?})", args, destination);
- // Insert non returning intrinsics here
- match intrinsic {
- "abort" => {
- fx.bcx.ins().trap(TrapCode::User(!0 - 1));
- }
- "unreachable" => {
- fx.bcx.ins().trap(TrapCode::User(!0 - 1));
- }
- _ => unimplemented!("unsupported instrinsic {}", intrinsic),
- }
- return true;
- }
- };
-
- let nil_ty = fx.tcx.mk_nil();
- let u64_layout = fx.layout_of(fx.tcx.types.u64);
- let usize_layout = fx.layout_of(fx.tcx.types.usize);
-
- match intrinsic {
- "assume" => {
- assert_eq!(args.len(), 1);
- }
- "arith_offset" => {
- assert_eq!(args.len(), 2);
- let base = args[0].load_value(fx);
- let offset = args[1].load_value(fx);
- let res = fx.bcx.ins().iadd(base, offset);
- let res = CValue::ByVal(res, ret.layout());
- ret.write_cvalue(fx, res);
- }
- "likely" | "unlikely" => {
- assert_eq!(args.len(), 1);
- ret.write_cvalue(fx, args[0]);
- }
- "copy" | "copy_nonoverlapping" => {
- let elem_ty = substs.type_at(0);
- let elem_size: u64 = fx.layout_of(elem_ty).size.bytes();
- let elem_size = fx.bcx.ins().iconst(types::I64, elem_size as i64);
- assert_eq!(args.len(), 3);
- let src = args[0];
- let dst = args[1];
- let count = args[2].load_value(fx);
- let byte_amount = fx.bcx.ins().imul(count, elem_size);
- fx.easy_call(
- "memmove",
- &[dst, src, CValue::ByVal(byte_amount, usize_layout)],
- nil_ty,
- );
- }
- "discriminant_value" => {
- assert_eq!(args.len(), 1);
- let discr = crate::base::trans_get_discriminant(fx, args[0], ret.layout());
- ret.write_cvalue(fx, discr);
- }
- "size_of" => {
- assert_eq!(args.len(), 0);
- let size_of = fx.layout_of(substs.type_at(0)).size.bytes();
- let size_of = CValue::const_val(fx, usize_layout.ty, size_of as i64);
- ret.write_cvalue(fx, size_of);
- }
- "type_id" => {
- assert_eq!(args.len(), 0);
- let type_id = fx.tcx.type_id_hash(substs.type_at(0));
- let type_id = CValue::const_val(fx, u64_layout.ty, type_id as i64);
- ret.write_cvalue(fx, type_id);
- }
- "min_align_of" => {
- assert_eq!(args.len(), 0);
- let min_align = fx.layout_of(substs.type_at(0)).align.abi();
- let min_align = CValue::const_val(fx, usize_layout.ty, min_align as i64);
- ret.write_cvalue(fx, min_align);
- }
- _ if intrinsic.starts_with("unchecked_") => {
- assert_eq!(args.len(), 2);
- let bin_op = match intrinsic {
- "unchecked_div" => BinOp::Div,
- "unchecked_rem" => BinOp::Rem,
- "unchecked_shl" => BinOp::Shl,
- "unchecked_shr" => BinOp::Shr,
- _ => unimplemented!("intrinsic {}", intrinsic),
- };
- let res = match ret.layout().ty.sty {
- TypeVariants::TyUint(_) => crate::base::trans_int_binop(
- fx,
- bin_op,
- args[0],
- args[1],
- ret.layout().ty,
- false,
- ),
- TypeVariants::TyInt(_) => crate::base::trans_int_binop(
- fx,
- bin_op,
- args[0],
- args[1],
- ret.layout().ty,
- true,
- ),
- _ => panic!(),
- };
- ret.write_cvalue(fx, res);
- }
- _ if intrinsic.ends_with("_with_overflow") => {
- assert_eq!(args.len(), 2);
- assert_eq!(args[0].layout().ty, args[1].layout().ty);
- let bin_op = match intrinsic {
- "add_with_overflow" => BinOp::Add,
- "sub_with_overflow" => BinOp::Sub,
- "mul_with_overflow" => BinOp::Mul,
- _ => unimplemented!("intrinsic {}", intrinsic),
- };
- let res = match args[0].layout().ty.sty {
- TypeVariants::TyUint(_) => crate::base::trans_checked_int_binop(
- fx,
- bin_op,
- args[0],
- args[1],
- ret.layout().ty,
- false,
- ),
- TypeVariants::TyInt(_) => crate::base::trans_checked_int_binop(
- fx,
- bin_op,
- args[0],
- args[1],
- ret.layout().ty,
- true,
- ),
- _ => panic!(),
- };
- ret.write_cvalue(fx, res);
- }
- _ if intrinsic.starts_with("overflowing_") => {
- assert_eq!(args.len(), 2);
- assert_eq!(args[0].layout().ty, args[1].layout().ty);
- let bin_op = match intrinsic {
- "overflowing_add" => BinOp::Add,
- "overflowing_sub" => BinOp::Sub,
- "overflowing_mul" => BinOp::Mul,
- _ => unimplemented!("intrinsic {}", intrinsic),
- };
- let res = match args[0].layout().ty.sty {
- TypeVariants::TyUint(_) => crate::base::trans_int_binop(
- fx,
- bin_op,
- args[0],
- args[1],
- ret.layout().ty,
- false,
- ),
- TypeVariants::TyInt(_) => crate::base::trans_int_binop(
- fx,
- bin_op,
- args[0],
- args[1],
- ret.layout().ty,
- true,
- ),
- _ => panic!(),
- };
- ret.write_cvalue(fx, res);
- }
- "offset" => {
- assert_eq!(args.len(), 2);
- let base = args[0].load_value(fx);
- let offset = args[1].load_value(fx);
- let res = fx.bcx.ins().iadd(base, offset);
- ret.write_cvalue(fx, CValue::ByVal(res, args[0].layout()));
- }
- "transmute" => {
- assert_eq!(args.len(), 1);
- let src_ty = substs.type_at(0);
- let dst_ty = substs.type_at(1);
- assert_eq!(args[0].layout().ty, src_ty);
- let addr = args[0].force_stack(fx);
- let dst_layout = fx.layout_of(dst_ty);
- ret.write_cvalue(fx, CValue::ByRef(addr, dst_layout))
- }
- "uninit" => {
- assert_eq!(args.len(), 0);
- let ty = substs.type_at(0);
- let layout = fx.layout_of(ty);
- let stack_slot = fx.bcx.create_stack_slot(StackSlotData {
- kind: StackSlotKind::ExplicitSlot,
- size: layout.size.bytes() as u32,
- offset: None,
- });
-
- let uninit_place = CPlace::from_stack_slot(fx, stack_slot, ty);
- let uninit_val = uninit_place.to_cvalue(fx);
- ret.write_cvalue(fx, uninit_val);
- }
- "ctlz" | "ctlz_nonzero" => {
- assert_eq!(args.len(), 1);
- let arg = args[0].load_value(fx);
- let res = CValue::ByVal(fx.bcx.ins().clz(arg), args[0].layout());
- ret.write_cvalue(fx, res);
- }
- "cttz" | "cttz_nonzero" => {
- assert_eq!(args.len(), 1);
- let arg = args[0].load_value(fx);
- let res = CValue::ByVal(fx.bcx.ins().clz(arg), args[0].layout());
- ret.write_cvalue(fx, res);
- }
- "ctpop" => {
- assert_eq!(args.len(), 1);
- let arg = args[0].load_value(fx);
- let res = CValue::ByVal(fx.bcx.ins().popcnt(arg), args[0].layout());
- ret.write_cvalue(fx, res);
- }
- _ => unimpl!("unsupported intrinsic {}", intrinsic),
- }
-
- if let Some((_, dest)) = destination {
- let ret_ebb = fx.get_ebb(dest);
- fx.bcx.ins().jump(ret_ebb, &[]);
- } else {
- fx.bcx.ins().trap(TrapCode::User(!0));
- }
- return true;
- }
- }
-
- false
-}