Skip to content

Commit

Permalink
[Arc] Hoist reset value in CompReg when lowering for simulation (#6972)
Browse files Browse the repository at this point in the history
Arcilator currently does not support non-zero reset values for compreg. This change canonicalizes reset values to a mux on the input, as it currently makes no difference for simulation purposes, and sidesteps the reset value limitations.
  • Loading branch information
Moxinilian committed May 2, 2024
1 parent 8e36cea commit 523d6fd
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 1 deletion.
32 changes: 31 additions & 1 deletion lib/Dialect/Arc/Transforms/ArcCanonicalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "circt/Dialect/Arc/ArcPasses.h"
#include "circt/Dialect/Comb/CombOps.h"
#include "circt/Dialect/HW/HWOps.h"
#include "circt/Dialect/Seq/SeqOps.h"
#include "circt/Support/Namespace.h"
#include "circt/Support/SymCache.h"
#include "mlir/IR/Matchers.h"
Expand Down Expand Up @@ -240,6 +241,12 @@ struct ICMPCanonicalizer : public OpRewritePattern<comb::ICmpOp> {
PatternRewriter &rewriter) const final;
};

struct CompRegCanonicalizer : public OpRewritePattern<seq::CompRegOp> {
using OpRewritePattern::OpRewritePattern;
LogicalResult matchAndRewrite(seq::CompRegOp op,
PatternRewriter &rewriter) const final;
};

struct RemoveUnusedArcArgumentsPattern : public SymOpRewritePattern<DefineOp> {
using SymOpRewritePattern::SymOpRewritePattern;
LogicalResult matchAndRewrite(DefineOp op,
Expand Down Expand Up @@ -547,6 +554,29 @@ SinkArcInputsPattern::matchAndRewrite(DefineOp op,
return success(toDelete.any());
}

LogicalResult
CompRegCanonicalizer::matchAndRewrite(seq::CompRegOp op,
PatternRewriter &rewriter) const {
if (!op.getReset())
return failure();

// Because Arcilator supports constant zero reset values, skip them.
APInt constant;
if (mlir::matchPattern(op.getResetValue(), mlir::m_ConstantInt(&constant)))
if (constant.isZero())
return failure();

Value newInput = rewriter.create<comb::MuxOp>(
op->getLoc(), op.getReset(), op.getResetValue(), op.getInput());
rewriter.modifyOpInPlace(op, [&]() {
op.getInputMutable().set(newInput);
op.getResetMutable().clear();
op.getResetValueMutable().clear();
});

return success();
}

//===----------------------------------------------------------------------===//
// ArcCanonicalizerPass implementation
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -594,7 +624,7 @@ void ArcCanonicalizerPass::runOnOperation() {
dialect->getCanonicalizationPatterns(patterns);
for (mlir::RegisteredOperationName op : ctxt.getRegisteredOperations())
op.getCanonicalizationPatterns(patterns, &ctxt);
patterns.add<ICMPCanonicalizer>(&getContext());
patterns.add<ICMPCanonicalizer, CompRegCanonicalizer>(&getContext());

// Don't test for convergence since it is often not reached.
(void)mlir::applyPatternsAndFoldGreedily(getOperation(), std::move(patterns),
Expand Down
28 changes: 28 additions & 0 deletions test/Dialect/Arc/arc-canonicalizer.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,34 @@ hw.module @icmpNeCanonicalizer(in %arg0: i1, in %arg1: i1, in %arg2: i1, in %arg
hw.output %1, %3, %5, %7 : i1, i1, i1, i1
}

//===----------------------------------------------------------------------===//
// CompRegCanonicalizer
//===----------------------------------------------------------------------===//

// CHECK-LABEL: hw.module @HoistCompRegReset
// CHECK-SAME: in %[[CLOCK:[^ ]*]] : !seq.clock, in %[[INPUT:[^ ]*]] : i32, in %[[RESET:[^ ]*]] : i1, in %[[RESET_VALUE:[^ ]*]] : i32
hw.module @HoistCompRegReset(in %clock: !seq.clock, in %input: i32, in %reset: i1, in %resetValue: i32, out out: i32) {
// CHECK: %[[NEW_INPUT:.*]] = comb.mux %[[RESET]], %[[RESET_VALUE]], %[[INPUT]] : i32
// CHECK: %[[REG:.*]] = seq.compreg %[[NEW_INPUT]], %[[CLOCK]] : i32
%reg = seq.compreg %input, %clock reset %reset, %resetValue : i32

// CHECK: hw.output %[[REG]] : i32
hw.output %reg : i32
}

// CHECK-LABEL: hw.module @NoHoistCompRegZeroResetValue
// CHECK-SAME: in %[[CLOCK:[^ ]*]] : !seq.clock, in %[[INPUT:[^ ]*]] : i32, in %[[RESET:[^ ]*]] : i1
hw.module @NoHoistCompRegZeroResetValue(in %clock: !seq.clock, in %input: i32, in %reset: i1, out out: i32) {
// CHECK: %[[ZERO:.*]] = hw.constant 0 : i32
%zero = hw.constant 0 : i32

// CHECK: %[[REG:.*]] = seq.compreg %[[INPUT]], %[[CLOCK]] reset %[[RESET]], %[[ZERO]] : i32
%reg = seq.compreg %input, %clock reset %reset, %zero : i32

// CHECK: hw.output %[[REG]] : i32
hw.output %reg : i32
}

//===----------------------------------------------------------------------===//
// RemoveUnusedArcArguments
//===----------------------------------------------------------------------===//
Expand Down
9 changes: 9 additions & 0 deletions test/arcilator/compreg.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: arcilator %s

// This test ensures that the pipeline completes, without checking the result.
// This is to make sure compatibility for some constructs does not regress.

hw.module @arbitrary_reset_value(in %value: i32, in %clock: !seq.clock, in %reset: i1, in %resetValue: i32, out out: i32) {
%reg = seq.compreg %value, %clock reset %reset, %resetValue : i32
hw.output %reg : i32
}

0 comments on commit 523d6fd

Please sign in to comment.