Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ tools/profiler/fg-tmp
*.folded
fud2-runs

# compare-experimental-args ignore
tools/compare-experimental-args/out*

temp/

# large queue .data and .expect files ignore
Expand Down
3 changes: 2 additions & 1 deletion calyx/opt/src/default_passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::passes::{
use crate::passes_experimental::{
CompileSync, CompileSyncWithoutSyncReg, DiscoverExternal, ExternalToRef,
FSMAnnotator, FSMBuilder, HoleInliner, Metadata, ParToSeq,
RegisterUnsharing,
RegisterUnsharing, SimplifyIfComb,
};
use crate::traversal::Named;
use crate::{pass_manager::PassManager, register_alias};
Expand Down Expand Up @@ -86,6 +86,7 @@ impl PassManager {
pm.register_pass::<RemoveIds>()?;
pm.register_pass::<ExternalToRef>()?;
pm.register_pass::<ConstantPortProp>()?;
pm.register_pass::<SimplifyIfComb>()?;

// instrumentation pass to collect profiling information
pm.register_pass::<ProfilerInstrumentation>()?;
Expand Down
2 changes: 2 additions & 0 deletions calyx/opt/src/passes_experimental/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod hole_inliner;
mod metadata_table_gen;
mod par_to_seq;
mod register_unsharing;
mod simplify_if_comb;
mod sync;

pub use discover_external::DiscoverExternal;
Expand All @@ -16,5 +17,6 @@ pub use hole_inliner::HoleInliner;
pub use metadata_table_gen::Metadata;
pub use par_to_seq::ParToSeq;
pub use register_unsharing::RegisterUnsharing;
pub use simplify_if_comb::SimplifyIfComb;
pub use sync::CompileSync;
pub use sync::CompileSyncWithoutSyncReg;
128 changes: 128 additions & 0 deletions calyx/opt/src/passes_experimental/simplify_if_comb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor};
use calyx_ir::{self as ir, LibrarySignatures, Rewriter, rewriter::RewriteMap};
use calyx_utils::CalyxResult;
use itertools::Itertools;

/// Transforms `if`s with `comb` groups into `if`s with the condition being computed
/// via continuous assignments.
///
/// The cell used for the condition (and any other cells on the LHS of an assignment
/// in the comb group) will be cloned. Therefore, it is important that dead-cell-removal
/// and dead-group-removal is ran after this pass.
///
/// # Example
/// ```
/// comb cond_comb {
/// lt.left = x.out;
/// lt.right = 32'd10;
/// }
/// ...
/// if lt.out with cond_comb {
/// then_group;
/// }
/// ```
/// into
///
/// ```
/// // continuous assignments
/// lt0.left = x.out;
/// lt0.right = 32'd10;
/// ...
/// if lt0.out {
/// then_group;
/// }
/// ```
pub struct SimplifyIfComb {}

impl Named for SimplifyIfComb {
fn name() -> &'static str {
"simplify-if-comb"
}

fn description() -> &'static str {
"Transform `if` with comb groups into `if` with continuous assignments when there is only one enable in the `then` block and there is no `else` block."
}

fn opts() -> Vec<crate::traversal::PassOpt> {
vec![]
}
}

impl ConstructVisitor for SimplifyIfComb {
fn from(_ctx: &ir::Context) -> CalyxResult<Self>
where
Self: Sized + Named,
{
Ok(SimplifyIfComb {})
}

fn clear_data(&mut self) {}
}

impl Visitor for SimplifyIfComb {
fn finish_if(
&mut self,
s: &mut calyx_ir::If,
comp: &mut calyx_ir::Component,
sigs: &LibrarySignatures,
_comps: &[calyx_ir::Component],
) -> VisResult {
let mut builder = ir::Builder::new(comp, sigs);
let mut rewrite_map = RewriteMap::new();
let mut new_continuous_assignments = Vec::new();

let Some(cond_group_ref) = &s.cond else {
return Ok(Action::Continue);
};
// create new cell for all cells in LHS of cond group assignments
for cond_group_asgn in &cond_group_ref.borrow().assignments {
if let calyx_ir::PortParent::Cell(c) =
&cond_group_asgn.dst.borrow().parent
{
let c_ref = c.upgrade();
let c_name = c_ref.borrow().name();
if !rewrite_map.contains_key(&c_name)
&& let ir::CellType::Primitive {
name,
param_binding,
..
} = &c_ref.borrow().prototype
{
let new_cell = builder.add_primitive(
c_name,
*name,
&param_binding.iter().map(|(_, v)| *v).collect_vec(),
);
rewrite_map.insert(c_name, new_cell);
}
}
}

// move all assignments in cond group to continuous and rewrite cells
for cond_group_asgn in &cond_group_ref.borrow().assignments {
let new_asgn = cond_group_asgn.clone();
new_continuous_assignments.push(new_asgn);
}

let rewrite = Rewriter {
cell_map: rewrite_map,
..Default::default()
};
for asgn in new_continuous_assignments.iter_mut() {
rewrite.rewrite_assign(asgn);
comp.continuous_assignments.push(asgn.clone());
}

// NOTE: Technically no assignments within `s.tbranch` and `s.fbranch` should reference
// any cells that are being set in the original `s.comb` so we probably don't need
// to rewrite the whole `if`, but doing so in case someone refers to cells set in `s.comb`
let mut new_if = calyx_ir::Control::if_(
s.port.clone(),
None,
Box::new(s.tbranch.take_control()),
Box::new(s.fbranch.take_control()),
);
rewrite.rewrite_control(&mut new_if);
Ok(Action::Change(Box::new(new_if)))
}
}
46 changes: 46 additions & 0 deletions tests/passes/simplify-if-comb/mult-cell-use.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import "primitives/core.futil";
import "primitives/memories/comb.futil";
component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) {
cells {
@external mem = comb_mem_d1(32, 1, 1);
lt = std_lt(32);
@generated lt0 = std_lt(32);
@generated lt1 = std_lt(32);
}
wires {
group the_answer {
mem.addr0 = 1'd0;
mem.write_data = 32'd42;
mem.write_en = 1'd1;
the_answer[done] = mem.done;
}
group the_answer_2 {
mem.addr0 = 1'd0;
mem.write_data = 32'd100;
mem.write_en = 1'd1;
the_answer_2[done] = mem.done;
}
comb group cond {
lt.left = 32'd1;
lt.right = 32'd8;
}
comb group cond2 {
lt.left = 32'd1;
lt.right = 32'd100;
}
lt0.left = 32'd1;
lt0.right = 32'd8;
lt1.left = 32'd1;
lt1.right = 32'd100;
}
control {
seq {
if lt0.out {
the_answer;
}
if lt1.out {
the_answer_2;
}
}
}
}
43 changes: 43 additions & 0 deletions tests/passes/simplify-if-comb/mult-cell-use.futil
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// -p simplify-if-comb

import "primitives/core.futil";
import "primitives/memories/comb.futil";

component main(@go go: 1) -> (@done done: 1) {
cells {
@external(1) mem = comb_mem_d1(32, 1, 1);
lt = std_lt(32);
}
wires {
group the_answer {
mem.addr0 = 1'b0;
mem.write_data = 32'd42;
mem.write_en = 1'b1;
the_answer[done] = mem.done;
}
group the_answer_2 {
mem.addr0 = 1'b0;
mem.write_data = 32'd100;
mem.write_en = 1'b1;
the_answer_2[done] = mem.done;
}
comb group cond {
lt.left = 32'd1;
lt.right = 32'd8;
}
comb group cond2 {
lt.left = 32'd1;
lt.right = 32'd100;
}
}
control {
seq {
if lt.out with cond {
the_answer;
}
if lt.out with cond2 {
the_answer_2;
}
}
}
}
28 changes: 28 additions & 0 deletions tests/passes/simplify-if-comb/simple.expect
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import "primitives/core.futil";
import "primitives/memories/comb.futil";
component main(@go go: 1, @clk clk: 1, @reset reset: 1) -> (@done done: 1) {
cells {
@external mem = comb_mem_d1(32, 1, 1);
lt = std_lt(32);
@generated lt0 = std_lt(32);
}
wires {
group the_answer {
mem.addr0 = 1'd0;
mem.write_data = 32'd42;
mem.write_en = 1'd1;
the_answer[done] = mem.done;
}
comb group cond {
lt.left = 32'd1;
lt.right = 32'd8;
}
lt0.left = 32'd1;
lt0.right = 32'd8;
}
control {
if lt0.out {
the_answer;
}
}
}
28 changes: 28 additions & 0 deletions tests/passes/simplify-if-comb/simple.futil
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// -p simplify-if-comb

import "primitives/core.futil";
import "primitives/memories/comb.futil";

component main(@go go: 1) -> (@done done: 1) {
cells {
@external(1) mem = comb_mem_d1(32, 1, 1);
lt = std_lt(32);
}
wires {
group the_answer {
mem.addr0 = 1'b0;
mem.write_data = 32'd42;
mem.write_en = 1'b1;
the_answer[done] = mem.done;
}
comb group cond {
lt.left = 32'd1;
lt.right = 32'd8;
}
}
control {
if lt.out with cond {
the_answer;
}
}
}
51 changes: 51 additions & 0 deletions tools/compare-experimental-args/compare-experimental-args.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# This script compares cycle counts between the default Calyx compiler and experimental compiler arguments.
# Currently this script runs the queues programs using Verilator to benchmark.

if [ $# -lt 1 ]; then
echo "USAGE: bash $0 CALYX_ARGS"
echo "where CALYX_ARGS is a string in quotes specifying experimental calyx args"
echo "ex) bash $0 \"-p simplify-if-comb -p dead-cell-removal -p dead-group-removal -p all\""
exit
fi

PASSES=$1

SCRIPT_DIR=$( cd $( dirname $0 ) && pwd )
SCRIPT_NAME=$( echo "$0" | rev | cut -d/ -f1 | rev )
CALYX_DIR=$( dirname $( dirname ${SCRIPT_DIR} ) )
OUT_DIR=${SCRIPT_DIR}/out
out=${OUT_DIR}/results.csv

if [ -d ${OUT_DIR} ]; then
echo "****Moving old results"
mv ${OUT_DIR} ${OUT_DIR}-`date +%Y-%m-%d-%H-%M-%S`
fi
mkdir -p ${OUT_DIR}

# rounding scheme
function round() {
echo $(printf %.$2f $(echo "scale=$2;(((10^$2)*$1)+0.5)/(10^$2)" | bc))
};

(
cd ${CALYX_DIR}
echo "name,og,exp,diff,diff(%)" > ${out}
py_args="20000 --keepgoing"
for f in $( cat ${SCRIPT_DIR}/queues-tests.txt ); do
name=$( basename "${f}" | cut -d. -f1 )
header=$( echo "${f}" | cut -d. -f1 )
echo ====${name}
original=${OUT_DIR}/${name}-original.json
opt=${OUT_DIR}/${name}-opt.json
# run with -p all
fud2 ${f} -o ${original} --to dat --through verilator -s sim.data=${header}.data -s py.args="${py_args}" -q
# run with specified passes
fud2 ${f} -o ${opt} --to dat --through verilator -s sim.data=${header}.data -s calyx.args="${PASSES}" -s py.args="${py_args}" -q
# TODO: maybe have something that throws a warning message if more than just the cycles are different?
original_num=$( grep cycles ${original} | rev | cut -d, -f2 | cut -d' ' -f1 | rev )
opt_num=$( grep cycles ${opt} | rev | cut -d, -f2 | cut -d' ' -f1 | rev )
diff=$( echo "${original_num} - ${opt_num}" | bc -l )
diff_percent=$( round $( echo "(${diff} / ${original_num}) * 100" | bc -l ) 2 )
echo "${name},${original_num},${opt_num},${diff},${diff_percent}" >> ${out}
done
)
14 changes: 14 additions & 0 deletions tools/compare-experimental-args/queues-tests.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
frontends/queues/tests/binheap/complex_tree_test.py
frontends/queues/tests/round_robin/rr_2flow_test.py
frontends/queues/tests/round_robin/rr_3flow_test.py
frontends/queues/tests/round_robin/rr_4flow_test.py
frontends/queues/tests/round_robin/rr_5flow_test.py
frontends/queues/tests/round_robin/rr_6flow_test.py
frontends/queues/tests/round_robin/rr_7flow_test.py
frontends/queues/tests/strict/strict_2flow_test.py
frontends/queues/tests/strict/strict_3flow_test.py
frontends/queues/tests/strict/strict_4flow_test.py
frontends/queues/tests/strict/strict_5flow_test.py
frontends/queues/tests/strict/strict_6flow_test.py
frontends/queues/tests/strict/strict_7flow_test.py
frontends/queues/tests/strict/strict_order_test.py
Loading