Skip to content

Commit

Permalink
[HandshakeToDC] Add clock and reset ports (#7825)
Browse files Browse the repository at this point in the history
After the lowering, add clock and reset ports (with the required
attributes) to all of the created modules.
  • Loading branch information
teqdruid authored Nov 19, 2024
1 parent a637d5b commit feae186
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 22 deletions.
49 changes: 43 additions & 6 deletions lib/Conversion/HandshakeToDC/HandshakeToDC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -651,9 +651,9 @@ static hw::ModulePortInfo getModulePortInfoHS(const TypeConverter &tc,
return hw::ModulePortInfo{inputs, outputs};
}

class FuncOpConversion : public OpConversionPattern<handshake::FuncOp> {
class FuncOpConversion : public DCOpConversionPattern<handshake::FuncOp> {
public:
using OpConversionPattern<handshake::FuncOp>::OpConversionPattern;
using DCOpConversionPattern<handshake::FuncOp>::DCOpConversionPattern;
using OpAdaptor = typename handshake::FuncOp::Adaptor;

// Replaces a handshake.func with a hw.module, converting the argument and
Expand All @@ -668,8 +668,9 @@ class FuncOpConversion : public OpConversionPattern<handshake::FuncOp> {
ModulePortInfo ports = getModulePortInfoHS(*getTypeConverter(), op);

if (op.isExternal()) {
rewriter.create<hw::HWModuleExternOp>(
auto mod = rewriter.create<hw::HWModuleExternOp>(
op.getLoc(), rewriter.getStringAttr(op.getName()), ports);
convertedOps->insert(mod);
} else {
auto hwModule = rewriter.create<hw::HWModuleOp>(
op.getLoc(), rewriter.getStringAttr(op.getName()), ports);
Expand All @@ -683,13 +684,40 @@ class FuncOpConversion : public OpConversionPattern<handshake::FuncOp> {
(void)getTypeConverter()->convertSignatureArgs(
TypeRange(moduleRegion.getArgumentTypes()), result);
rewriter.applySignatureConversion(hwModule.getBodyBlock(), result);
convertedOps->insert(hwModule);
}

rewriter.eraseOp(op);
return success();
}
};

/// Add DC clock and reset ports to the module.
static void addClkRst(hw::HWModuleOp mod) {
auto *ctx = mod.getContext();

size_t numInputs = mod.getNumInputPorts();
mod.insertInput(numInputs, "clk", seq::ClockType::get(ctx));
mod.setPortAttrs(
numInputs,
DictionaryAttr::get(ctx, {NamedAttribute(StringAttr::get(ctx, "dc.clock"),
UnitAttr::get(ctx))}));
mod.insertInput(numInputs + 1, "rst", IntegerType::get(ctx, 1));
mod.setPortAttrs(
numInputs + 1,
DictionaryAttr::get(ctx, {NamedAttribute(StringAttr::get(ctx, "dc.reset"),
UnitAttr::get(ctx))}));

// We must initialize any port attributes that are not set otherwise the
// verifier will fail.
for (size_t portNum = 0, e = mod.getNumPorts(); portNum < e; ++portNum) {
auto attrs = dyn_cast_or_null<DictionaryAttr>(mod.getPortAttrs(portNum));
if (attrs)
continue;
mod.setPortAttrs(portNum, DictionaryAttr::get(ctx, {}));
}
}

class HandshakeToDCPass
: public circt::impl::HandshakeToDCBase<HandshakeToDCPass> {
public:
Expand All @@ -702,8 +730,9 @@ class HandshakeToDCPass
auto patternBuilder = [&](TypeConverter &typeConverter,
handshaketodc::ConvertedOps &convertedOps,
RewritePatternSet &patterns) {
patterns.add<FuncOpConversion, ReturnOpConversion>(typeConverter,
mod.getContext());
patterns.add<FuncOpConversion>(mod.getContext(), typeConverter,
&convertedOps);
patterns.add<ReturnOpConversion>(typeConverter, mod.getContext());
};

LogicalResult res = runHandshakeToDC(mod, patternBuilder, targetModifier);
Expand Down Expand Up @@ -774,5 +803,13 @@ LogicalResult circt::handshaketodc::runHandshakeToDC(

// Build any user-specified patterns
patternBuilder(typeConverter, convertedOps, patterns);
return applyPartialConversion(op, target, std::move(patterns));
if (failed(applyPartialConversion(op, target, std::move(patterns))))
return failure();

// Add clock and reset ports to each converted module.
for (auto &op : convertedOps)
if (auto mod = dyn_cast<hw::HWModuleOp>(op); mod)
addClkRst(mod);

return success();
}
32 changes: 16 additions & 16 deletions test/Conversion/HandshakeToDC/basic.mlir
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: circt-opt %s --lower-handshake-to-dc | FileCheck %s

// CHECK: hw.module @test_fork(in %[[VAL_0:.*]] : !dc.token, out out0 : !dc.token, out out1 : !dc.token) {
// CHECK: hw.module @test_fork(in %[[VAL_0:.*]] : !dc.token, in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.token, out out1 : !dc.token) {
// CHECK: %[[VAL_1:.*]]:2 = dc.fork [2] %[[VAL_0]]
// CHECK: hw.output %[[VAL_1]]#0, %[[VAL_1]]#1 : !dc.token, !dc.token
// CHECK: }
Expand All @@ -9,7 +9,7 @@ handshake.func @test_fork(%arg0: none) -> (none, none) {
return %0#0, %0#1 : none, none
}

// CHECK: hw.module @test_fork_data(in %[[VAL_0:.*]] : !dc.value<i32>, out out0 : !dc.value<i32>) {
// CHECK: hw.module @test_fork_data(in %[[VAL_0:.*]] : !dc.value<i32>, in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.value<i32>) {
// CHECK: %[[VAL_1:.*]], %[[VAL_2:.*]] = dc.unpack %[[VAL_0]] : !dc.value<i32>
// CHECK: %[[VAL_3:.*]]:2 = dc.fork [2] %[[VAL_1]]
// CHECK: %[[VAL_4:.*]] = dc.pack %[[VAL_3]]#0, %[[VAL_2]] : i32
Expand All @@ -27,7 +27,7 @@ handshake.func @test_fork_data(%arg0: i32) -> (i32) {
return %1 : i32
}

// CHECK: hw.module @top(in %[[VAL_0:.*]] : !dc.value<i64>, in %[[VAL_1:.*]] : !dc.value<i64>, in %[[VAL_2:.*]] : !dc.token, out out0 : !dc.value<i64>, out out1 : !dc.token) {
// CHECK: hw.module @top(in %[[VAL_0:.*]] : !dc.value<i64>, in %[[VAL_1:.*]] : !dc.value<i64>, in %[[VAL_2:.*]] : !dc.token, in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.value<i64>, out out1 : !dc.token) {
// CHECK: %[[VAL_3:.*]], %[[VAL_4:.*]] = dc.unpack %[[VAL_0]] : !dc.value<i64>
// CHECK: %[[VAL_5:.*]], %[[VAL_6:.*]] = dc.unpack %[[VAL_1]] : !dc.value<i64>
// CHECK: %[[VAL_7:.*]] = dc.join %[[VAL_3]], %[[VAL_5]]
Expand All @@ -47,7 +47,7 @@ handshake.func @top(%arg0: i64, %arg1: i64, %arg8: none, ...) -> (i64, none) {
return %1, %arg8 : i64, none
}

// CHECK-LABEL: hw.module @constant(out out0 : !dc.value<i32>) {
// CHECK-LABEL: hw.module @constant(in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.value<i32>) {
// CHECK: %[[VAL_1:.*]] = dc.source
// CHECK: %[[VAL_2:.*]] = arith.constant 42 : i32
// CHECK: %[[VAL_3:.*]] = dc.pack %[[VAL_1]], %[[VAL_2]] : i32
Expand All @@ -58,7 +58,7 @@ handshake.func @constant() -> (i32) {
return %0 : i32
}

// CHECK: hw.module @mux(in %[[VAL_0:.*]] : !dc.value<i1>, in %[[VAL_1:.*]] : !dc.value<i64>, in %[[VAL_2:.*]] : !dc.value<i64>, out out0 : !dc.value<i64>) {
// CHECK: hw.module @mux(in %[[VAL_0:.*]] : !dc.value<i1>, in %[[VAL_1:.*]] : !dc.value<i64>, in %[[VAL_2:.*]] : !dc.value<i64>, in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.value<i64>) {
// CHECK: %[[VAL_3:.*]], %[[VAL_4:.*]] = dc.unpack %[[VAL_0]] : !dc.value<i1>
// CHECK: %[[VAL_5:.*]], %[[VAL_6:.*]] = dc.unpack %[[VAL_1]] : !dc.value<i64>
// CHECK: %[[VAL_7:.*]], %[[VAL_8:.*]] = dc.unpack %[[VAL_2]] : !dc.value<i64>
Expand All @@ -75,7 +75,7 @@ handshake.func @mux(%select : i1, %a : i64, %b : i64) -> i64{
return %0 : i64
}

// CHECK: hw.module @mux4(in %[[VAL_0:.*]] : !dc.value<i2>, in %[[VAL_1:.*]] : !dc.value<i64>, in %[[VAL_2:.*]] : !dc.value<i64>, in %[[VAL_3:.*]] : !dc.value<i64>, in %[[VAL_4:.*]] : !dc.value<i64>, out out0 : !dc.value<i64>) {
// CHECK: hw.module @mux4(in %[[VAL_0:.*]] : !dc.value<i2>, in %[[VAL_1:.*]] : !dc.value<i64>, in %[[VAL_2:.*]] : !dc.value<i64>, in %[[VAL_3:.*]] : !dc.value<i64>, in %[[VAL_4:.*]] : !dc.value<i64>, in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.value<i64>) {
// CHECK: %[[VAL_5:.*]], %[[VAL_6:.*]] = dc.unpack %[[VAL_0]] : !dc.value<i2>
// CHECK: %[[VAL_7:.*]], %[[VAL_8:.*]] = dc.unpack %[[VAL_1]] : !dc.value<i64>
// CHECK: %[[VAL_9:.*]], %[[VAL_10:.*]] = dc.unpack %[[VAL_2]] : !dc.value<i64>
Expand Down Expand Up @@ -104,7 +104,7 @@ handshake.func @mux4(%select : i2, %a : i64, %b : i64, %c : i64, %d : i64) -> i6
return %0 : i64
}

// CHECK: hw.module @test_conditional_branch(in %[[VAL_0:.*]] : !dc.value<i1>, in %[[VAL_1:.*]] : !dc.value<index>, in %[[VAL_2:.*]] : !dc.token, out out0 : !dc.value<index>, out out1 : !dc.value<index>, out out2 : !dc.token) {
// CHECK: hw.module @test_conditional_branch(in %[[VAL_0:.*]] : !dc.value<i1>, in %[[VAL_1:.*]] : !dc.value<index>, in %[[VAL_2:.*]] : !dc.token, in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.value<index>, out out1 : !dc.value<index>, out out2 : !dc.token) {
// CHECK: %[[VAL_3:.*]], %[[VAL_4:.*]] = dc.unpack %[[VAL_0]] : !dc.value<i1>
// CHECK: %[[VAL_5:.*]], %[[VAL_6:.*]] = dc.unpack %[[VAL_1]] : !dc.value<index>
// CHECK: %[[VAL_7:.*]] = dc.join %[[VAL_3]], %[[VAL_5]]
Expand All @@ -119,7 +119,7 @@ handshake.func @test_conditional_branch(%arg0: i1, %arg1: index, %arg2: none, ..
return %0#0, %0#1, %arg2 : index, index, none
}

// CHECK: hw.module @test_conditional_branch_none(in %[[VAL_0:.*]] : !dc.value<i1>, in %[[VAL_1:.*]] : !dc.token, out out0 : !dc.token, out out1 : !dc.token) {
// CHECK: hw.module @test_conditional_branch_none(in %[[VAL_0:.*]] : !dc.value<i1>, in %[[VAL_1:.*]] : !dc.token, in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.token, out out1 : !dc.token) {
// CHECK: %[[VAL_2:.*]], %[[VAL_3:.*]] = dc.unpack %[[VAL_0]] : !dc.value<i1>
// CHECK: %[[VAL_4:.*]] = dc.join %[[VAL_2]], %[[VAL_1]]
// CHECK: %[[VAL_5:.*]] = dc.pack %[[VAL_4]], %[[VAL_3]] : i1
Expand All @@ -131,7 +131,7 @@ handshake.func @test_conditional_branch_none(%arg0: i1, %arg1: none) -> (none, n
return %0#0, %0#1 : none, none
}

// CHECK: hw.module @test_constant(in %[[VAL_0:.*]] : !dc.token, out out0 : !dc.value<i32>) {
// CHECK: hw.module @test_constant(in %[[VAL_0:.*]] : !dc.token, in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.value<i32>) {
// CHECK: %[[VAL_1:.*]] = dc.source
// CHECK: %[[VAL_2:.*]] = arith.constant 42 : i32
// CHECK: %[[VAL_3:.*]] = dc.pack %[[VAL_1]], %[[VAL_2]] : i32
Expand All @@ -142,7 +142,7 @@ handshake.func @test_constant(%arg0: none) -> (i32) {
return %1: i32
}

// CHECK: hw.module @test_control_merge(in %[[VAL_0:.*]] : !dc.token, in %[[VAL_1:.*]] : !dc.token, out out0 : !dc.token, out out1 : !dc.value<index>) {
// CHECK: hw.module @test_control_merge(in %[[VAL_0:.*]] : !dc.token, in %[[VAL_1:.*]] : !dc.token, in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.token, out out1 : !dc.value<index>) {
// CHECK: %[[VAL_2:.*]] = dc.merge %[[VAL_0]], %[[VAL_1]]
// CHECK: %[[VAL_3:.*]], %[[VAL_4:.*]] = dc.unpack %[[VAL_2]] : !dc.value<i1>
// CHECK: %[[VAL_5:.*]], %[[VAL_6:.*]] = dc.unpack %[[VAL_2]] : !dc.value<i1>
Expand All @@ -155,7 +155,7 @@ handshake.func @test_control_merge(%arg0 : none, %arg1 : none) -> (none, index)
return %out, %idx : none, index
}

// CHECK: hw.module @test_control_merge_data(in %[[VAL_0:.*]] : !dc.value<i2>, in %[[VAL_1:.*]] : !dc.value<i2>, out out0 : !dc.value<i2>, out out1 : !dc.value<index>) {
// CHECK: hw.module @test_control_merge_data(in %[[VAL_0:.*]] : !dc.value<i2>, in %[[VAL_1:.*]] : !dc.value<i2>, in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.value<i2>, out out1 : !dc.value<index>) {
// CHECK: %[[VAL_2:.*]], %[[VAL_3:.*]] = dc.unpack %[[VAL_0]] : !dc.value<i2>
// CHECK: %[[VAL_4:.*]], %[[VAL_5:.*]] = dc.unpack %[[VAL_1]] : !dc.value<i2>
// CHECK: %[[VAL_6:.*]] = dc.merge %[[VAL_2]], %[[VAL_4]]
Expand All @@ -172,7 +172,7 @@ handshake.func @test_control_merge_data(%arg0 : i2, %arg1 : i2) -> (i2, index) {
}

// CHECK-LABEL: hw.module @test_control_fixed_index_type(in
// CHECK-SAME: %[[VAL_0:.*]] : !dc.value<i4>, in %[[VAL_1:.*]] : !dc.value<i4>, out out0 : !dc.value<i4>, out out1 : !dc.value<i32>) {
// CHECK-SAME: %[[VAL_0:.*]] : !dc.value<i4>, in %[[VAL_1:.*]] : !dc.value<i4>, in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.value<i4>, out out1 : !dc.value<i32>) {
// CHECK: %[[VAL_2:.*]], %[[VAL_3:.*]] = dc.unpack %[[VAL_0]] : !dc.value<i4>
// CHECK: %[[VAL_4:.*]], %[[VAL_5:.*]] = dc.unpack %[[VAL_1]] : !dc.value<i4>
// CHECK: %[[VAL_6:.*]] = dc.merge %[[VAL_2]], %[[VAL_4]]
Expand All @@ -188,7 +188,7 @@ handshake.func @test_control_fixed_index_type(%arg0 : i4, %arg1 : i4) -> (i4, i3
return %out, %idx : i4, i32
}

// CHECK: hw.module @branch_and_merge(in %[[VAL_0:.*]] : !dc.value<i1>, in %[[VAL_1:.*]] : !dc.token, out out0 : !dc.token, out out1 : !dc.value<index>) {
// CHECK: hw.module @branch_and_merge(in %[[VAL_0:.*]] : !dc.value<i1>, in %[[VAL_1:.*]] : !dc.token, in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.token, out out1 : !dc.value<index>) {
// CHECK: %[[VAL_2:.*]] = dc.merge %[[VAL_3:.*]], %[[VAL_4:.*]]
// CHECK: %[[VAL_5:.*]], %[[VAL_6:.*]] = dc.unpack %[[VAL_2]] : !dc.value<i1>
// CHECK: %[[VAL_7:.*]], %[[VAL_8:.*]] = dc.unpack %[[VAL_2]] : !dc.value<i1>
Expand All @@ -206,7 +206,7 @@ handshake.func @branch_and_merge(%0 : i1, %1 : none) -> (none, index) {
return %out, %idx : none, index
}

// CHECK: hw.module @datamerge(in %[[VAL_0:.*]] : !dc.value<i1>, in %[[VAL_1:.*]] : !dc.value<i1>, in %[[VAL_2:.*]] : !dc.value<i1>, out out0 : !dc.value<i1>) {
// CHECK: hw.module @datamerge(in %[[VAL_0:.*]] : !dc.value<i1>, in %[[VAL_1:.*]] : !dc.value<i1>, in %[[VAL_2:.*]] : !dc.value<i1>, in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.value<i1>) {
// CHECK: %[[VAL_3:.*]], %[[VAL_4:.*]] = dc.unpack %[[VAL_0]] : !dc.value<i1>
// CHECK: %[[VAL_5:.*]], %[[VAL_6:.*]] = dc.unpack %[[VAL_1]] : !dc.value<i1>
// CHECK: %[[VAL_7:.*]] = dc.merge %[[VAL_3]], %[[VAL_5]]
Expand All @@ -220,7 +220,7 @@ handshake.func @datamerge(%arg0 : i1, %arg1 : i1, %arg2 : i1) -> i1 {
return %out : i1
}

// CHECK: hw.module @nonemerge(in %[[VAL_0:.*]] : !dc.token, in %[[VAL_1:.*]] : !dc.token, out out0 : !dc.token) {
// CHECK: hw.module @nonemerge(in %[[VAL_0:.*]] : !dc.token, in %[[VAL_1:.*]] : !dc.token, in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.token) {
// CHECK: %[[VAL_2:.*]] = dc.merge %[[VAL_0]], %[[VAL_1]]
// CHECK: %[[VAL_3:.*]], %[[VAL_4:.*]] = dc.unpack %[[VAL_2]] : !dc.value<i1>
// CHECK: hw.output %[[VAL_3]] : !dc.token
Expand All @@ -231,7 +231,7 @@ handshake.func @nonemerge(%arg0 : none, %arg1 : none) -> none {
}

// CHECK-LABEL: hw.module @pack_unpack(in
// CHECK-SAME: %[[VAL_0:.*]] : !dc.value<i32>, in %[[VAL_1:.*]] : !dc.value<i1>, out out0 : !dc.value<i32>, out out1 : !dc.value<i1>) {
// CHECK-SAME: %[[VAL_0:.*]] : !dc.value<i32>, in %[[VAL_1:.*]] : !dc.value<i1>, in %clk : !seq.clock {dc.clock}, in %rst : i1 {dc.reset}, out out0 : !dc.value<i32>, out out1 : !dc.value<i1>) {
// CHECK: %[[VAL_2:.*]], %[[VAL_3:.*]] = dc.unpack %[[VAL_0]] : !dc.value<i32>
// CHECK: %[[VAL_4:.*]], %[[VAL_5:.*]] = dc.unpack %[[VAL_1]] : !dc.value<i1>
// CHECK: %[[VAL_6:.*]] = dc.join %[[VAL_2]], %[[VAL_4]]
Expand Down

0 comments on commit feae186

Please sign in to comment.