CIRCT  19.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 LogicalResult handshake::lockRegion(Region &r, OpBuilder &rewriter) {
33  Block *entry = &r.front();
34  Location loc = r.getLoc();
35 
36  if (entry->getNumArguments() == 0)
37  return r.getParentOp()->emitError("cannot lock a region without arguments");
38 
39  auto *ret = r.front().getTerminator();
40  if (ret->getNumOperands() == 0)
41  return r.getParentOp()->emitError("cannot lock a region without results");
42 
43  rewriter.setInsertionPointToStart(entry);
44  BackedgeBuilder bebuilder(rewriter, loc);
45  auto backEdge = bebuilder.get(rewriter.getNoneType());
46 
47  auto buff = rewriter.create<handshake::BufferOp>(loc, backEdge, 1,
48  BufferTypeEnum::seq);
49 
50  // Dummy value that causes a buffer initialization, but itself does not have a
51  // semantic meaning.
52  buff->setAttr("initValues", rewriter.getI64ArrayAttr({0}));
53 
54  SmallVector<Value> inSyncOperands =
55  llvm::to_vector_of<Value>(entry->getArguments());
56  inSyncOperands.push_back(buff);
57  auto sync = rewriter.create<SyncOp>(loc, inSyncOperands);
58 
59  // replace all func arg usages with the synced ones
60  // TODO is this UB?
61  for (auto &&[arg, synced] :
62  llvm::drop_end(llvm::zip(inSyncOperands, sync.getResults())))
63  arg.replaceAllUsesExcept(synced, sync);
64 
65  rewriter.setInsertionPoint(ret);
66  SmallVector<Value> endJoinOperands = llvm::to_vector(ret->getOperands());
67  // Add the axilirary control signal output to the end-join
68  endJoinOperands.push_back(sync.getResults().back());
69  auto endJoin = rewriter.create<JoinOp>(loc, endJoinOperands);
70 
71  backEdge.setValue(endJoin);
72  return success();
73 }
74 
75 namespace {
76 
77 struct HandshakeLockFunctionsPass
78  : public circt::handshake::impl::HandshakeLockFunctionsBase<
79  HandshakeLockFunctionsPass> {
80  void runOnOperation() override {
81  handshake::FuncOp op = getOperation();
82  if (op.isExternal())
83  return;
84 
85  OpBuilder builder(op);
86  if (failed(lockRegion(op.getRegion(), builder)))
87  signalPassFailure();
88  };
89 };
90 } // namespace
91 
92 std::unique_ptr<mlir::Pass>
94  return std::make_unique<HandshakeLockFunctionsPass>();
95 }
Builder builder
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()
LogicalResult lockRegion(Region &r, OpBuilder &rewriter)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21