[MSFT] Introduce `LinearOp` (#3680)

The `msft.hlc.linear` operation defines a linear datapath. It serves as a container for `hw`, `comb` and `msft` operations, with the following restrictions:
- Not graph-like - only SSA def-use chains are allowed.
- `seq` ops are not allowed.
This commit is contained in:
Morten Borup Petersen 2022-08-11 12:40:56 +02:00 committed by GitHub
parent 69b1fcd2d4
commit 375018a90c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 80 additions and 1 deletions

View File

@ -67,3 +67,37 @@ def ChannelOp: MSFTOp<"constructs.channel",
$input $clk $sym_name `(` $defaultStages `)` attr-dict `:` type($input)
}];
}
// Linear, pipelineable datapath.
def LinearOp : MSFTOp<"hlc.linear", [
SingleBlockImplicitTerminator<"OutputOp">
]> {
let summary = "Model of a linear datapath which can be arbitrarily pipelined";
let description = [{
Defines a feed-forward datapath which can be scheduled into a pipeline.
Due to the feed-forwardness, the inner region is NOT a graph region.
Internally, only combinational operations (`comb`, `msft`, `hw`) are allowed.
Example:
```mlir
msft.module @foo(%in0 : i32, %in1 : i32, %in2 : i32, %clk : i1) -> (out: i32) -> {
%0 = msft.hlc.linear(%a = %in0, %b = %in1, %c = %in2) clock %clk (i32, i32, i32) -> (i32) {
%0 = comb.mul %a, %b : i32
%1 = comb.add %0, %c : i32
msft.output %1 : i32
}
}
```
}];
let arguments = (ins I1:$clock);
let results = (outs Variadic<AnyType>:$outs);
let regions = (region SizedRegion<1>:$datapath);
let extraClassDeclaration = [{
Block *getBodyBlock() { return &datapath().front(); }
}];
let hasVerifier = 1;
let assemblyFormat = [{ `clock` $clock attr-dict `:` type($outs) $datapath }];
}

View File

@ -237,7 +237,7 @@ def DesignPartitionOp : MSFTOp<"partition",
let assemblyFormat = "$sym_name `,` $verilogName attr-dict";
}
def OutputOp : MSFTOp<"output", [Terminator, HasParent<"MSFTModuleOp">,
def OutputOp : MSFTOp<"output", [Terminator, ParentOneOf<["MSFTModuleOp", "LinearOp"]>,
NoSideEffect, ReturnLike]> {
let summary = "termination operation";

View File

@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "circt/Dialect/MSFT/MSFTOps.h"
#include "circt/Dialect/Comb/CombDialect.h"
#include "circt/Dialect/HW/HWAttributes.h"
#include "circt/Dialect/HW/HWOps.h"
#include "circt/Dialect/HW/ModuleImplementation.h"
@ -978,5 +979,21 @@ void SystolicArrayOp::print(OpAsmPrinter &p) {
p.printRegion(pe(), false);
}
//===----------------------------------------------------------------------===//
// LinearOp
//===----------------------------------------------------------------------===//
LogicalResult LinearOp::verify() {
for (auto &op : *getBodyBlock()) {
if (!isa<hw::HWDialect, comb::CombDialect, msft::MSFTDialect>(
op.getDialect()))
return emitOpError() << "expected only hw, comb, and msft dialect ops "
"inside the datapath.";
}
return success();
}
#define GET_OP_CLASSES
#include "circt/Dialect/MSFT/MSFT.cpp.inc"

View File

@ -61,3 +61,19 @@ msft.module @ChannelExample {} (%clk: i1, %a : i8) -> (out: i8) {
%out = msft.constructs.channel %a %clk "chEx" (2) : i8
msft.output %out : i8
}
// CHECK-LABEL: msft.module @foo {} (%in0: i32, %in1: i32, %in2: i32, %clk: i1) -> (out: i32) {
// CHECK: %0 = msft.hlc.linear clock %clk : i32 {
// CHECK: %1 = comb.mul %in0, %in1 : i32
// CHECK: %2 = comb.add %1, %in2 : i32
// CHECK: msft.output %2 : i32
// CHECK: }
// CHECK: msft.output %0 : i32
msft.module @foo {} (%in0 : i32, %in1 : i32, %in2 : i32, %clk : i1) -> (out: i32) {
%0 = msft.hlc.linear clock %clk : i32 {
%0 = comb.mul %in0, %in1 : i32
%1 = comb.add %0, %in2 : i32
msft.output %1 : i32
}
msft.output %0 : i32
}

View File

@ -45,3 +45,15 @@ msft.module @M {} (%x : i32) {
comb.add %x, %x {msft.appid=#msft.appid<"add"[0]>} : i32
msft.output
}
// -----
msft.module @foo {} (%in0 : i32, %clk : i1) -> (out: i32) {
// expected-error @+1 {{'msft.hlc.linear' op expected only hw, comb, and msft dialect ops inside the datapath.}}
%0 = msft.hlc.linear clock %clk : i32 {
%c1_i1 = hw.constant 1 : i1
%0 = seq.compreg %in0, %c1_i1 : i32
msft.output %0 : i32
}
msft.output %0 : i32
}