Skip to content

Commit

Permalink
Use graph algorithm to identify loops instead
Browse files Browse the repository at this point in the history
  • Loading branch information
qinheping committed Aug 20, 2024
1 parent d5acbe5 commit 0de9681
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 9 deletions.
4 changes: 2 additions & 2 deletions tests/script-based-pre/tool-scanner/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ pub fn with_iterator(input: &[usize]) -> usize {
.iter()
.copied()
.find(|e| *e == 0)
.unwrap_or_else(|| input.iter().fold(0, |acc, i| acc + 1))
.unwrap_or_else(|| input.iter().fold(0, |acc, _| acc + 1))
}

pub fn with_for_loop(input: &[usize]) -> usize {
let mut res = 0;
for n in input {
for _ in input {
res += 1;
}
res
Expand Down
2 changes: 2 additions & 0 deletions tools/scanner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ csv = "1.3"
serde = {version = "1", features = ["derive"]}
strum = "0.26"
strum_macros = "0.26"
petgraph = "0.6.5"
graph-cycles = "0.1.0"

[package.metadata.rust-analyzer]
# This crate uses rustc crates.
Expand Down
24 changes: 17 additions & 7 deletions tools/scanner/src/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
use crate::info;
use csv::WriterBuilder;
use graph_cycles::Cycles;
use petgraph::graph::Graph;
use serde::{ser::SerializeStruct, Serialize, Serializer};
use stable_mir::mir::mono::Instance;
use stable_mir::mir::visit::{Location, PlaceContext, PlaceRef};
Expand Down Expand Up @@ -473,7 +475,8 @@ fn_props! {

impl FnLoops {
pub fn collect(self, body: &Body) -> FnLoops {
let mut visitor = IteratorVisitor { props: self, body, visited_blocks: HashSet::new() };
let mut visitor =
IteratorVisitor { props: self, body, graph: Vec::new(), current_bbidx: 0 };
visitor.visit_body(body);
visitor.props
}
Expand All @@ -494,23 +497,30 @@ impl FnLoops {
struct IteratorVisitor<'a> {
props: FnLoops,
body: &'a Body,
visited_blocks: HashSet<usize>,
graph: Vec<(u32, u32)>,
current_bbidx: u32,
}

impl<'a> MirVisitor for IteratorVisitor<'a> {
fn visit_body(&mut self, body: &Body) {
// First visit the body to build the control flow graph
self.super_body(body);
// Build the petgraph from the adj vec
let g = Graph::<(), ()>::from_edges(self.graph.clone());
self.props.loops += g.cycles().len();
}

fn visit_basic_block(&mut self, bb: &BasicBlock) {
self.visited_blocks.insert(self.body.blocks.iter().position(|b| *b == *bb).unwrap());
self.current_bbidx = self.body.blocks.iter().position(|b| *b == *bb).unwrap() as u32;
self.super_basic_block(bb);
}

fn visit_terminator(&mut self, term: &Terminator, location: Location) {
// Check if any successor has been visited---the terminator is a loop latch.
// Add edges between basic block into the adj table
let successors = term.kind.successors();
let mut contain_loop = false;
for target in successors {
contain_loop |= self.visited_blocks.contains(&target);
self.graph.push((self.current_bbidx, target as u32));
}
self.props.loops += contain_loop as usize;

if let TerminatorKind::Call { func, .. } = &term.kind {
let kind = func.ty(self.body.locals()).unwrap().kind();
Expand Down

0 comments on commit 0de9681

Please sign in to comment.