Skip to content

Commit 2085d0d

Browse files
[Arc] Add dominance-aware pass to sink ops and merge scf.if ops (#7702)
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.
1 parent 5a6a561 commit 2085d0d

File tree

8 files changed

+656
-630
lines changed

8 files changed

+656
-630
lines changed

include/circt/Dialect/Arc/ArcPasses.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ std::unique_ptr<mlir::Pass> createAllocateStatePass();
3131
std::unique_ptr<mlir::Pass> createArcCanonicalizerPass();
3232
std::unique_ptr<mlir::Pass> createDedupPass();
3333
std::unique_ptr<mlir::Pass> createFindInitialVectorsPass();
34-
std::unique_ptr<mlir::Pass> createGroupResetsAndEnablesPass();
3534
std::unique_ptr<mlir::Pass>
3635
createInferMemoriesPass(const InferMemoriesOptions &options = {});
3736
std::unique_ptr<mlir::Pass> createInlineArcsPass();

include/circt/Dialect/Arc/ArcPasses.td

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,6 @@ def FindInitialVectors : Pass<"arc-find-initial-vectors", "mlir::ModuleOp"> {
9292
];
9393
}
9494

95-
def GroupResetsAndEnables : Pass<"arc-group-resets-and-enables",
96-
"mlir::ModuleOp"> {
97-
let summary = "Group reset and enable conditions of lowered states";
98-
let constructor = "circt::arc::createGroupResetsAndEnablesPass()";
99-
let dependentDialects = ["arc::ArcDialect", "mlir::scf::SCFDialect"];
100-
}
101-
10295
def InferMemories : Pass<"arc-infer-memories", "mlir::ModuleOp"> {
10396
let summary = "Convert `FIRRTL_Memory` instances to dedicated memory ops";
10497
let constructor = "circt::arc::createInferMemoriesPass()";
@@ -282,6 +275,31 @@ def MakeTables : Pass<"arc-make-tables", "mlir::ModuleOp"> {
282275
let dependentDialects = ["arc::ArcDialect"];
283276
}
284277

278+
def MergeIfsPass : Pass<"arc-merge-ifs"> {
279+
let summary = "Merge control flow structures";
280+
let description = [{
281+
This pass optimizes control flow in a few ways. It moves operations closer
282+
to their earliest user, if possible sinking them into blocks if all uses are
283+
nested in the same block. It merges adjacent `scf.if` operations with the
284+
same condition. And it moves operations in between two `scf.if` operations
285+
ahead of the first if op to allow them to be merged. The pass runs on any
286+
SSACFG regions nested under the operation it is applied to.
287+
288+
Note that this pass assumes that `!arc.state` and `!arc.memory` values can
289+
never alias. That is, different values are assumed to never point to the
290+
same storage location in simulation memory.
291+
}];
292+
let statistics = [
293+
Statistic<"numOpsSunk", "sunk", "Ops sunk into blocks">,
294+
Statistic<"numOpsMovedToUser", "moved-to-user", "Ops moved to first user">,
295+
Statistic<"numIfsMerged", "ifs-merged", "Adjacent scf.if ops merged">,
296+
Statistic<"numOpsMovedFromBetweenIfs", "moved-from-between-ifs",
297+
"Ops moved from between ifs to enable merging">,
298+
Statistic<"numIterations", "iterations",
299+
"Number of iterations until no more ops were sunk/merged">,
300+
];
301+
}
302+
285303
def MuxToControlFlow : Pass<"arc-mux-to-control-flow", "mlir::ModuleOp"> {
286304
let summary = "Convert muxes with large independent fan-ins to if-statements";
287305
let constructor = "circt::arc::createMuxToControlFlowPass()";

lib/Dialect/Arc/Transforms/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ add_circt_dialect_library(CIRCTArcTransforms
44
ArcCanonicalizer.cpp
55
Dedup.cpp
66
FindInitialVectors.cpp
7-
GroupResetsAndEnables.cpp
87
InferMemories.cpp
98
InferStateProperties.cpp
109
InlineArcs.cpp
@@ -17,6 +16,7 @@ add_circt_dialect_library(CIRCTArcTransforms
1716
LowerState.cpp
1817
LowerVectorizations.cpp
1918
MakeTables.cpp
19+
MergeIfs.cpp
2020
MuxToControlFlow.cpp
2121
PrintCostModel.cpp
2222
SimplifyVariadicOps.cpp

lib/Dialect/Arc/Transforms/GroupResetsAndEnables.cpp

Lines changed: 0 additions & 224 deletions
This file was deleted.

0 commit comments

Comments
 (0)