Skip to content

Commit

Permalink
[Arc] Add dominance-aware pass to sink ops and merge scf.if ops (#7702)
Browse files Browse the repository at this point in the history
Add the `MergeIfs` pass to the Arc dialect. This pass covers a handful
of control flow optimizations that are valuable to pick up after
`hw.module`s have been linearized and lowered into `arc.model` ops:

- It moves operations closer to their earliest user, if possible sinking
  them into blocks if all uses are nested in the same block.
- It merges adjacent `scf.if` operations with the same condition.
- It moves operations in between two `scf.if` operations ahead of the
  first if op to allow them to be merged.

The `MergeIfs` pass can operate on SSACFG regions. It assigns an integer
order to each operation and considers that order to determine up to
which point operations can be moved without moving beyond their first
use and without crossing interfering side-effecting ops. The pass is
aware of side-effects, and in particular uses the non-aliasing between
`arc.state` and `arc.memory` to track read/write side-effects at a
per-state level, which allows for fairly aggressive optimization. Other
side-effecting ops act as a hard barrier and will not be moved or moved
over.

This pass supersedes the very effective `GroupResetsAndEnables` pass
we have been using until now. The latter relies on the
`LegalizeStateUpdate` pass to run at a later point however, which will
be removed in a future PR, thus making this new pass necessary.

This is a preparatory step for a later PR that overhauls the LowerState
pass. That rewrite will make the `arc.clock_tree` and `arc.passthrough`
ops obsolete, which is why they are not present in the tests.
  • Loading branch information
fabianschuiki authored Oct 15, 2024
1 parent 5a6a561 commit 2085d0d
Show file tree
Hide file tree
Showing 8 changed files with 656 additions and 630 deletions.
1 change: 0 additions & 1 deletion include/circt/Dialect/Arc/ArcPasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ std::unique_ptr<mlir::Pass> createAllocateStatePass();
std::unique_ptr<mlir::Pass> createArcCanonicalizerPass();
std::unique_ptr<mlir::Pass> createDedupPass();
std::unique_ptr<mlir::Pass> createFindInitialVectorsPass();
std::unique_ptr<mlir::Pass> createGroupResetsAndEnablesPass();
std::unique_ptr<mlir::Pass>
createInferMemoriesPass(const InferMemoriesOptions &options = {});
std::unique_ptr<mlir::Pass> createInlineArcsPass();
Expand Down
32 changes: 25 additions & 7 deletions include/circt/Dialect/Arc/ArcPasses.td
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,6 @@ def FindInitialVectors : Pass<"arc-find-initial-vectors", "mlir::ModuleOp"> {
];
}

def GroupResetsAndEnables : Pass<"arc-group-resets-and-enables",
"mlir::ModuleOp"> {
let summary = "Group reset and enable conditions of lowered states";
let constructor = "circt::arc::createGroupResetsAndEnablesPass()";
let dependentDialects = ["arc::ArcDialect", "mlir::scf::SCFDialect"];
}

def InferMemories : Pass<"arc-infer-memories", "mlir::ModuleOp"> {
let summary = "Convert `FIRRTL_Memory` instances to dedicated memory ops";
let constructor = "circt::arc::createInferMemoriesPass()";
Expand Down Expand Up @@ -282,6 +275,31 @@ def MakeTables : Pass<"arc-make-tables", "mlir::ModuleOp"> {
let dependentDialects = ["arc::ArcDialect"];
}

def MergeIfsPass : Pass<"arc-merge-ifs"> {
let summary = "Merge control flow structures";
let description = [{
This pass optimizes control flow in a few ways. It moves operations closer
to their earliest user, if possible sinking them into blocks if all uses are
nested in the same block. It merges adjacent `scf.if` operations with the
same condition. And it moves operations in between two `scf.if` operations
ahead of the first if op to allow them to be merged. The pass runs on any
SSACFG regions nested under the operation it is applied to.

Note that this pass assumes that `!arc.state` and `!arc.memory` values can
never alias. That is, different values are assumed to never point to the
same storage location in simulation memory.
}];
let statistics = [
Statistic<"numOpsSunk", "sunk", "Ops sunk into blocks">,
Statistic<"numOpsMovedToUser", "moved-to-user", "Ops moved to first user">,
Statistic<"numIfsMerged", "ifs-merged", "Adjacent scf.if ops merged">,
Statistic<"numOpsMovedFromBetweenIfs", "moved-from-between-ifs",
"Ops moved from between ifs to enable merging">,
Statistic<"numIterations", "iterations",
"Number of iterations until no more ops were sunk/merged">,
];
}

def MuxToControlFlow : Pass<"arc-mux-to-control-flow", "mlir::ModuleOp"> {
let summary = "Convert muxes with large independent fan-ins to if-statements";
let constructor = "circt::arc::createMuxToControlFlowPass()";
Expand Down
2 changes: 1 addition & 1 deletion lib/Dialect/Arc/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ add_circt_dialect_library(CIRCTArcTransforms
ArcCanonicalizer.cpp
Dedup.cpp
FindInitialVectors.cpp
GroupResetsAndEnables.cpp
InferMemories.cpp
InferStateProperties.cpp
InlineArcs.cpp
Expand All @@ -17,6 +16,7 @@ add_circt_dialect_library(CIRCTArcTransforms
LowerState.cpp
LowerVectorizations.cpp
MakeTables.cpp
MergeIfs.cpp
MuxToControlFlow.cpp
PrintCostModel.cpp
SimplifyVariadicOps.cpp
Expand Down
224 changes: 0 additions & 224 deletions lib/Dialect/Arc/Transforms/GroupResetsAndEnables.cpp

This file was deleted.

Loading

0 comments on commit 2085d0d

Please sign in to comment.