CIRCT  20.0.0git
LockFunctions.cpp
Go to the documentation of this file.
1 //===- LockFunctions.cpp - lock functions pass ------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Contains the definitions of the lock functions pass.
10 //
11 //===----------------------------------------------------------------------===//
12 
16 #include "mlir/IR/PatternMatch.h"
17 #include "mlir/Pass/Pass.h"
18 #include "mlir/Rewrite/FrozenRewritePatternSet.h"
19 #include "mlir/Transforms/DialectConversion.h"
20 
21 namespace circt {
22 namespace handshake {
23 #define GEN_PASS_DEF_HANDSHAKELOCKFUNCTIONS
24 #include "circt/Dialect/Handshake/HandshakePasses.h.inc"
25 } // namespace handshake
26 } // namespace circt
27 
28 using namespace circt;
29 using namespace handshake;
30 using namespace mlir;
31 
32 /// Adds a locking mechanism around the region.
33 static LogicalResult lockRegion(Region &r, OpBuilder &rewriter) {
34  Block *entry = &r.front();
35  Location loc = r.getLoc();
36 
37  if (entry->getNumArguments() == 0)
38  return r.getParentOp()->emitError("cannot lock a region without arguments");
39 
40  auto *ret = r.front().getTerminator();
41  if (ret->getNumOperands() == 0)
42  return r.getParentOp()->emitError("cannot lock a region without results");
43 
44  rewriter.setInsertionPointToStart(entry);
45  BackedgeBuilder bebuilder(rewriter, loc);
46  auto backEdge = bebuilder.get(rewriter.getNoneType());
47 
48  auto buff = rewriter.create<handshake::BufferOp>(loc, backEdge, 1,
49  BufferTypeEnum::seq);
50 
51  // Dummy value that causes a buffer initialization, but itself does not have a
52  // semantic meaning.
53  buff->setAttr("initValues", rewriter.getI64ArrayAttr({0}));
54 
55  SmallVector<Value> inSyncOperands =
56  llvm::to_vector_of<Value>(entry->getArguments());
57  inSyncOperands.push_back(buff);
58  auto sync = rewriter.create<SyncOp>(loc, inSyncOperands);
59 
60  // replace all func arg usages with the synced ones
61  // TODO is this UB?
62  for (auto &&[arg, synced] :
63  llvm::drop_end(llvm::zip(inSyncOperands, sync.getResults())))
64  arg.replaceAllUsesExcept(synced, sync);
65 
66  rewriter.setInsertionPoint(ret);
67  SmallVector<Value> endJoinOperands = llvm::to_vector(ret->getOperands());
68  // Add the axilirary control signal output to the end-join
69  endJoinOperands.push_back(sync.getResults().back());
70  auto endJoin = rewriter.create<JoinOp>(loc, endJoinOperands);
71 
72  backEdge.setValue(endJoin);
73  return success();
74 }
75 
76 namespace {
77 
78 struct HandshakeLockFunctionsPass
79  : public circt::handshake::impl::HandshakeLockFunctionsBase<
80  HandshakeLockFunctionsPass> {
81  void runOnOperation() override {
82  handshake::FuncOp op = getOperation();
83  if (op.isExternal())
84  return;
85 
86  OpBuilder builder(op);
87  if (failed(lockRegion(op.getRegion(), builder)))
88  signalPassFailure();
89  };
90 };
91 } // namespace
92 
93 std::unique_ptr<mlir::Pass>
95  return std::make_unique<HandshakeLockFunctionsPass>();
96 }
static LogicalResult lockRegion(Region &r, OpBuilder &rewriter)
Adds a locking mechanism around the region.
Instantiate one of these and use it to build typed backedges.
Backedge get(mlir::Type resultType, mlir::LocationAttr optionalLoc={})
Create a typed backedge.
std::unique_ptr< mlir::Pass > createHandshakeLockFunctionsPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21