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"
27 using namespace circt;
30 using namespace igraph;
34 struct HWEliminateInOutPortsPass
35 :
public circt::sv::impl::HWEliminateInOutPortsBase<
36 HWEliminateInOutPortsPass> {
37 using HWEliminateInOutPortsBase<
38 HWEliminateInOutPortsPass>::HWEliminateInOutPortsBase;
39 void runOnOperation()
override;
45 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 llvm::StringRef readSuffix;
75 llvm::StringRef writeSuffix;
80 llvm::StringRef readSuffix,
81 llvm::StringRef writeSuffix)
83 writeSuffix(writeSuffix) {}
85 LogicalResult HWInOutPortConversion::init() {
87 for (
auto *user : body->getArgument(origPort.argNum).getUsers()) {
88 if (
auto read = dyn_cast<sv::ReadInOutOp>(user))
89 readers.push_back(read);
90 else if (
auto write = dyn_cast<sv::AssignOp>(user))
91 writers.push_back(write);
93 return user->emitOpError() <<
"uses hw.inout port " << origPort.name
94 <<
" but the operation itself is unsupported.";
97 if (writers.size() > 1)
98 return converter.
getModule()->emitOpError()
99 <<
"multiple writers of inout port " << origPort.name
100 <<
" is unsupported.";
105 void HWInOutPortConversion::buildInputSignals() {
109 converter.createNewInput(origPort, readSuffix, origPort.type, readPort);
110 Value origInput = body->getArgument(origPort.argNum);
111 for (
auto *user : llvm::make_early_inc_range(origInput.getUsers())) {
116 read.replaceAllUsesWith(readValue);
124 converter.createNewOutput(origPort, writeSuffix, origPort.type,
130 void HWInOutPortConversion::buildOutputSignals() {
132 "`hw.inout` outputs not yet supported. Currently, `hw.inout` "
133 "outputs are handled by UntouchedPortConversion, given that "
134 "output `hw.inout` ports have a `ModulePort::Direction::Output` "
135 "direction instead of `ModulePort::Direction::InOut`. If this for "
136 "some reason changes, then this assert will fire.");
139 void HWInOutPortConversion::mapInputSignals(OpBuilder &b, Operation *inst,
141 SmallVectorImpl<Value> &newOperands,
142 ArrayRef<Backedge> newResults) {
147 newOperands[readPort.argNum] =
148 b.create<
ReadInOutOp>(inst->getLoc(), instValue).getResult();
154 Value writeFromInsideMod = newResults[
writePort.argNum];
155 b.create<
sv::AssignOp>(inst->getLoc(), instValue, writeFromInsideMod);
159 void HWInOutPortConversion::mapOutputSignals(
160 OpBuilder &b, Operation *inst, Value instValue,
161 SmallVectorImpl<Value> &newOperands, ArrayRef<Backedge> newResults) {
164 "`hw.inout` outputs not yet supported. Currently, `hw.inout` "
165 "outputs are handled by UntouchedPortConversion, given that "
166 "output `hw.inout` ports have a `ModulePort::Direction::Output` "
167 "direction instead of `ModulePort::Direction::InOut`. If this for "
168 "some reason changes, then this assert will fire.");
174 llvm::StringRef readSuffix,
175 llvm::StringRef writeSuffix)
177 writeSuffix(writeSuffix) {}
179 FailureOr<std::unique_ptr<PortConversion>>
build(hw::PortInfo port)
override {
181 return {std::make_unique<HWInOutPortConversion>(converter, port,
182 readSuffix, writeSuffix)};
187 llvm::StringRef readSuffix;
188 llvm::StringRef writeSuffix;
193 void HWEliminateInOutPortsPass::runOnOperation() {
196 getAnalysis<circt::hw::InstanceGraph>();
197 llvm::DenseSet<InstanceGraphNode *> visited;
198 FailureOr<llvm::ArrayRef<InstanceGraphNode *>> res =
222 if (visited.count(node))
225 dyn_cast_or_null<hw::HWMutableModuleLike>(*node->getModule());
229 instanceGraph, mutableModule, readSuffix.getValue(),
230 writeSuffix.getValue())
232 return signalPassFailure();
238 const HWEliminateInOutPortsOptions &options) {
239 return std::make_unique<HWEliminateInOutPortsPass>(options);
assert(baseType &&"element must be base type")
static void writePort(uint16_t port)
Write the port number to a file.
HW-specific instance graph with a virtual entry node linking to all publicly visible modules.
virtual FailureOr< std::unique_ptr< PortConversion > > build(hw::PortInfo port)
Base class for the port conversion of a particular port.
hw::HWMutableModuleLike getModule()
LogicalResult run()
Run port conversion.
This is a Node in the InstanceGraph.
FailureOr< llvm::ArrayRef< InstanceGraphNode * > > getInferredTopLevelNodes()
Get the nodes corresponding to the inferred top-level modules of a circuit.
std::unique_ptr< mlir::Pass > createHWEliminateInOutPortsPass(const HWEliminateInOutPortsOptions &options={})
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
This holds the name, type, direction of a module's ports.