Skip to content

Commit

Permalink
Refactor common part of evaluating Call&TailCall in the interpreter
Browse files Browse the repository at this point in the history
  • Loading branch information
WaffleLapkin committed Jun 30, 2023
1 parent 7727481 commit 119cb0d
Showing 1 changed file with 56 additions and 61 deletions.
117 changes: 56 additions & 61 deletions compiler/rustc_const_eval/src/interpret/terminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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
Expand Down Expand Up @@ -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<OpTy<'tcx, M::Provenance>>,
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.
Expand Down

0 comments on commit 119cb0d

Please sign in to comment.