Skip to content

Commit

Permalink
[Arc] Use seq.clock_gate op (#6501)
Browse files Browse the repository at this point in the history
The arc dialect currently provides its own `arc.clock_gate` operation.
Since the seq dialect has a proper `seq.clock_gate` now, switch over to
that and remove custom arc op.

Fixes #6500.
  • Loading branch information
fabianschuiki authored Dec 8, 2023
1 parent 7910a1e commit 5838a9e
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 26 deletions.
9 changes: 0 additions & 9 deletions include/circt/Dialect/Arc/ArcOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -260,15 +260,6 @@ def CallOp : ArcOp<"call", [
}];
}

def ClockGateOp : ArcOp<"clock_gate", [Pure]> {
let summary = "Clock gate";
let arguments = (ins ClockType:$input, I1:$enable);
let results = (outs ClockType:$output);
let assemblyFormat = [{
$input `,` $enable attr-dict
}];
}

def MemoryOp : ArcOp<"memory", [MemoryEffects<[MemAlloc]>]> {
let summary = "Memory";
let results = (outs MemoryType:$memory);
Expand Down
4 changes: 2 additions & 2 deletions lib/Conversion/ArcToLLVM/LowerArcToLLVM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,10 @@ struct MemoryWriteOpLowering : public OpConversionPattern<arc::MemoryWriteOp> {
};

/// A dummy lowering for clock gates to an AND gate.
struct ClockGateOpLowering : public OpConversionPattern<arc::ClockGateOp> {
struct ClockGateOpLowering : public OpConversionPattern<seq::ClockGateOp> {
using OpConversionPattern::OpConversionPattern;
LogicalResult
matchAndRewrite(arc::ClockGateOp op, OpAdaptor adaptor,
matchAndRewrite(seq::ClockGateOp op, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const final {
rewriter.replaceOpWithNewOp<comb::AndOp>(op, adaptor.getInput(),
adaptor.getEnable(), true);
Expand Down
4 changes: 2 additions & 2 deletions lib/Conversion/ConvertToArcs/ConvertToArcs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ using llvm::MapVector;

static bool isArcBreakingOp(Operation *op) {
return op->hasTrait<OpTrait::ConstantLike>() ||
isa<hw::InstanceOp, seq::CompRegOp, ClockGateOp, MemoryOp,
ClockedOpInterface>(op) ||
isa<hw::InstanceOp, seq::CompRegOp, MemoryOp, ClockedOpInterface,
seq::ClockGateOp>(op) ||
op->getNumResults() > 1;
}

Expand Down
26 changes: 23 additions & 3 deletions lib/Dialect/Arc/Transforms/LowerState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ struct ClockLowering {
IRMapping materializedValues;
/// A cache of AND gates created for aggregating enable conditions.
DenseMap<std::pair<Value, Value>, Value> andCache;
/// A cache of OR gates created for aggregating enable conditions.
DenseMap<std::pair<Value, Value>, Value> orCache;

ClockLowering(Value clock, Operation *treeOp, Statistics &stats)
: clock(clock), treeOp(treeOp), stats(stats), builder(treeOp) {
Expand All @@ -81,6 +83,7 @@ struct ClockLowering {

Value materializeValue(Value value);
Value getOrCreateAnd(Value lhs, Value rhs, Location loc);
Value getOrCreateOr(Value lhs, Value rhs, Location loc);
};

struct GatedClockLowering {
Expand Down Expand Up @@ -236,13 +239,27 @@ Value ClockLowering::getOrCreateAnd(Value lhs, Value rhs, Location loc) {
return slot;
}

/// Create an OR gate if none with the given operands already exists. Note that
/// the operands may be null, in which case the function will return the
/// non-null operand, or null if both operands are null.
Value ClockLowering::getOrCreateOr(Value lhs, Value rhs, Location loc) {
if (!lhs)
return rhs;
if (!rhs)
return lhs;
auto &slot = orCache[std::make_pair(lhs, rhs)];
if (!slot)
slot = builder.create<comb::OrOp>(loc, lhs, rhs);
return slot;
}

//===----------------------------------------------------------------------===//
// Module Lowering
//===----------------------------------------------------------------------===//

GatedClockLowering ModuleLowering::getOrCreateClockLowering(Value clock) {
// Look through clock gates.
if (auto ckgOp = clock.getDefiningOp<ClockGateOp>()) {
if (auto ckgOp = clock.getDefiningOp<seq::ClockGateOp>()) {
// Reuse the existing lowering for this clock gate if possible.
if (auto it = gatedClockLowerings.find(clock);
it != gatedClockLowerings.end())
Expand All @@ -254,8 +271,11 @@ GatedClockLowering ModuleLowering::getOrCreateClockLowering(Value clock) {
// we have to do is to add this clock gate's condition to that list.
auto info = getOrCreateClockLowering(ckgOp.getInput());
auto ckgEnable = info.clock.materializeValue(ckgOp.getEnable());
info.enable =
info.clock.getOrCreateAnd(info.enable, ckgEnable, ckgOp.getLoc());
auto ckgTestEnable = info.clock.materializeValue(ckgOp.getTestEnable());
info.enable = info.clock.getOrCreateAnd(
info.enable,
info.clock.getOrCreateOr(ckgEnable, ckgTestEnable, ckgOp.getLoc()),
ckgOp.getLoc());
gatedClockLowerings.insert({clock, info});
return info;
}
Expand Down
11 changes: 5 additions & 6 deletions lib/Dialect/Arc/Transforms/StripSV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,16 +158,15 @@ void StripSVPass::runOnOperation() {
continue;
}

// Replace clock gate instances with the dedicated arc op and stub
// out other external modules.
// Replace clock gate instances with the dedicated `seq.clock_gate` op and
// stub out other external modules.
if (auto instOp = dyn_cast<hw::InstanceOp>(&op)) {
auto modName = instOp.getModuleNameAttr().getAttr();
ImplicitLocOpBuilder builder(instOp.getLoc(), instOp);
if (clockGateModuleNames.contains(modName)) {
auto enable = builder.createOrFold<comb::OrOp>(
instOp.getOperand(1), instOp.getOperand(2), true);
auto gated =
builder.create<arc::ClockGateOp>(instOp.getOperand(0), enable);
auto gated = builder.create<seq::ClockGateOp>(
instOp.getOperand(0), instOp.getOperand(1), instOp.getOperand(2),
hw::InnerSymAttr{});
instOp.replaceAllUsesWith(gated);
opsToDelete.push_back(instOp);
}
Expand Down
11 changes: 7 additions & 4 deletions test/Dialect/Arc/lower-state.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,16 @@ hw.module @InputsAndOutputs(in %a: i42, in %b: i17, out c: i42, out d: i17) {
}

// CHECK-LABEL: arc.model "State" {
hw.module @State(in %clk: !seq.clock, in %en: i1) {
%gclk = arc.clock_gate %clk, %en
hw.module @State(in %clk: !seq.clock, in %en: i1, in %en2: i1) {
%gclk = seq.clock_gate %clk, %en, %en2
%3 = arc.state @DummyArc(%6) clock %clk lat 1 : (i42) -> i42
%4 = arc.state @DummyArc(%5) clock %gclk lat 1 : (i42) -> i42
%5 = comb.add %3, %3 : i42
%6 = comb.add %4, %4 : i42
// CHECK-NEXT: (%arg0: !arc.storage):
// CHECK-NEXT: [[INCLK:%.+]] = arc.root_input "clk", %arg0 : (!arc.storage) -> !arc.state<i1>
// CHECK-NEXT: [[INEN:%.+]] = arc.root_input "en", %arg0 : (!arc.storage) -> !arc.state<i1>
// CHECK-NEXT: [[INEN2:%.+]] = arc.root_input "en2", %arg0 : (!arc.storage) -> !arc.state<i1>
// CHECK-NEXT: [[CLK_OLD:%.+]] = arc.alloc_state %arg0 : (!arc.storage) -> !arc.state<i1>
// CHECK-NEXT: [[S0:%.+]] = arc.alloc_state %arg0 : (!arc.storage) -> !arc.state<i42>
// CHECK-NEXT: [[S1:%.+]] = arc.alloc_state %arg0 : (!arc.storage) -> !arc.state<i42>
Expand All @@ -52,11 +53,13 @@ hw.module @State(in %clk: !seq.clock, in %en: i1) {
// CHECK-NEXT: [[TMP1:%.+]] = comb.add [[TMP0]], [[TMP0]]
// CHECK-NEXT: [[TMP2:%.+]] = arc.state @DummyArc([[TMP1]]) lat 0 : (i42) -> i42
// CHECK-NEXT: arc.state_write [[S0]] = [[TMP2]] : <i42>
// CHECK-NEXT: [[EN:%.+]] = arc.state_read [[INEN]] : <i1>
// CHECK-NEXT: [[EN2:%.+]] = arc.state_read [[INEN2]] : <i1>
// CHECK-NEXT: [[TMP3:%.+]] = comb.or [[EN]], [[EN2]] : i1
// CHECK-NEXT: [[TMP0:%.+]] = arc.state_read [[S0]] : <i42>
// CHECK-NEXT: [[TMP1:%.+]] = comb.add [[TMP0]], [[TMP0]]
// CHECK-NEXT: [[TMP2:%.+]] = arc.state @DummyArc([[TMP1]]) lat 0 : (i42) -> i42
// CHECK-NEXT: [[EN:%.+]] = arc.state_read [[INEN]] : <i1>
// CHECK-NEXT: arc.state_write [[S1]] = [[TMP2]] if [[EN]] : <i42>
// CHECK-NEXT: arc.state_write [[S1]] = [[TMP2]] if [[TMP3]] : <i42>
// CHECK-NEXT: }
}

Expand Down

0 comments on commit 5838a9e

Please sign in to comment.