From b1a512dbf6152be70f0a26a4f3494bc94c031b8f Mon Sep 17 00:00:00 2001 From: Chris Fallin Date: Thu, 10 Mar 2022 10:35:08 -0800 Subject: [PATCH] Checker analysis: change order of block processing for better efficiency. (#29) After going through the checker with @fitzgen, we discussed the dataflow analysis and @fitzgen noted that it would likely be more efficient to, for example, process an inner cycle of blocks in a loop nest and converge before returning to the outer loop. I had written a BFS-style workqueue loop to converge the dataflow analysis without much thought, with a FIFO workqueue. Any workqueue ordering will work and will converge to the same fixpoint (as long as we are operating on a lattice), but indeed some orderings will be more efficient, and a DFS-style (LIFO stack) workqueue will give us this property of converging inner loops first. In measurements, there doesn't seem to be much of a difference for small fuzz testcases, but this will likely matter more if/when we try to run the checker to validate register allocation on large functions. --- src/checker.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/checker.rs b/src/checker.rs index 3ccb6df..3da8cb5 100644 --- a/src/checker.rs +++ b/src/checker.rs @@ -102,7 +102,6 @@ use crate::{ }; use fxhash::{FxHashMap, FxHashSet}; use smallvec::{smallvec, SmallVec}; -use std::collections::VecDeque; use std::default::Default; use std::hash::Hash; use std::result::Result; @@ -726,16 +725,14 @@ impl<'a, F: Function> Checker<'a, F> { /// Perform the dataflow analysis to compute checker state at each BB entry. fn analyze(&mut self) { - let mut queue = VecDeque::new(); + let mut queue = Vec::new(); let mut queue_set = FxHashSet::default(); - for block in 0..self.f.num_blocks() { - let block = Block::new(block); - queue.push_back(block); - queue_set.insert(block); - } + + queue.push(self.f.entry_block()); + queue_set.insert(self.f.entry_block()); while !queue.is_empty() { - let block = queue.pop_front().unwrap(); + let block = queue.pop().unwrap(); queue_set.remove(&block); let mut state = self.bb_in.get(&block).cloned().unwrap(); trace!("analyze: block {} has state {:?}", block.index(), state); @@ -777,7 +774,7 @@ impl<'a, F: Function> Checker<'a, F> { ); self.bb_in.insert(succ, new_state); if !queue_set.contains(&succ) { - queue.push_back(succ); + queue.push(succ); queue_set.insert(succ); } }