From 119cb0dd29f4b2d83f6c7d0a787fbd0c2d6ceaed Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Fri, 30 Jun 2023 18:27:43 +0000 Subject: [PATCH] Refactor common part of evaluating `Call`&`TailCall` in the interpreter --- .../src/interpret/terminator.rs | 117 +++++++++--------- 1 file changed, 56 insertions(+), 61 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index f7fb5fd27889c..a867a4dea48e6 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -67,36 +67,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } => { let old_stack = self.frame_idx(); let old_loc = self.frame().loc; - let func = self.eval_operand(func, None)?; - let args = self.eval_operands(args)?; - - let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx); - let fn_sig = - self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder); - let extra_args = &args[fn_sig.inputs().len()..]; - let extra_args = - self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout.ty)); - - let (fn_val, fn_abi, with_caller_location) = match *func.layout.ty.kind() { - ty::FnPtr(_sig) => { - let fn_ptr = self.read_pointer(&func)?; - let fn_val = self.get_ptr_fn(fn_ptr)?; - (fn_val, self.fn_abi_of_fn_ptr(fn_sig_binder, extra_args)?, false) - } - ty::FnDef(def_id, substs) => { - let instance = self.resolve(def_id, substs)?; - ( - FnVal::Instance(instance), - self.fn_abi_of_instance(instance, extra_args)?, - instance.def.requires_caller_location(*self.tcx), - ) - } - _ => span_bug!( - terminator.source_info.span, - "invalid callee of type {:?}", - func.layout.ty - ), - }; + + let (fn_val, args, fn_sig, fn_abi, with_caller_location) = + self.prepare_fn_for_call(terminator, func, args)?; let destination = self.eval_place(destination)?; self.eval_fn_call( @@ -116,38 +89,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } TailCall { ref func, ref args, fn_span: _ } => { - // FIXME(explicit_tail_calls): a lot of code here is duplicated with normal calls, can we refactor this? let old_frame_idx = self.frame_idx(); - let func = self.eval_operand(func, None)?; - let args = self.eval_operands(args)?; - - let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx); - let fn_sig = - self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder); - let extra_args = &args[fn_sig.inputs().len()..]; - let extra_args = - self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout.ty)); - - let (fn_val, fn_abi, with_caller_location) = match *func.layout.ty.kind() { - ty::FnPtr(_sig) => { - let fn_ptr = self.read_pointer(&func)?; - let fn_val = self.get_ptr_fn(fn_ptr)?; - (fn_val, self.fn_abi_of_fn_ptr(fn_sig_binder, extra_args)?, false) - } - ty::FnDef(def_id, substs) => { - let instance = self.resolve(def_id, substs)?; - ( - FnVal::Instance(instance), - self.fn_abi_of_instance(instance, extra_args)?, - instance.def.requires_caller_location(*self.tcx), - ) - } - _ => span_bug!( - terminator.source_info.span, - "invalid callee of type {:?}", - func.layout.ty - ), - }; + + let (fn_val, args, fn_sig, fn_abi, with_caller_location) = + self.prepare_fn_for_call(terminator, func, args)?; // This is the "canonical" implementation of tails calls, // a pop of the current stack frame, followed by a normal call @@ -401,6 +346,56 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.copy_op(&caller_arg, callee_arg, /*allow_transmute*/ true) } + /// Shared part of `Call` and `TailCall` implementation — finding and evaluating all the + /// necessary information about callee to make a call. + fn prepare_fn_for_call( + &self, + terminator: &mir::Terminator<'tcx>, + func: &mir::Operand<'tcx>, + args: &[mir::Operand<'tcx>], + ) -> InterpResult< + 'tcx, + ( + FnVal<'tcx, M::ExtraFnVal>, + Vec>, + ty::FnSig<'tcx>, + &'tcx FnAbi<'tcx, Ty<'tcx>>, + bool, + ), + > { + let func = self.eval_operand(func, None)?; + let args = self.eval_operands(args)?; + + let fn_sig_binder = func.layout.ty.fn_sig(*self.tcx); + let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, fn_sig_binder); + let extra_args = &args[fn_sig.inputs().len()..]; + let extra_args = + self.tcx.mk_type_list_from_iter(extra_args.iter().map(|arg| arg.layout.ty)); + + let (fn_val, fn_abi, with_caller_location) = match *func.layout.ty.kind() { + ty::FnPtr(_sig) => { + let fn_ptr = self.read_pointer(&func)?; + let fn_val = self.get_ptr_fn(fn_ptr)?; + (fn_val, self.fn_abi_of_fn_ptr(fn_sig_binder, extra_args)?, false) + } + ty::FnDef(def_id, substs) => { + let instance = self.resolve(def_id, substs)?; + ( + FnVal::Instance(instance), + self.fn_abi_of_instance(instance, extra_args)?, + instance.def.requires_caller_location(*self.tcx), + ) + } + _ => span_bug!( + terminator.source_info.span, + "invalid callee of type {:?}", + func.layout.ty + ), + }; + + Ok((fn_val, args, fn_sig, fn_abi, with_caller_location)) + } + /// Call this function -- pushing the stack frame and initializing the arguments. /// /// `caller_fn_abi` is used to determine if all the arguments are passed the proper way.