CIRCT 20.0.0git
Loading...
Searching...
No Matches
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
18namespace circt {
19namespace moore {
20#define GEN_PASS_DEF_SIMPLIFYPROCEDURES
21#include "circt/Dialect/Moore/MoorePasses.h.inc"
22} // namespace moore
23} // namespace circt
24
25using namespace circt;
26using namespace moore;
27
28namespace {
29struct SimplifyProceduresPass
30 : public circt::moore::impl::SimplifyProceduresBase<
31 SimplifyProceduresPass> {
32 void runOnOperation() override;
33};
34} // namespace
35
36std::unique_ptr<mlir::Pass> circt::moore::createSimplifyProceduresPass() {
37 return std::make_unique<SimplifyProceduresPass>();
38}
39
40void 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.