16#include "mlir/IR/Builders.h"
17#include "mlir/Pass/Pass.h"
18#include "llvm/ADT/PostOrderIterator.h"
22#define GEN_PASS_DEF_HWELIMINATEINOUTPORTS
23#include "circt/Dialect/SV/SVPasses.h.inc"
34struct HWEliminateInOutPortsPass
35 :
public circt::sv::impl::HWEliminateInOutPortsBase<
36 HWEliminateInOutPortsPass> {
37 using HWEliminateInOutPortsBase<
38 HWEliminateInOutPortsPass>::HWEliminateInOutPortsBase;
39 void runOnOperation()
override;
44 HWInOutPortConversion(PortConverterImpl &converter, hw::PortInfo port,
45 Type type, llvm::StringRef readSuffix,
46 llvm::StringRef writeSuffix);
48 void mapInputSignals(OpBuilder &b, Operation *inst, Value instValue,
49 SmallVectorImpl<Value> &newOperands,
50 ArrayRef<Backedge> newResults)
override;
51 void mapOutputSignals(OpBuilder &b, Operation *inst, Value instValue,
52 SmallVectorImpl<Value> &newOperands,
53 ArrayRef<Backedge> newResults)
override;
55 LogicalResult init()
override;
58 void buildInputSignals()
override;
59 void buildOutputSignals()
override;
62 llvm::SmallVector<sv::ReadInOutOp, 4> readers;
64 llvm::SmallVector<sv::AssignOp, 4> writers;
66 bool hasReaders() {
return !readers.empty(); }
67 bool hasWriters() {
return !writers.empty(); }
73 PortInfo readPort, writePort;
76 llvm::StringRef readSuffix;
78 llvm::StringRef writeSuffix;
82 hw::PortInfo port, Type type,
83 llvm::StringRef readSuffix,
84 llvm::StringRef writeSuffix)
85 :
PortConversion(converter, port), type(type), readSuffix(readSuffix),
86 writeSuffix(writeSuffix) {}
88LogicalResult HWInOutPortConversion::init() {
90 for (
auto *user : body->getArgument(origPort.argNum).getUsers()) {
91 if (
auto read = dyn_cast<sv::ReadInOutOp>(user))
92 readers.push_back(read);
93 else if (
auto write = dyn_cast<sv::AssignOp>(user))
94 writers.push_back(write);
96 return user->emitOpError() <<
"uses hw.inout port " << origPort.name
97 <<
" but the operation itself is unsupported.";
100 if (writers.size() > 1)
101 return converter.getModule()->emitOpError()
102 <<
"multiple writers of inout port " << origPort.name
103 <<
" is unsupported.";
108void HWInOutPortConversion::buildInputSignals() {
112 converter.createNewInput(origPort, readSuffix, type, readPort);
113 Value origInput = body->getArgument(origPort.argNum);
114 for (
auto *user : llvm::make_early_inc_range(origInput.getUsers())) {
115 sv::ReadInOutOp
read = dyn_cast<sv::ReadInOutOp>(user);
119 read.replaceAllUsesWith(readValue);
126 sv::AssignOp
write = writers.front();
127 converter.createNewOutput(origPort, writeSuffix, type,
write.getSrc(),
133void HWInOutPortConversion::buildOutputSignals() {
135 "`hw.inout` outputs not yet supported. Currently, `hw.inout` "
136 "outputs are handled by UntouchedPortConversion, given that "
137 "output `hw.inout` ports have a `ModulePort::Direction::Output` "
138 "direction instead of `ModulePort::Direction::InOut`. If this for "
139 "some reason changes, then this assert will fire.");
142void HWInOutPortConversion::mapInputSignals(OpBuilder &b, Operation *inst,
144 SmallVectorImpl<Value> &newOperands,
145 ArrayRef<Backedge> newResults) {
150 newOperands[readPort.
argNum] =
157 Value writeFromInsideMod = newResults[writePort.
argNum];
162void HWInOutPortConversion::mapOutputSignals(
163 OpBuilder &b, Operation *inst, Value instValue,
164 SmallVectorImpl<Value> &newOperands, ArrayRef<Backedge> newResults) {
167 "`hw.inout` outputs not yet supported. Currently, `hw.inout` "
168 "outputs are handled by UntouchedPortConversion, given that "
169 "output `hw.inout` ports have a `ModulePort::Direction::Output` "
170 "direction instead of `ModulePort::Direction::InOut`. If this for "
171 "some reason changes, then this assert will fire.");
174class HWInoutPortConversionBuilder :
public PortConversionBuilder {
176 HWInoutPortConversionBuilder(PortConverterImpl &converter,
177 llvm::StringRef readSuffix,
178 llvm::StringRef writeSuffix)
179 : PortConversionBuilder(converter), readSuffix(readSuffix),
180 writeSuffix(writeSuffix) {}
182 FailureOr<std::unique_ptr<PortConversion>> build(hw::PortInfo port)
override {
184 return {std::make_unique<HWInOutPortConversion>(
185 converter, port, inout.getElementType(), readSuffix, writeSuffix)};
190 llvm::StringRef readSuffix;
191 llvm::StringRef writeSuffix;
196void HWEliminateInOutPortsPass::runOnOperation() {
198 circt::hw::InstanceGraph &instanceGraph =
199 getAnalysis<circt::hw::InstanceGraph>();
200 llvm::DenseSet<InstanceGraphNode *> visited;
201 FailureOr<llvm::ArrayRef<InstanceGraphNode *>> res =
223 for (InstanceGraphNode *topModule : res.value()) {
224 for (InstanceGraphNode *node : llvm::post_order(topModule)) {
225 if (visited.count(node))
228 dyn_cast_or_null<hw::HWMutableModuleLike>(*node->getModule());
231 if (failed(PortConverter<HWInoutPortConversionBuilder>(
232 instanceGraph, mutableModule, readSuffix.getValue(),
233 writeSuffix.getValue())
235 return signalPassFailure();
assert(baseType &&"element must be base type")
virtual FailureOr< std::unique_ptr< PortConversion > > build(hw::PortInfo port)
Base class for the port conversion of a particular port.
FailureOr< llvm::ArrayRef< InstanceGraphNode * > > getInferredTopLevelNodes()
Get the nodes corresponding to the inferred top-level modules of a circuit.
BaseTy type_dyn_cast(Type type)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
size_t argNum
This is the argument index or the result index depending on the direction.