]> git.lizzy.rs Git - rust.git/blobdiff - src/abi/mod.rs
Rustup to rustc 1.40.0-nightly (9e346646e 2019-11-08)
[rust.git] / src / abi / mod.rs
index eaf25ef48ec0bbbc1696fe0c5f39f7f1eeb317c1..881174646afe7bbd32c025ec650debee2fd020b8 100644 (file)
@@ -1,16 +1,20 @@
 #[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 {
@@ -22,20 +26,20 @@ fn clif_sig_from_fn_sig<'tcx>(tcx: TyCtxt<'tcx>, sig: FnSig<'tcx>, is_vtable_fn:
         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),
     };
 
@@ -47,12 +51,18 @@ fn clif_sig_from_fn_sig<'tcx>(tcx: TyCtxt<'tcx>, sig: FnSig<'tcx>, is_vtable_fn:
             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(),
@@ -87,12 +97,13 @@ pub fn get_function_name_and_sig<'tcx>(
     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
@@ -131,7 +142,7 @@ fn lib_call(
         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
@@ -141,7 +152,8 @@ fn lib_call(
             .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);
@@ -165,7 +177,7 @@ pub fn easy_call(
             })
             .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()]
@@ -185,7 +197,10 @@ pub fn easy_call(
     }
 
     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> {
@@ -213,10 +228,7 @@ fn local_place<'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)]
@@ -243,27 +255,20 @@ enum ArgKind<'tcx> {
                 // 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)
             }
         })
@@ -277,10 +282,35 @@ enum ArgKind<'tcx> {
     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);
 
@@ -306,10 +336,7 @@ enum ArgKind<'tcx> {
         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);
     }
@@ -324,26 +351,35 @@ pub fn codegen_terminator_call<'tcx>(
     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) => {
@@ -364,7 +400,7 @@ pub fn codegen_terminator_call<'tcx>(
         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)));
@@ -402,9 +438,11 @@ fn codegen_call_inner<'tcx>(
     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())
         }
@@ -425,7 +463,10 @@ fn codegen_call_inner<'tcx>(
                 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);
@@ -433,7 +474,13 @@ fn codegen_call_inner<'tcx>(
         }
 
         // 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 => {
@@ -446,36 +493,40 @@ fn codegen_call_inner<'tcx>(
                 .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 {
@@ -498,10 +549,7 @@ fn codegen_call_inner<'tcx>(
     }
 }
 
-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);
 
@@ -509,12 +557,15 @@ pub fn codegen_drop<'tcx>(
         // 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());
 
@@ -536,13 +587,7 @@ pub fn codegen_drop<'tcx>(
                 );
                 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);
             }
         }
     }