13 using namespace circt;
17 static StringAttr
append(StringAttr base,
const Twine &suffix) {
18 if (suffix.isTriviallyEmpty())
20 auto *context = base.getContext();
29 class UntouchedPortConversion :
public PortConversion {
31 UntouchedPortConversion(PortConverterImpl &converter, hw::PortInfo origPort)
32 : PortConversion(converter, origPort) {
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;
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)
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.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
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.