13 using namespace circt;
17 static StringAttr
append(StringAttr base,
const Twine &suffix) {
18 if (suffix.isTriviallyEmpty())
20 auto *context = base.getContext();
34 isUntouchedFlag =
true;
37 void mapInputSignals(OpBuilder &b, Operation *inst, Value instValue,
38 SmallVectorImpl<Value> &newOperands,
39 ArrayRef<Backedge> newResults)
override {
40 newOperands[portInfo.argNum] = instValue;
42 void mapOutputSignals(OpBuilder &b, Operation *inst, Value instValue,
43 SmallVectorImpl<Value> &newOperands,
44 ArrayRef<Backedge> newResults)
override {
45 instValue.replaceAllUsesWith(newResults[portInfo.argNum]);
49 void buildInputSignals()
override {
51 converter.createNewInput(origPort,
"", origPort.type, portInfo);
53 body->getArgument(origPort.argNum).replaceAllUsesWith(newValue);
56 void buildOutputSignals()
override {
59 output = body->getTerminator()->getOperand(origPort.argNum);
60 converter.createNewOutput(origPort,
"", origPort.type, output, portInfo);
63 hw::PortInfo portInfo;
68 FailureOr<std::unique_ptr<PortConversion>>
72 return {std::make_unique<UntouchedPortConversion>(
converter, port)};
76 : moduleNode(moduleNode), b(moduleNode->getModule()->getContext()) {
78 assert(
mod &&
"PortConverter only works on HWMutableModuleLike");
80 if (
mod->getNumRegions() == 1 &&
mod->getRegion(0).hasOneBlock()) {
81 body = &
mod->getRegion(0).front();
97 return body->addArgument(type, origPort.
loc);
101 Type type, Value output,
113 OpBuilder::InsertionGuard g(
b);
114 b.setInsertionPointToStart(
body);
121 bool foundLoweredPorts =
false;
123 auto createPortLowering = [&](
PortInfo port) {
128 auto loweredPort =
ssb->build(port);
129 if (failed(loweredPort))
132 foundLoweredPorts |= !(*loweredPort)->isUntouched();
133 loweredPorts.emplace_back(std::move(*loweredPort));
135 if (failed(loweredPorts.back()->init()))
143 if (failed(createPortLowering(port)))
147 if (!foundLoweredPorts) {
157 lowering->lowerPort();
159 lowering->lowerPort();
165 SmallVector<unsigned> inputsToErase(
mod.getNumInputPorts());
166 std::iota(inputsToErase.begin(), inputsToErase.end(), 0);
167 SmallVector<unsigned> outputsToErase(
mod.getNumOutputPorts());
168 std::iota(outputsToErase.begin(), outputsToErase.end(), 0);
175 body->eraseArguments([&ports](BlockArgument arg) {
176 return arg.getArgNumber() < ports.
sizeInputs();
185 auto instanceLike = instance->getInstance<hw::HWInstanceLike>();
188 hw::InstanceOp hwInstance = dyn_cast_or_null<hw::InstanceOp>(*instanceLike);
190 return instanceLike->emitOpError(
191 "This code only converts hw.instance instances - ask your friendly "
192 "neighborhood compiler engineers to implement support for something "
193 "like an hw::HWMutableInstanceLike interface");
205 ImplicitLocOpBuilder
b(inst.getLoc(), inst);
211 SmallVector<Backedge> newResults;
213 newResults.push_back(beb.
get(outputPort.type));
216 SmallVector<Value> newOperands(ports.
sizeInputs(), {});
217 for (
size_t oldOpIdx = 0, e = inst.getNumOperands(); oldOpIdx < e; ++oldOpIdx)
219 b, inst, inst->getOperand(oldOpIdx), newOperands, newResults);
222 for (
size_t oldResIdx = 0, e = inst.getNumResults(); oldResIdx < e;
225 b, inst, inst->getResult(oldResIdx), newOperands, newResults);
229 assert(llvm::none_of(newOperands, [](Value v) {
return !v; }));
230 b.setInsertionPointAfter(inst);
232 b.create<InstanceOp>(
mod, inst.getInstanceNameAttr(), newOperands,
233 inst.getParameters(), inst.getInnerSymAttr());
234 newInst->setDialectAttrs(inst->getDialectAttrs());
237 for (
auto [idx, be] : llvm::enumerate(newResults))
238 be.setValue(newInst.getResult(idx));
assert(baseType &&"element must be base type")
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
Instantiate one of these and use it to build typed backedges.
Backedge get(mlir::Type resultType, mlir::LocationAttr optionalLoc={})
Create a typed backedge.
PortConverterImpl & converter
virtual FailureOr< std::unique_ptr< PortConversion > > build(hw::PortInfo port)
Base class for the port conversion of a particular port.
LogicalResult run()
Run port conversion.
SmallVector< std::unique_ptr< PortConversion > > loweredOutputs
SmallVector< std::pair< unsigned, hw::PortInfo >, 0 > newInputs
igraph::InstanceGraphNode * moduleNode
SmallVector< std::unique_ptr< PortConversion > > loweredInputs
hw::HWMutableModuleLike mod
void createNewOutput(hw::PortInfo origPort, const Twine &suffix, Type type, Value output, hw::PortInfo &newPort)
Same as above.
void updateInstance(hw::InstanceOp)
Updates an instance of the module.
std::unique_ptr< PortConversionBuilder > ssb
PortConverterImpl(igraph::InstanceGraphNode *moduleNode)
SmallVector< std::pair< unsigned, hw::PortInfo >, 0 > newOutputs
Value createNewInput(hw::PortInfo origPort, const Twine &suffix, Type type, hw::PortInfo &newPort)
These two methods take care of allocating new ports in the correct place based on the position of 'or...
This is a Node in the InstanceGraph.
auto getModule()
Get the module that this node is tracking.
llvm::iterator_range< UseIterator > uses()
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
This holds a decoded list of input/inout and output ports for a module or instance.
size_t sizeOutputs() const
size_t sizeInputs() const
PortDirectionRange getOutputs()
This holds the name, type, direction of a module's ports.