CIRCT  19.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 "mlir/Pass/Pass.h"
19 
21 #include "circt/Support/Debug.h"
22 #include "mlir/IR/Dominance.h"
23 #include "mlir/IR/ImplicitLocOpBuilder.h"
24 #include "llvm/Support/Debug.h"
25 
26 #include <deque>
27 
28 #define DEBUG_TYPE "firrtl-eliminate-wires"
29 
30 namespace circt {
31 namespace firrtl {
32 #define GEN_PASS_DEF_ELIMINATEWIRES
33 #include "circt/Dialect/FIRRTL/Passes.h.inc"
34 } // namespace firrtl
35 } // namespace circt
36 
37 using namespace circt;
38 using namespace firrtl;
39 
40 //===----------------------------------------------------------------------===//
41 // Pass Infrastructure
42 //===----------------------------------------------------------------------===//
43 
44 namespace {
45 struct EliminateWiresPass
46  : public circt::firrtl::impl::EliminateWiresBase<EliminateWiresPass> {
47  void runOnOperation() override;
48 };
49 } // end anonymous namespace
50 
51 void EliminateWiresPass::runOnOperation() {
52  LLVM_DEBUG(debugPassHeader(this) << "\n";);
53  auto module = getOperation();
54  auto &dominance = getAnalysis<mlir::DominanceInfo>();
55 
56  std::deque<std::pair<WireOp, MatchingConnectOp>> worklist;
57 
58  for (auto wire : module.getOps<WireOp>()) {
59  auto type = type_dyn_cast<FIRRTLBaseType>(wire.getResult().getType());
60  if (!type || !type.isPassive()) {
61  ++complexTypeWires;
62  continue;
63  }
64  // This will fail if there are multiple connects (due to aggregate
65  // decomposition or whens) or if there are connects in blocks (due to whens
66  // or matches). We are fine with this, we don't want to reason about those
67  // cases as other passes will handle them.
68  auto writer = getSingleConnectUserOf(wire.getResult());
69  if (!writer) {
70  ++complexWriteWires;
71  continue;
72  }
73  bool safe = true;
74  for (auto *user : wire->getUsers()) {
75  if (!dominance.dominates(writer, user)) {
76  ++notDomWires;
77  safe = false;
78  break;
79  }
80  }
81  if (!safe)
82  continue;
83  worklist.emplace_back(wire, writer);
84  }
85 
86  for (auto [wire, writer] : worklist) {
87  mlir::ImplicitLocOpBuilder builder(wire->getLoc(), writer);
88  auto node = builder.create<NodeOp>(
89  writer.getSrc(), wire.getName(), wire.getNameKind(),
90  wire.getAnnotations(), wire.getInnerSymAttr(), wire.getForceable());
91  wire.replaceAllUsesWith(node);
92  wire.erase();
93  writer.erase();
94  ++erasedWires;
95  }
96 }
97 
98 /// This is the pass constructor.
99 std::unique_ptr<mlir::Pass> circt::firrtl::createEliminateWiresPass() {
100  return std::make_unique<EliminateWiresPass>();
101 }
Builder builder
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