CIRCT  20.0.0git
EliminateWires.cpp
Go to the documentation of this file.
1 //===- EliminateWires.cpp - Eliminate useless wires -------------*- 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 // This file defines the EliminateWires pass. This pass finds wires which,
10 // when relocated, become unnecessary and eliminates them. This is done by
11 // creating a node between the write and readers. Using a node allows the pass
12 // to preserve inner symbols and probes, letting CSE remove useless nodes.
13 //
14 //===----------------------------------------------------------------------===//
15 
18 #include "circt/Support/Debug.h"
19 #include "mlir/IR/Dominance.h"
20 #include "mlir/IR/ImplicitLocOpBuilder.h"
21 #include "mlir/Pass/Pass.h"
22 #include "llvm/Support/Debug.h"
23 
24 #include <deque>
25 
26 #define DEBUG_TYPE "firrtl-eliminate-wires"
27 
28 namespace circt {
29 namespace firrtl {
30 #define GEN_PASS_DEF_ELIMINATEWIRES
31 #include "circt/Dialect/FIRRTL/Passes.h.inc"
32 } // namespace firrtl
33 } // namespace circt
34 
35 using namespace circt;
36 using namespace firrtl;
37 
38 //===----------------------------------------------------------------------===//
39 // Pass Infrastructure
40 //===----------------------------------------------------------------------===//
41 
42 namespace {
43 struct EliminateWiresPass
44  : public circt::firrtl::impl::EliminateWiresBase<EliminateWiresPass> {
45  void runOnOperation() override;
46 };
47 } // end anonymous namespace
48 
49 void EliminateWiresPass::runOnOperation() {
50  LLVM_DEBUG(debugPassHeader(this) << "\n";);
51  auto module = getOperation();
52  auto &dominance = getAnalysis<mlir::DominanceInfo>();
53 
54  std::deque<std::pair<WireOp, MatchingConnectOp>> worklist;
55 
56  for (auto wire : module.getOps<WireOp>()) {
57  auto type = type_dyn_cast<FIRRTLBaseType>(wire.getResult().getType());
58  if (!type || !type.isPassive()) {
59  ++complexTypeWires;
60  continue;
61  }
62  // This will fail if there are multiple connects (due to aggregate
63  // decomposition or whens) or if there are connects in blocks (due to whens
64  // or matches). We are fine with this, we don't want to reason about those
65  // cases as other passes will handle them.
66  auto writer = getSingleConnectUserOf(wire.getResult());
67  if (!writer) {
68  ++complexWriteWires;
69  continue;
70  }
71  bool safe = true;
72  for (auto *user : wire->getUsers()) {
73  if (!dominance.dominates(writer, user)) {
74  ++notDomWires;
75  safe = false;
76  break;
77  }
78  }
79  if (!safe)
80  continue;
81  worklist.emplace_back(wire, writer);
82  }
83 
84  for (auto [wire, writer] : worklist) {
85  mlir::ImplicitLocOpBuilder builder(wire->getLoc(), writer);
86  auto node = builder.create<NodeOp>(
87  writer.getSrc(), wire.getName(), wire.getNameKind(),
88  wire.getAnnotations(), wire.getInnerSymAttr(), wire.getForceable());
89  wire.replaceAllUsesWith(node);
90  wire.erase();
91  writer.erase();
92  ++erasedWires;
93  }
94 }
95 
96 /// This is the pass constructor.
97 std::unique_ptr<mlir::Pass> circt::firrtl::createEliminateWiresPass() {
98  return std::make_unique<EliminateWiresPass>();
99 }
std::unique_ptr< mlir::Pass > createEliminateWiresPass()
This is the pass constructor.
MatchingConnectOp getSingleConnectUserOf(Value value)
Scan all the uses of the specified value, checking to see if there is exactly one connect that has th...
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
llvm::raw_ostream & debugPassHeader(const mlir::Pass *pass, int width=80)
Write a boilerplate header for a pass to the debug stream.
Definition: Debug.cpp:31