1
Fork 0

Check the number of arguments first in is_recursive_call

This commit is contained in:
Tomasz Miąsko 2022-01-27 00:00:00 +00:00
parent a00e130dae
commit 35b5daaaf8

View file

@ -66,8 +66,14 @@ struct Search<'mir, 'tcx> {
impl<'mir, 'tcx> Search<'mir, 'tcx> { impl<'mir, 'tcx> Search<'mir, 'tcx> {
/// Returns `true` if `func` refers to the function we are searching in. /// Returns `true` if `func` refers to the function we are searching in.
fn is_recursive_call(&self, func: &Operand<'tcx>) -> bool { fn is_recursive_call(&self, func: &Operand<'tcx>, args: &[Operand<'tcx>]) -> bool {
let Search { tcx, body, trait_substs, .. } = *self; let Search { tcx, body, trait_substs, .. } = *self;
// Resolving function type to a specific instance that is being called is expensive. To
// avoid the cost we check the number of arguments first, which is sufficient to reject
// most of calls as non-recursive.
if args.len() != body.arg_count {
return false;
}
let caller = body.source.def_id(); let caller = body.source.def_id();
let param_env = tcx.param_env(caller); let param_env = tcx.param_env(caller);
@ -141,8 +147,8 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> {
fn node_settled(&mut self, bb: BasicBlock) -> ControlFlow<Self::BreakVal> { fn node_settled(&mut self, bb: BasicBlock) -> ControlFlow<Self::BreakVal> {
// When we examine a node for the last time, remember it if it is a recursive call. // When we examine a node for the last time, remember it if it is a recursive call.
let terminator = self.body[bb].terminator(); let terminator = self.body[bb].terminator();
if let TerminatorKind::Call { func, .. } = &terminator.kind { if let TerminatorKind::Call { func, args, .. } = &terminator.kind {
if self.is_recursive_call(func) { if self.is_recursive_call(func, args) {
self.reachable_recursive_calls.push(terminator.source_info.span); self.reachable_recursive_calls.push(terminator.source_info.span);
} }
} }
@ -157,7 +163,7 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> {
} }
// Don't traverse successors of recursive calls or false CFG edges. // Don't traverse successors of recursive calls or false CFG edges.
match self.body[bb].terminator().kind { match self.body[bb].terminator().kind {
TerminatorKind::Call { ref func, .. } => self.is_recursive_call(func), TerminatorKind::Call { ref func, ref args, .. } => self.is_recursive_call(func, args),
TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == target, TerminatorKind::FalseEdge { imaginary_target, .. } => imaginary_target == target,
_ => false, _ => false,
} }