CIRCT  19.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  DenseSet<Operation *> assignOps;
47  for (auto &nestedOp : procedureOp) {
48  // Only create a "shadow" varaible for the global variable used by other
49  // operations in the procedure body.
50  if (isa<ReadOp>(nestedOp) &&
51  isa<SVModuleOp>(
52  nestedOp.getOperand(0).getDefiningOp()->getParentOp())) {
53  // Collect the users of the global variable that is mentioned above.
54  DenseSet<Operation *> users;
55  for (auto *user : nestedOp.getOperand(0).getUsers())
56  // Ensuring don't handle the users existing in another procedure body.
57  if (user->getBlock() == procedureOp.getBody())
58  users.insert(user);
59 
60  // Because the operand of moore.event_wait is net.
61  if (auto varOp = llvm::dyn_cast_or_null<VariableOp>(
62  nestedOp.getOperand(0).getDefiningOp())) {
63  auto resultType = varOp.getResult().getType();
64  builder.setInsertionPointToStart(procedureOp.getBody());
65  auto readOp = builder.create<ReadOp>(
66  nestedOp.getLoc(), cast<RefType>(resultType).getNestedType(),
67  varOp.getResult());
68  auto newVarOp = builder.create<VariableOp>(
69  nestedOp.getLoc(), resultType, StringAttr{}, readOp);
70  builder.clearInsertionPoint();
71 
72  // Replace the users of the global variable with a corresponding
73  // "shadow" variable.
74  for (auto *user : users) {
75  user->replaceUsesOfWith(user->getOperand(0), newVarOp);
76  if (isa<BlockingAssignOp>(user))
77  assignOps.insert(user);
78  }
79  }
80  }
81 
82  // Ensure the global variable has the correct value. So needing to create
83  // a blocking assign for the global variable when the "shadow" variable
84  // has a new value.
85  for (auto *assignOp : assignOps)
86  if (auto localVarOp = llvm::dyn_cast_or_null<VariableOp>(
87  assignOp->getOperand(0).getDefiningOp())) {
88  auto resultType = localVarOp.getResult().getType();
89  builder.setInsertionPointAfter(assignOp);
90  auto readOp = builder.create<ReadOp>(
91  localVarOp.getLoc(), cast<RefType>(resultType).getNestedType(),
92  localVarOp.getResult());
93  builder.create<BlockingAssignOp>(
94  nestedOp.getLoc(),
95  localVarOp.getInitial().getDefiningOp()->getOperand(0), readOp);
96  builder.clearInsertionPoint();
97  assignOps.erase(assignOp);
98  }
99  }
100  });
101 }
std::unique_ptr< mlir::Pass > createSimplifyProceduresPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21