mirror of https://github.com/llvm/circt.git
[Handshake] Add sync op (#3912)
A `SyncOp` will make its results available once all inputs have arrived.
This commit is contained in:
parent
39cefff2e6
commit
d18142046b
|
@ -810,6 +810,33 @@ def JoinOp : Handshake_Op<"join", [
|
|||
let hasCustomAssemblyFormat = 1;
|
||||
}
|
||||
|
||||
def SyncOp : Handshake_Op<"sync", [
|
||||
HasClock, DeclareOpInterfaceMethods<ExecutableOpInterface>,
|
||||
DeclareOpInterfaceMethods<GeneralOpInterface>,
|
||||
AllTypesMatch<["operands", "results"]>
|
||||
]> {
|
||||
let summary = "sync operation";
|
||||
let description = [{
|
||||
Synchronizes an arbitrary set of inputs. Synchronization implies applying
|
||||
join semantics in between all in- and output ports.
|
||||
|
||||
Example:
|
||||
```mlir
|
||||
%aSynced, %bSynced, %cSynced = sync %a, %b, %c : i32, i1, none
|
||||
```
|
||||
}];
|
||||
let arguments = (ins Variadic<AnyType> : $operands);
|
||||
let results = (outs Variadic<AnyType> : $results);
|
||||
|
||||
let skipDefaultBuilders = 1;
|
||||
let builders = [OpBuilder<
|
||||
(ins "ValueRange":$operands), [{
|
||||
$_state.addOperands(operands);
|
||||
$_state.addTypes(operands.getTypes());
|
||||
}]>];
|
||||
let assemblyFormat = [{ $operands attr-dict `:` type($operands)}];
|
||||
}
|
||||
|
||||
def I4 : I<4>;
|
||||
def I4Attr : SignlessIntegerAttrBase<I4, "4-bit integer attribute">;
|
||||
|
||||
|
|
|
@ -34,8 +34,8 @@ public:
|
|||
BranchOp, BufferOp, ConditionalBranchOp, ConstantOp, ControlMergeOp,
|
||||
EndOp, ForkOp, FuncOp, InstanceOp, JoinOp, LazyForkOp, LoadOp,
|
||||
MemoryOp, ExternalMemoryOp, MergeOp, MuxOp, ReturnOp, SinkOp,
|
||||
handshake::SelectOp, SourceOp, StartOp, StoreOp, TerminatorOp,
|
||||
PackOp, UnpackOp>([&](auto opNode) -> ResultType {
|
||||
handshake::SelectOp, SourceOp, StartOp, StoreOp, SyncOp,
|
||||
TerminatorOp, PackOp, UnpackOp>([&](auto opNode) -> ResultType {
|
||||
return thisCast->visitHandshake(opNode, args...);
|
||||
})
|
||||
.Default([&](auto opNode) -> ResultType {
|
||||
|
@ -83,6 +83,7 @@ public:
|
|||
HANDLE(SourceOp);
|
||||
HANDLE(StartOp);
|
||||
HANDLE(StoreOp);
|
||||
HANDLE(SyncOp);
|
||||
HANDLE(TerminatorOp);
|
||||
HANDLE(PackOp);
|
||||
HANDLE(UnpackOp);
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
// RUN: handshake-runner %s | FileCheck %s
|
||||
// CHECK: 0 42
|
||||
|
||||
handshake.func @main(%ctrl: none) -> (i64, i64, none) {
|
||||
%ctrlF:3 = fork [3] %ctrl : none
|
||||
%c0 = constant %ctrlF#0 {value = 0 : i64} : i64
|
||||
%c42 = constant %ctrlF#1 {value = 42 : i64} : i64
|
||||
%out:3 = sync %c0, %c42, %ctrlF#2 : i64, i64, none
|
||||
return %out#0, %out#1, %out#2 : i64, i64, none
|
||||
}
|
|
@ -438,6 +438,19 @@ bool JoinOp::tryExecute(llvm::DenseMap<mlir::Value, llvm::Any> &valueMap,
|
|||
return tryToExecute(getOperation(), valueMap, timeMap, scheduleList, 1);
|
||||
}
|
||||
|
||||
void SyncOp::execute(std::vector<llvm::Any> &ins,
|
||||
std::vector<llvm::Any> &outs) {
|
||||
outs = ins;
|
||||
}
|
||||
|
||||
bool SyncOp::tryExecute(llvm::DenseMap<mlir::Value, llvm::Any> &valueMap,
|
||||
llvm::DenseMap<unsigned, unsigned> & /*memoryMap*/,
|
||||
llvm::DenseMap<mlir::Value, double> &timeMap,
|
||||
std::vector<std::vector<llvm::Any>> & /*store*/,
|
||||
std::vector<mlir::Value> &scheduleList) {
|
||||
return tryToExecute(getOperation(), valueMap, timeMap, scheduleList, 1);
|
||||
}
|
||||
|
||||
void StoreOp::execute(std::vector<llvm::Any> &ins,
|
||||
std::vector<llvm::Any> &outs) {
|
||||
// Forward the address and data to the memory op.
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
// RUN: circt-opt -split-input-file %s | circt-opt | FileCheck %s
|
||||
|
||||
// CHECK-LABEL: handshake.func @single_in(
|
||||
// CHECK-SAME: %[[VAL_0:.*]]: none, ...) -> none
|
||||
// CHECK: %[[VAL_1:.*]] = sync %[[VAL_0]] : none
|
||||
// CHECK: return %[[VAL_1]] : none
|
||||
// CHECK: }
|
||||
|
||||
handshake.func @single_in(%in0: none) -> none {
|
||||
%ctrlOut = sync %in0 : none
|
||||
return %ctrlOut : none
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// CHECK-LABEL: handshake.func @multi_in(
|
||||
// CHECK-SAME: %[[VAL_0:.*]]: none,
|
||||
// CHECK-SAME: %[[VAL_1:.*]]: i32,
|
||||
// CHECK-SAME: %[[VAL_2:.*]]: i512, ...) -> (none, i32, i512)
|
||||
// CHECK: %[[VAL_3:.*]]:3 = sync %[[VAL_0]], %[[VAL_1]], %[[VAL_2]] : none, i32, i512
|
||||
// CHECK: return %[[VAL_3]]#0, %[[VAL_3]]#1, %[[VAL_3]]#2 : none, i32, i512
|
||||
// CHECK: }
|
||||
|
||||
handshake.func @multi_in(%in0: none, %in1: i32, %in2: i512) -> (none, i32, i512) {
|
||||
%out:3 = sync %in0, %in1, %in2 : none, i32, i512
|
||||
return %out#0, %out#1, %out#2 : none, i32, i512
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
// CHECK-LABEL: handshake.func @attr(
|
||||
// CHECK-SAME: %[[VAL_0:.*]]: i64,
|
||||
// CHECK-SAME: %[[VAL_1:.*]]: i32, ...) -> (i64, i32)
|
||||
// CHECK: %[[VAL_2:.*]]:2 = sync %[[VAL_0]], %[[VAL_1]] {test_attr = "attribute"} : i64, i32
|
||||
// CHECK: return %[[VAL_2]]#0, %[[VAL_2]]#1 : i64, i32
|
||||
// CHECK: }
|
||||
|
||||
handshake.func @attr(%in0: i64, %in1: i32) -> (i64, i32) {
|
||||
%out:2 = sync %in0, %in1 {test_attr = "attribute"} : i64, i32
|
||||
return %out#0, %out#1 : i64, i32
|
||||
}
|
Loading…
Reference in New Issue