mirror of https://github.com/llvm/circt.git
[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:
parent
69b1fcd2d4
commit
375018a90c
|
@ -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 }];
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue