CIRCT  20.0.0git
SimplifyProcedures.cpp
Go to the documentation of this file.
1 //===- DeleteLocalVar.cpp - Delete local temporary variables --------------===//
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 // This file defines the SimplifyProcedures pass.
10 // Use to insert a local "shadow" variable in always blocks for every
11 // module-level variable that the process modifies.
12 //
13 //===----------------------------------------------------------------------===//
14 
17 
18 namespace circt {
19 namespace moore {
20 #define GEN_PASS_DEF_SIMPLIFYPROCEDURES
21 #include "circt/Dialect/Moore/MoorePasses.h.inc"
22 } // namespace moore
23 } // namespace circt
24 
25 using namespace circt;
26 using namespace moore;
27 
28 namespace {
29 struct SimplifyProceduresPass
30  : public circt::moore::impl::SimplifyProceduresBase<
31  SimplifyProceduresPass> {
32  void runOnOperation() override;
33 };
34 } // namespace
35 
36 std::unique_ptr<mlir::Pass> circt::moore::createSimplifyProceduresPass() {
37  return std::make_unique<SimplifyProceduresPass>();
38 }
39 
40 void SimplifyProceduresPass::runOnOperation() {
41  getOperation()->walk([&](ProcedureOp procedureOp) {
42  mlir::OpBuilder builder(&getContext());
43 
44  // Use to collect blocking assignments that have been replaced by a "shadow"
45  // variable.
46  procedureOp.walk([&](Operation *op) {
47  SmallVector<std::tuple<BlockingAssignOp, Value, Value>> assignOps;
48  auto &nestedOp = *op;
49  // Only create a "shadow" varaible for the global variable used by other
50  // operations in the procedure body.
51  if (isa<ReadOp>(nestedOp) &&
52  isa<SVModuleOp>(
53  nestedOp.getOperand(0).getDefiningOp()->getParentOp())) {
54  // Collect the users of the global variable that is mentioned above.
55  DenseSet<Operation *> users;
56  for (auto *user : nestedOp.getOperand(0).getUsers())
57  // Ensuring don't handle the users existing in another procedure body.
58  if (procedureOp->isAncestor(user))
59  users.insert(user);
60 
61  // Because the operand of moore.event_wait is net.
62  if (auto varOp = llvm::dyn_cast_or_null<VariableOp>(
63  nestedOp.getOperand(0).getDefiningOp())) {
64  auto resultType = varOp.getResult().getType();
65  builder.setInsertionPointToStart(&procedureOp.getBody().front());
66  auto readOp = builder.create<ReadOp>(
67  nestedOp.getLoc(), cast<RefType>(resultType).getNestedType(),
68  varOp.getResult());
69  auto newVarOp = builder.create<VariableOp>(
70  nestedOp.getLoc(), resultType, StringAttr{}, Value{});
71  builder.create<BlockingAssignOp>(nestedOp.getLoc(), newVarOp, readOp);
72  builder.clearInsertionPoint();
73 
74  // Replace the users of the global variable with a corresponding
75  // "shadow" variable.
76  for (auto *user : users) {
77  user->replaceUsesOfWith(user->getOperand(0), newVarOp);
78  if (auto assignOp = dyn_cast<BlockingAssignOp>(user))
79  assignOps.push_back({assignOp, newVarOp, varOp});
80  }
81  }
82  }
83 
84  // Ensure the global variable has the correct value. So needing to create
85  // a blocking assign for the global variable when the "shadow" variable
86  // has a new value.
87  for (auto [assignOp, localVar, var] : assignOps) {
88  builder.setInsertionPointAfter(assignOp);
89  auto readOp = builder.create<ReadOp>(assignOp.getLoc(), localVar);
90  builder.create<BlockingAssignOp>(assignOp.getLoc(), var, readOp);
91  builder.clearInsertionPoint();
92  }
93  });
94  });
95 }
std::unique_ptr< mlir::Pass > createSimplifyProceduresPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21