# 'dfg' Dialect
The `dfg` dialect groups together a set of types, operations and
transformations that are useful to implement a structured abstraction
on dataflow graphs.
These abstractions are useful for constructing KPN/SDF-like dataflow
graphs, which include definitions of nodes, edges and their connections.
[TOC]
## Operations
### `dfg.channel` (dfg::ChannelOp)
_Defines a channel with one input and one output port_
The `channel` operation produces a typed channel (i.e. an edge in the
dataflow graph) that links two nodes (i.e. process or operator) in the
dataflow graph.
The input of a channel will be connected to an output port of a node,
which means its type is dfg::InputType, same for output port.
A channel can also be sized manually with a 32-bit integer, otherwise,
it indicates an unbounded FIFO channel.
The token flows in the channel can also be of memref/tensor type, which
implicitly enables multiple read/write as in KPN MoC.
Examples:
```
%input, %output = dfg.channel() : type
$input, %output = dfg.channel(size) : shape x type
```
Interfaces: `DFG_EdgeInterface`, `MemoryEffectsOpInterface`, `OpAsmOpInterface`
#### Attributes:
| Attribute | MLIR Type | Description |
token_type | ::mlir::TypeAttr | any type attribute |
buffer_size | ::mlir::IntegerAttr | 32-bit signless integer attribute |
#### Results:
| Result | Description |
| :----: | ----------- |
| `input_port` | Sending channel end type |
| `output_port` | Receiving channel end type |
### `dfg.embed` (dfg::EmbedOp)
_Embed a region as a subgraph in another._
The `embed` operation embed a region into another region.
The syntax and usage of this operation is similar to `instantiate` operation.
```
dfg.region @child inputs(...) outputs(...) {...}
dfg.region @parent inputs(...) outputs(...) {
dfg.embed @child inputs(...) outputs(...) : (...) -> (...)
}
```
Traits: `AttrSizedOperandSegments`
Interfaces: `DFG_GraphInterface`, `DFG_NodeInterface`
#### Attributes:
| Attribute | MLIR Type | Description |
actor | ::mlir::SymbolRefAttr | symbol reference attribute |
offloaded | ::mlir::dfg::OffloadHardwareAttr | The hardware back to be offloaded to |
#### Operands:
| Operand | Description |
| :-----: | ----------- |
| `inputs` | variadic of Receiving channel end type |
| `outputs` | variadic of Sending channel end type |
### `dfg.instantiate` (dfg::InstantiateOp)
_Instantiates an DFG node._
The `instantiate` operation instantiate an operator or process in a
region with a set of inputs and outputs.
InstantiateOp creates a DFG node with a set of input and output values.
```
dfg.operator @operator inputs(...) outputs(...) {...}
dfg.process @process inputs(...) outputs(...) {...}
dfg.region @graph inputs(...) outputs(...) {
dfg.instantiate @operator inputs(...) outputs(...) : (...) -> (...)
dfg.instantiate @process inputs(...) outputs(...) : (...) -> (...)
}
```
Traits: `AttrSizedOperandSegments`
Interfaces: `DFG_NodeInterface`
#### Attributes:
| Attribute | MLIR Type | Description |
actor | ::mlir::SymbolRefAttr | symbol reference attribute |
offloaded | ::mlir::dfg::OffloadHardwareAttr | The hardware back to be offloaded to |
#### Operands:
| Operand | Description |
| :-----: | ----------- |
| `inputs` | variadic of Receiving channel end type |
| `outputs` | variadic of Sending channel end type |
### `dfg.loop` (dfg::LoopOp)
_Defines the repeatedly executed body of a process._
The `loop` operation defines the repeatedly executed body of a process.
During each iteration, operations in the body can pull tokens from the
process input ports, perform computations, and push tokens to the
process output ports.
The `inputs` and `outputs` lists identify the process ports that are
monitored for stream termination. A port is closed when no further
tokens will be transferred through it. When closure is observed on the
listed input ports, the process loop terminates and closure propagates
through its listed output ports. This allows downstream processes, and
eventually the whole dataflow graph, to shut down.
Example:
```
dfg.process @add inputs(%a: !dfg.output) outputs(%b: !dfg.input)
{
dfg.loop inputs(%a: !dfg.output) outputs(%b: !dfg.input) {
ops ...
}
}
```
Traits: `AttrSizedOperandSegments`, `AutomaticAllocationScope`, `HasParent`, `NoTerminator`, `RecursiveMemoryEffects`
#### Operands:
| Operand | Description |
| :-----: | ----------- |
| `input_channels` | variadic of Receiving channel end type |
| `output_channels` | variadic of Sending channel end type |
### `dfg.operator` (dfg::OperatorOp)
_Defines an DFG node in SDF MoC_
The `operator` operation defines one node (actor) in the SDF dataflow model.
An operator is a special case of `process`, which only write values into output
ports once at the end.
Example:
```
dfg.operator @node inputs(%in0: i32, %in1: i32) outputs(%out0: i32, %out1: i32)
{
ops ...
dfg.output ...
}
```
Traits: `AffineScope`, `AutomaticAllocationScope`, `HasParent`, `IsolatedFromAbove`, `SingleBlockImplicitTerminator`, `SingleBlock`
Interfaces: `DFG_NodeInterface`, `OpAsmOpInterface`
#### Attributes:
| Attribute | MLIR Type | Description |
sym_name | ::mlir::StringAttr | string attribute |
function_type | ::mlir::TypeAttr | type attribute of function type |
### `dfg.output` (dfg::OutputOp)
_Terminator for an OperatorOp_
Syntax:
```
operation ::= `dfg.output` attr-dict ($operands^ `:` type($operands))?
```
Traits: `HasParent`, `Terminator`
#### Operands:
| Operand | Description |
| :-----: | ----------- |
| `operands` | variadic of any non-token type |
### `dfg.process` (dfg::ProcessOp)
_Defines a process in the KPN MoC_
The `process` operation defines one node (actor) in the KPN dataflow model.
A process is a symbol at module scope and can be connected to other processes
through its input and output ports.
The port interface is described by `function_type`:
- function inputs represent incoming channel ends
- function results represent outgoing channel ends
A `process` can have one region with other IRs inside or none with a link to a library call.
Example:
```
dfg.process @node inputs(%in0: !dfg.output, %in1: !dfg.output)
outputs(%out0: !dfg.input, %out1: !dfg.input)
{
ops ...
}
```
Traits: `AffineScope`, `AutomaticAllocationScope`, `HasParent`, `IsolatedFromAbove`, `NoTerminator`
Interfaces: `DFG_NodeInterface`, `OpAsmOpInterface`
#### Attributes:
| Attribute | MLIR Type | Description |
sym_name | ::mlir::StringAttr | string attribute |
function_type | ::mlir::TypeAttr | type attribute of function type |
multiplicity | ::mlir::DenseI64ArrayAttr | i64 dense array attribute |
### `dfg.pull` (dfg::PullOp)
_Pulls a token from an input port of a node._
The `pull` operation reads a token out from an input port of a node,
which is connected via a channel to an output port of another node.
An optional set of indices must be used if the read port has a shape,
indicating a set of ports to be chosen from.
Example:
```
dfg.process @pull inputs(%in0: !dfg.output, %in1: !dfg.output)
{
%0 = arith.constant ... : index
%token0 = dfg.pull %in0 : !dfg.output
%token1 = dfg.pull %in1[%0] : !dfg.output
}
```
Interfaces: `OpAsmOpInterface`
#### Operands:
| Operand | Description |
| :-----: | ----------- |
| `read_port` | Receiving channel end type |
| `indices` | variadic of index |
#### Results:
| Result | Description |
| :----: | ----------- |
| `token` | any non-token type |
### `dfg.pull_as_memref` (dfg::PullAsMemRefOp)
_Pulls as a memref from a shaped input port of a node._
Interfaces: `OpAsmOpInterface`
#### Operands:
| Operand | Description |
| :-----: | ----------- |
| `read_port` | Receiving channel end type |
#### Results:
| Result | Description |
| :----: | ----------- |
| `token_memref` | memref of any non-token type values |
### `dfg.pull_as_tensor` (dfg::PullAsTensorOp)
_Pulls as a tensor from a shaped input port of a node._
Interfaces: `OpAsmOpInterface`
#### Operands:
| Operand | Description |
| :-----: | ----------- |
| `read_port` | Receiving channel end type |
#### Results:
| Result | Description |
| :----: | ----------- |
| `token_tensor` | ranked tensor of any non-token type values |
### `dfg.push` (dfg::PushOp)
_Pushes a token to an output port of a node._
The `push` operation writes a token to an output port of a node,
which is connected via a channel to an input port of another node.
An optional set of indices must be used if the port has a shape.
Example:
```
dfg.process @push outputs(%out0: !dfg.input, %out1: !dfg.input)
{
%0 = arith.constant ... : index
%1 = arith.constant ... : type
%token0 = dfg.push %1 to %out0 : !dfg.input
%token1 = dfg.push %1 to %out1[%0] : !dfg.input
}
```
#### Operands:
| Operand | Description |
| :-----: | ----------- |
| `token` | any non-token type |
| `write_port` | Sending channel end type |
| `indices` | variadic of index |
### `dfg.push_memref` (dfg::PushMemRefOp)
_Pushes a memref to a shaped output port of a node._
#### Operands:
| Operand | Description |
| :-----: | ----------- |
| `token_memref` | memref of any non-token type values |
| `write_port` | Sending channel end type |
### `dfg.push_tensor` (dfg::PushTensorOp)
_Pushes a tensor to a shaped output port of a node._
#### Operands:
| Operand | Description |
| :-----: | ----------- |
| `token_tensor` | ranked tensor of any non-token type values |
| `write_port` | Sending channel end type |
### `dfg.region` (dfg::RegionOp)
_Defines a region(subgraph) in the DFG._
The `region` operation defines one node(subgraph) or the entire graph in the
dataflow graph model.
A region can be embedded into another region as subgraph, which content can
only be an instantiation of a node(processes/operators/regions) and their
connections(channels).
A region's input/output ports must be connected/used.
Example:
```
dfg.region @node inputs(%in0: !dfg.output, %in1: !dfg.output)
outputs(%out0: !dfg.input, %out1: !dfg.input)
{
%0:2 = dfg.channel ...
dfg.instantiate @process ...
dfg.instantiate @operator ...
dfg.embed @region ...
}
```
Traits: `IsolatedFromAbove`, `NoTerminator`
Interfaces: `DFG_GraphInterface`, `DFG_NodeInterface`, `OpAsmOpInterface`
#### Attributes:
| Attribute | MLIR Type | Description |
sym_name | ::mlir::StringAttr | string attribute |
function_type | ::mlir::TypeAttr | type attribute of function type |
## Types
### InputType
_Sending channel end type_
The `input` type represents the sending end of a dataflow edge
in a dataflow graph.
This type takes an optional shape and a scalar MLIR type as
element type, such as:
`!dfg.input`, `!dfg.input<2xi32>`, `!dfg.input<2x2xi32>`
#### Parameters:
| Parameter | C++ type | Description |
| :-------: | :-------: | ----------- |
| shape | `::llvm::ArrayRef` | |
| elementType | `Type` | |
### OutputType
_Receiving channel end type_
The `output` type represents the receiving end of a dataflow edge
in a dataflow graph.
Details are similar to dfg::InputType.
#### Parameters:
| Parameter | C++ type | Description |
| :-------: | :-------: | ----------- |
| shape | `::llvm::ArrayRef` | |
| elementType | `Type` | |
## Enums
### OffloadHardware
_The hardware back to be offloaded to_
#### Cases:
| Symbol | Value | String |
| :----: | :---: | ------ |
| EmitHLS | `0` | emithls |
| MDC | `1` | mdc |
| CGRA | `2` | cgra |