CIRCT 24.0.0git
Loading...
Searching...
No Matches
Sig2Reg.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
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// Promote LLHD signals to SSA values.
10//
11//===----------------------------------------------------------------------===//
12
16#include "mlir/IR/Matchers.h"
17#include "llvm/Support/Debug.h"
18
19#define DEBUG_TYPE "llhd-sig2reg"
20
21namespace circt {
22namespace llhd {
23#define GEN_PASS_DEF_SIG2REGPASS
24#include "circt/Dialect/LLHD/LLHDPasses.h.inc"
25} // namespace llhd
26} // namespace circt
27
28using namespace mlir;
29using namespace circt;
30using namespace llhd;
31
32namespace {
33struct Sig2RegPass : public llhd::impl::Sig2RegPassBase<Sig2RegPass> {
34 void runOnOperation() override;
35 void promote(SignalOp op);
36 SmallVector<SignalOp> signalsToErase;
37};
38} // namespace
39
40void Sig2RegPass::runOnOperation() {
41 LLVM_DEBUG(llvm::dbgs() << "Promoting signals to values in "
42 << getOperation().getModuleName() << "\n");
43 for (auto op : getOperation().getOps<SignalOp>())
44 promote(op);
45 for (auto op : signalsToErase)
46 op.erase();
47 signalsToErase.clear();
48}
49
50void Sig2RegPass::promote(SignalOp op) {
51 // Find the single drive, and check if there are any probes or multiple drives
52 // of this signal. Bail on unknown users.
53 DriveLikeOp drive;
54 bool multipleDrives = false;
55 bool anyProbe = false;
56 for (auto *user : op->getUsers()) {
57 if (isa<ProbeOp>(user)) {
58 anyProbe = true;
59 continue;
60 }
61
62 if (auto driveOp = dyn_cast<DriveLikeOp>(user)) {
63 if (driveOp->getBlock() != op->getBlock()) {
64 LLVM_DEBUG(llvm::dbgs() << "- Skipping " << op
65 << " (driven from different block)\n");
66 ++numSkipped;
67 return;
68 }
69 if (drive)
70 multipleDrives = true;
71 drive = driveOp;
72 continue;
73 }
74
75 // Unknown user.
76 LLVM_DEBUG(llvm::dbgs() << "- Skipping " << op << " (unsupported user "
77 << user->getName() << ")\n");
78 ++numSkipped;
79 return;
80 }
81
82 // Remove unprobed signals.
83 if (!anyProbe) {
84 LLVM_DEBUG(llvm::dbgs() << "- Removing unprobed " << op << "\n");
85 ++numUnused;
86 SmallPtrSet<Operation *, 8> erased;
87 for (auto *user : llvm::make_early_inc_range(op->getUsers()))
88 if (erased.insert(user).second)
89 user->erase();
90 signalsToErase.push_back(op);
91 return;
92 }
93
94 // If there are multiple drives, we cannot come up with a clean replacement
95 // value.
96 if (multipleDrives) {
97 LLVM_DEBUG(llvm::dbgs() << "- Skipping " << op << " (multiple drives)\n");
98 ++numSkipped;
99 return;
100 }
101
102 // We can't promote conditional drives.
103 if (drive && drive.getEnable()) {
104 LLVM_DEBUG(llvm::dbgs() << "- Skipping " << op << " (conditional drive)\n");
105 ++numSkipped;
106 return;
107 }
108
109 // Determine the value to replace the signal with.
110 Value value;
111 if (drive) {
112 value = drive.getValue();
113 if (drive.getTime()) {
114 if (op.getInit()) {
115 LLVM_DEBUG(llvm::dbgs()
116 << "- Skipping " << op
117 << " (delayed drive to signal with initializer)\n");
118 ++numSkipped;
119 return;
120 }
121 TimeAttr delay;
122 if (!matchPattern(drive.getTime(), m_Constant(&delay))) {
123 LLVM_DEBUG(llvm::dbgs()
124 << "- Skipping " << op << " (non-constant drive delay)\n");
125 ++numSkipped;
126 return;
127 }
128 OpBuilder builder(drive);
129 value = DelayOp::create(builder, drive.getLoc(), value, delay);
130 }
131 } else {
132 value = op.getInit();
133 if (!value) {
134 LLVM_DEBUG(llvm::dbgs()
135 << "- Skipping " << op << " (undriven with no initializer)\n");
136 ++numSkipped;
137 return;
138 }
139
140 // The signal captures its initial value once. Only a constant initializer
141 // is guaranteed to equal the signal's value at all times.
142 if (!matchPattern(value, m_Constant())) {
143 LLVM_DEBUG(llvm::dbgs() << "- Skipping " << op
144 << " (undriven with non-constant initializer)\n");
145 ++numSkipped;
146 return;
147 }
148 }
149
150 // Replace all probes with this value, and remove all users, which are only
151 // probes and drives at this point.
152 LLVM_DEBUG({
153 llvm::dbgs() << "- Replacing " << op << " with ";
154 value.printAsOperand(llvm::dbgs(), OpPrintingFlags());
155 llvm::dbgs() << "\n";
156 });
157 SmallPtrSet<Operation *, 8> erased;
158 for (auto *user : llvm::make_early_inc_range(op->getUsers())) {
159 if (auto probeOp = dyn_cast<ProbeOp>(user))
160 probeOp.replaceAllUsesWith(value);
161 if (erased.insert(user).second)
162 user->erase();
163 }
164 signalsToErase.push_back(op);
165 ++numPromoted;
166}
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.