forked from coredac/neura
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTaskflowOps.td
More file actions
263 lines (218 loc) · 8.46 KB
/
TaskflowOps.td
File metadata and controls
263 lines (218 loc) · 8.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
#ifndef TASKFLOW_OPS_TD
#define TASKFLOW_OPS_TD
include "TaskflowDialect/TaskflowDialect.td"
include "TaskflowDialect/TaskflowTypes.td"
include "mlir/IR/OpBase.td"
include "mlir/IR/RegionKindInterface.td"
include "mlir/Interfaces/ControlFlowInterfaces.td"
include "mlir/Interfaces/SideEffectInterfaces.td"
include "mlir/Interfaces/InferTypeOpInterface.td"
include "mlir/IR/CommonTypeConstraints.td"
include "mlir/IR/CommonAttrConstraints.td"
//----------------------------------------------------------------------
// Base Class for all Taskflow operations.
//----------------------------------------------------------------------
class TaskflowOpBase<string mnemonic, list<Trait> traits = []> : Op<TaskflowDialect, mnemonic, traits>;
//----------------------------------------------------------------------
// Task Level Operations.
//----------------------------------------------------------------------
// Defines a uniform computation task operation within a Taskflow graph.
def TaskflowTaskOp : TaskflowOpBase<"task", [
IsolatedFromAbove,
AutomaticAllocationScope,
AttrSizedOperandSegments,
AttrSizedResultSegments,
SingleBlockImplicitTerminator<"TaskflowYieldOp">
]>{
let summary = "Computation task operation within a Taskflow graph.";
let description = [{
Represents a computational task that takes data inputs and produces
data outoputs. Tasks are isolated from their surrounding scope and can only
communicate through explicit data dependencies.
Tasks has two types of inputs/outputs:
1. Memory dependencies: memrefs that are read or written by the task
2. Value dependencies: SSA values from producer tasks
Example:
// Memory input: %mem, Value input: %val
$out_mem, %out_val = taskflow.task "Task_0"
memory_inputs(%mem : memref<4xi32>)
value_inputs(%val : i32) {
^bb0(%a0: memref<4xi32>, %a1: i32):
affine.for %i = 0 to 4 {
%v = affine.load %a0[%i] : memref<4xi32>
%sum = arith.addi %v, %a1 : i32
affine.store %sum, %a0[%i] : memref<4xi32>
}
taskflow.yield memory_outputs(%a0 : memref<4xi32>) value_outputs(%a1 : i32)
} : (memref<4xi32>, i32) -> (memref<4xi32>, i32)
}];
let arguments = (ins
Variadic<AnyMemRef>:$memory_inputs,
Variadic<AnyType>:$value_inputs,
StrAttr:$task_name
);
let results = (outs
Variadic<AnyMemRef>:$memory_outputs,
Variadic<AnyType>:$value_outputs
);
let regions = (region SizedRegion<1>:$body);
// let hasCustomAssemblyFormat = 1;
// let assemblyFormat = [{
// (`memory_inputs` `(` $memory_inputs^ `:` type($memory_inputs) `)`)?
// (`value_inputs` `(` $value_inputs^ `:` type($value_inputs) `)`)?
// attr-dict-with-keyword
// $body
// `->` `(` type($memory_outputs) `,` type($value_outputs) `)`
// }];
}
// Defines the yield operation to terminate a Taskflow task.
def TaskflowYieldOp : TaskflowOpBase<"yield", [Terminator, Pure, ReturnLike, AttrSizedOperandSegments, ParentOneOf<["TaskflowTaskOp"]>]>{
let summary = "Yield operation for Taskflow task";
let description = [{
Yields values from a task body. The number and types of operands
must match the result types of the parent taskflow.task operation.
Example:
taskflow.task "Task_0" (%arg0, %arg1) {
...
taskflow.yield %a0 : memref<4xi32>
} : (memref<4xi32>, i32) -> memref<4xi32>
}];
let arguments = (ins
Variadic<AnyMemRef>:$memory_results,
Variadic<AnyType>:$value_results);
// let assemblyFormat = [{
// (`memory_outputs` `(` $memory_results^ `:` type($memory_results) `)`)?
// (`value_outputs` `(` $value_results^ `:` type($value_results) `)`)?
// attr-dict
// }];
// let hasCustomAssemblyFormat = 1;
let builders = [
// Default builder for empty yield.
OpBuilder<(ins), [{
build($_builder, $_state, ValueRange{}, ValueRange{});
}]>
];
}
// Defines the data dependency edge operation that carries data dependencies between tasks in a Taskflow graph.
def TaskflowChannelOp : TaskflowOpBase<"channel", [Pure, SameOperandsAndResultType]>{
let summary = "Data dependency edge that carries data dependencies between tasks in a Taskflow graph";
let description = [{
Represents a data dependency edge between tasks in the taskflow graph.
A channel connects a producer task's output to a consumer task's input.
Channels enforce explicit data dependencies and can be used for:
- Producer-consumer relationships
- Read-after-write (RAW) dependencies
- Write-after-read (WAR) dependencies
- Write-after-write (WAW) dependencies
Example:
%0 = taskflow.task "producer_task" (...) { ... } : (...) -> memref<4xi32>
%1 = taskflow.channel %0 : memref<4xi32>
%2 = taskflow.task "consumer_task" (%1, ...) { ... } : (memref<4xi32>, ...) -> ...
}];
let arguments = (ins AnyType:$source);
let results = (outs AnyType:$target);
let assemblyFormat = [{
$source attr-dict `:` type($source) `->` type($target)
}];
}
//----------------------------------------------------------------------
// Intra-Task Operations.
//----------------------------------------------------------------------
// Counter operation representing loop iteration control within a Taskflow task.
def TaskflowCounterOp : TaskflowOpBase<"counter", []>{
let summary = "Loop counter operation with hardware counter semantics";
let description = [{
Represents a loop counter that generates iteration indices.
The hardware counter produces a predicated index value.
Counter classification:
- "root": Top-level counter with no parent (drives entire loop nest)
- "relay": Intermediate counter with both parent and child counters
- "leaf": Innermost counter with no child counters (maps to CGRA tile array)
Example:
// Root counter
%i = taskflow.counter {
lower_bound = 0 : index,
upper_bound = 16 : index,
step = 1 : index,
counter_type = "root"
} : index
// Leaf counter
%j = taskflow.counter parent(%i) {
lower_bound = 0 : index,
upper_bound = 8 : index,
step = 1 : index,
counter_type = "leaf"
} : index
}];
let arguments = (ins
Optional<AnyType>:$parent_index,
IndexAttr:$lower_bound,
IndexAttr:$upper_bound,
IndexAttr:$step,
OptionalAttr<StrAttr>:$counter_type,
OptionalAttr<I32Attr>:$counter_id
);
let results = (outs AnyType:$counter_index);
let assemblyFormat = [{
(`parent` `(` $parent_index^ `:` type($parent_index) `)`)?
attr-dict-with-keyword
`:` type($counter_index)
}];
}
def TaskflowHyperblockOp : TaskflowOpBase<"hyperblock",[
AutomaticAllocationScope,
AttrSizedOperandSegments,
SingleBlockImplicitTerminator<"TaskflowHyperblockYieldOp">
]>{
let summary = "Hyperblock operation containing loop body computation";
let description = [{
Represents the loop body computation as a hyperblock controlled by taskflow.counter operation.
The hyperblock takes the counter indices as input to trigger its execution.
If the hyperblock has a return value, it must return the final value produced by the hyperblock (i.e., from the last iteration).
Example:
%result = taskflow.hyperblock indices(%i : index), iter_args(%init_val : i32) {
^bb0(%idx: index, %arg: i32):
// Loop body computation using %idx and %arg
...
taskflow.hyperblock.yield %output : i32
} -> i32
}];
let arguments = (ins
Variadic<AnyType>:$indices,
Variadic<AnyType>:$iter_args
);
let results = (outs
Variadic<AnyType>:$outputs
);
let regions = (region SizedRegion<1>:$body);
// let assemblyFormat = [{
// (`indices` `(` $indices^ `:` type($indices) `)`)?
// attr-dict-with-keyword
// $body
// `->` `(` type($outputs) `)`
// }];
}
def TaskflowHyperblockYieldOp : TaskflowOpBase<"hyperblock.yield", [
Terminator,
Pure,
ReturnLike,
AttrSizedOperandSegments,
ParentOneOf<["TaskflowHyperblockOp"]>
]>{
let summary = "Yield operation for Taskflow hyperblock";
let description = [{
Terminates the hyperblock body.
}];
let arguments = (ins
Variadic<AnyType>:$iter_args_next,
Variadic<AnyType>:$results);
let assemblyFormat = [{
(`iter_args_next` `(` $iter_args_next^ `:` type($iter_args_next) `)`)?
(`results` `(` $results^ `:` type($results) `)`)?
attr-dict
}];
let builders = [
OpBuilder<(ins), [{build($_builder, $_state, ValueRange{}, ValueRange{});}]>
];
}
#endif // TASKFLOW_OPS_TD