[AlwaysFusion] Fix merging in the presence of top-level #ifdefs.

This changes the pass to do a post-order walk of the region tree, in
preparation for other changes.
This commit is contained in:
Chris Lattner 2021-02-20 21:40:36 -08:00
parent 334798e4a2
commit 20b04d2369
2 changed files with 56 additions and 21 deletions

View File

@ -83,39 +83,52 @@ static void mergeOperations(Operation *op1, Operation *op2) {
namespace {
struct AlwaysFusionPass : public AlwaysFusionBase<AlwaysFusionPass> {
void runOnOperation() override;
void runOnRegionBlock(Block &body);
private:
bool anythingChanged;
};
} // end anonymous namespace
void AlwaysFusionPass::runOnOperation() {
auto *moduleBody = getOperation().getBodyBlock();
// Keeps track if anything changed during this pass, used to determine if
// the analyses were preserved.
bool graphChanged = false;
// A set of operations in the current block which are mergable. Any
// operation in this set is a candidate for another similar operation to
// merge in to.
DenseSet<Operation *, SimpleOperationInfo> foundOps;
for (sv::AlwaysFFOp alwaysOp :
llvm::make_early_inc_range(moduleBody->getOps<sv::AlwaysFFOp>())) {
// Check if we have encountered an equivalent operation already. If we
// have, merge them together and delete the old operation.
auto itAndInserted = foundOps.insert(alwaysOp);
if (!itAndInserted.second) {
// Merge with a similar alwaysff
mergeOperations(*itAndInserted.first, alwaysOp);
alwaysOp.erase();
graphChanged = true;
}
}
anythingChanged = false;
runOnRegionBlock(*getOperation().getBodyBlock());
// If we did not change anything in the graph mark all analysis as
// preserved.
if (!graphChanged)
if (!anythingChanged)
markAllAnalysesPreserved();
}
void AlwaysFusionPass::runOnRegionBlock(Block &body) {
// A set of operations in the current block which are mergable. Any
// operation in this set is a candidate for another similar operation to
// merge in to.
DenseSet<Operation *, SimpleOperationInfo> alwaysFFOpsSeen;
for (Operation &op : llvm::make_early_inc_range(body)) {
// Recursively process any regions in the op before we visit it.
for (size_t i = 0, e = op.getNumRegions(); i != e; ++i) {
if (op.getRegion(i).getBlocks().size() == 1)
runOnRegionBlock(op.getRegion(i).front());
}
if (auto alwaysOp = dyn_cast<sv::AlwaysFFOp>(op)) {
// Check if we have encountered an equivalent operation already. If we
// have, merge them together and delete the old operation.
auto itAndInserted = alwaysFFOpsSeen.insert(alwaysOp);
if (!itAndInserted.second) {
// Merge with a similar alwaysff if we already have one.
mergeOperations(*itAndInserted.first, alwaysOp);
alwaysOp.erase();
anythingChanged = true;
}
}
}
}
std::unique_ptr<Pass> circt::sv::createAlwaysFusionPass() {
return std::make_unique<AlwaysFusionPass>();
}

View File

@ -97,3 +97,25 @@ rtl.module @alwaysff_different_reset(%arg0: i1, %arg1: i1) {
}
rtl.output
}
//CHECK-LABEL: rtl.module @alwaysff_ifdef(%arg0: i1) {
//CHECK-NEXT: sv.ifdef "FOO" {
//CHECK-NEXT: sv.alwaysff(posedge %arg0) {
//CHECK-NEXT: sv.fwrite "A1"
//CHECK-NEXT: sv.fwrite "B1"
//CHECK-NEXT: }
//CHECK-NEXT: }
//CHECK-NEXT: rtl.output
//CHECK-NEXT: }
rtl.module @alwaysff_ifdef(%arg0: i1) {
sv.ifdef "FOO" {
sv.alwaysff(posedge %arg0) {
sv.fwrite "A1"
}
sv.alwaysff(posedge %arg0) {
sv.fwrite "B1"
}
}
rtl.output
}