Skip to content

Conversation

@ayakayorihiro
Copy link
Contributor

@ayakayorihiro ayakayorihiro commented Dec 3, 2025

This PR contains:

  • A new experimental pass simplify-if-comb to address the cycle inefficiency of if with comb groups (Cycle inefficiency of if with comb group #2595).
  • A simple bash script (compare-experimental-args.sh) that compares cycle counts differences between running Calyx with default arguments vs new experimental arguments

simplify-if-comb

This pass transforms if with combinational groups. It replaces the combinational group with a series of conditional assignments. The pass creates a new cell for any cell being written to in an assignment in the combinational group. For example, the code snippet

wires { ...
  comb group cond {
    lt.left = counter.out;
    lt.right = 32'd10;
  }
}
control {
  if lt.out with cond {
      my_group;
   }
}

gets converted into:

wires { ...
  // continuous assignments
  lt0.left = counter.out; // lt0 is a clone of lt
  lt0.right = 32'd10;
}
control {
  if lt0.out {
      my_group;
   }
}

Cycle count effects

Comparing this pass with Calyx's default compilation flow on the queues programs (using compare-experimental-args described below), we found maximum of 17.85% cycle reduction!
image

Next steps

This pass is currently experimental (not used in any of the default pass aliases) because we don't know its effects on area and critical path. Our guess is that area and critical path will be negatively affected, since we are creating new cells and adding continuous assignments, but we need to actually run some experiments before deciding whether to add this pass to default compilation!

compare-experimental-args

This script compares cycle counts between running Calyx with default arguments and running Calyx with new, experimental arguments. The motivation for this script was to compare the cycle count effects of simplify-if-comb. It (currently) runs a subset of the queues tests listed in queues-tests.txt.

Usage

Note: This script assumes that you have fud2 set up and Verilator installed.

From the base Calyx directory (it's not necessary to run from this directory):

bash tools/compare-experimental-args/compare-experimental-args.sh <EXP_ARGS>

where <EXP_ARGS> should be a string with quotation marks around any new arguments

ex)

bash tools/compare-experimental-args/compare-experimental-args.sh "-p simplify-if-comb -p dead-cell-removal -p dead-group-removal -p all"

The output of the script is the out directory, which contains a JSON result file for each file and each configuration, a results.csv that shows the cycle reduction between the original Calyx compilation (og) and the experimental arguments (exp).

Next steps

Some things we may want to add to this script:

  • We may want to check whether the outputs (besides the cycle count) match, and report when outputs were not equal in case the experimental arguments produced incorrect results.
  • Ability to provide a user-specified test suite
  • Result statistics?

@ayakayorihiro ayakayorihiro self-assigned this Dec 3, 2025
@ayakayorihiro ayakayorihiro added the C: calyx-opt Optimization or analysis pass label Dec 3, 2025
@rachitnigam
Copy link
Contributor

This is awesome @ayakayorihiro! I particularly love the very rigorous benchmarking and analysis!

Copy link
Collaborator

@EclecticGriffin EclecticGriffin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me! My only floating thought is that I don't know if it is fully necessary to call rewrite_control on the entire block, since the only thing we actually are trying to rewrite is the condition port. Anything else within the if block shouldn't be referencing anything inside the with comb group, so such programs are already exhibiting bad behavior and we needn't worry about preservation of their already ambiguous semantics

&cond_group_asgn.dst.borrow().parent
{
let c_ref = c.upgrade();
let c_name = c_ref.borrow().name();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Random note, if you want to remove a layer of indentation, you could use a
let-else with an early return rather than an if-let

        let Some(cond_group_ref) = &s.cond else {
            return Ok(Action::Continue);
        };

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some cursed reason this comment ended up on the wrong line. As the code hopefully makes clear, this was supposed to be about line 72

..Default::default()
};
// move all assignments in cond group to continuous and rewrite cells
for cond_group_asgn in &cond_group_ref.borrow_mut().assignments {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this needs to be borrow_mut since you only clone the assignment

Comment on lines +110 to +116
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);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgive me if this is a misunderstanding of how the visitor system works, but
given that we're just replacing the current if block with a near clone, wouldn't
it make more sense to mutate the if directly? You would just need to remove the
cond and do whatever (if any?) rewriting is necessary

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C: calyx-opt Optimization or analysis pass

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants