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