CIRCT 24.0.0git
Loading...
Searching...
No Matches
PortConverter.h
Go to the documentation of this file.
1//===- PortConverter.h - Module I/O rewriting utility -----------*- C++ -*-===//
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// The PortConverter is a utility class for rewriting arguments of a
10// HWMutableModuleLike operation.
11// It is intended to be a generic utility that can facilitate replacement of
12// a given module in- or output to an arbitrary set of new inputs and outputs
13// (i.e. 1 port -> N in, M out ports). Typical usecases is where an in (or
14// output) of a module represents some higher-level abstraction that will be
15// implemented by a set of lower-level in- and outputs ports + supporting
16// operations within a module. It also attempts to do so in an optimal way, by
17// e.g. being able to collect multiple port modifications of a module, and
18// perform them all at once.
19//
20//===----------------------------------------------------------------------===//
21
22#ifndef CIRCT_DIALECT_HW_PORTCONVERTER_H
23#define CIRCT_DIALECT_HW_PORTCONVERTER_H
24
28#include "circt/Support/LLVM.h"
29
30namespace circt {
31namespace hw {
32
33class PortConversionBuilder;
34class PortConversion;
35
36/// Controls whether a newly created port inherits the original port's
37/// attributes.
39
41public:
42 /// Run port conversion.
43 LogicalResult run();
44 Block *getBody() const { return body; }
45 hw::HWMutableModuleLike getModule() const { return mod; }
46
47 /// These two methods take care of allocating new ports in the correct place
48 /// based on the position of 'origPort'. The new port is based on the original
49 /// name and suffix. The specification for the new port is given by `newPort`
50 /// and is recorded internally. `attrPolicy` controls whether the new port
51 /// inherits the original port's attributes. Any changes to 'newPort' after
52 /// calling this will not be reflected in the modules new port list. Will also
53 /// add the new input to the block arguments of the body of the module.
54 Value createNewInput(hw::PortInfo origPort, const Twine &suffix, Type type,
55 hw::PortInfo &newPort,
57 /// Same as above. 'output' is the value fed into the new port and is required
58 /// if 'body' is non-null. Important note: cannot be a backedge which gets
59 /// replaced since this isn't attached to an op until later in the pass.
60 void createNewOutput(hw::PortInfo origPort, const Twine &suffix, Type type,
61 Value output, hw::PortInfo &newPort,
63
64protected:
66
67 std::unique_ptr<PortConversionBuilder> ssb;
68
69private:
70 /// Updates an instance of the module. This is called after the module has
71 /// been updated. It will update the instance to match the new port
72 void updateInstance(hw::InstanceOp);
73
74 // If the module has a block and it wants to be modified, this'll be
75 // non-null.
76 Block *body = nullptr;
77
79 hw::HWMutableModuleLike mod;
80 OpBuilder b;
81
82 // Keep around a reference to the specific port conversion classes to
83 // facilitate updating the instance ops. Indexed by the original port
84 // location.
85 SmallVector<std::unique_ptr<PortConversion>> loweredInputs;
86 SmallVector<std::unique_ptr<PortConversion>> loweredOutputs;
87
88 // Tracking information to modify the module. Populated by the
89 // 'createNew(Input|Output)' methods. Will be cleared once port changes have
90 // materialized. Default length is 0 to save memory in case we'll be keeping
91 // this around for later use.
92 SmallVector<std::pair<unsigned, hw::PortInfo>, 0> newInputs;
93 SmallVector<std::pair<unsigned, hw::PortInfo>, 0> newOutputs;
94
95 // Maintain a handle to the terminator of the body, if any. This will get
96 // continuously updated during port conversion whenever a new output is added
97 // to the module.
98 Operation *terminator = nullptr;
99};
100
101/// Base class for the port conversion of a particular port. Abstracts the
102/// details of a particular port conversion from the port layout. Subclasses
103/// keep around port mapping information to use when updating instances.
105public:
108 virtual ~PortConversion() = default;
109
110 // An optional initialization step that can be overridden by subclasses.
111 // This allows subclasses to perform a failable post-construction
112 // initialization step.
113 virtual LogicalResult init() { return success(); }
114
115 // Lower the specified port into a wire-level signaling protocol. The two
116 // virtual methods 'build*Signals' should be overridden by subclasses. They
117 // should use the 'create*' methods in 'PortConverter' to create the
118 // necessary ports.
125
126 /// Update an instance port to the new port information.
127 virtual void mapInputSignals(OpBuilder &b, Operation *inst, Value instValue,
128 SmallVectorImpl<Value> &newOperands,
129 ArrayRef<Backedge> newResults) = 0;
130 virtual void mapOutputSignals(OpBuilder &b, Operation *inst, Value instValue,
131 SmallVectorImpl<Value> &newOperands,
132 ArrayRef<Backedge> newResults) = 0;
133
134 MLIRContext *getContext() { return getModule()->getContext(); }
135 bool isUntouched() const { return isUntouchedFlag; }
136
137protected:
138 // Build the input and output signals for the port. This pertains to modifying
139 // the module itself.
140 virtual void buildInputSignals() = 0;
141 virtual void buildOutputSignals() = 0;
142
144 Block *body;
146
147 hw::HWMutableModuleLike getModule() { return converter.getModule(); }
148
149 // We don't need full LLVM-style RTTI support for PortConversion (would
150 // require some mechanism of registering user-provided PortConversion-derived
151 // classes), we only need to dynamically tell whether any given PortConversion
152 // is the UntouchedPortConversion.
153 bool isUntouchedFlag = false;
154};
155
156// A PortConversionBuilder will, given an input type, build the appropriate
157// port conversion for that type.
159public:
161 virtual ~PortConversionBuilder() = default;
162
163 // Builds the appropriate port conversion for the port. Users should
164 // override this method with their own llvm::TypeSwitch-based dispatch code,
165 // and by default call this method when no port conversion applies.
166 virtual FailureOr<std::unique_ptr<PortConversion>> build(hw::PortInfo port);
167
169};
170
171// A PortConverter wraps a single HWMutableModuleLike operation, and is
172// initialized from an instance graph node. The port converter is templated
173// on a PortConversionBuilder, which is used to build the appropriate
174// port conversion for each port type.
175template <typename PortConversionBuilderImpl>
177public:
178 template <typename... Args>
179 PortConverter(hw::InstanceGraph &graph, hw::HWMutableModuleLike mod,
180 Args &&...args)
181 : PortConverterImpl(graph.lookup(cast<hw::HWModuleLike>(*mod))) {
182 ssb = std::make_unique<PortConversionBuilderImpl>(*this, args...);
183 }
184};
185
186} // namespace hw
187} // namespace circt
188
189#endif // CIRCT_DIALECT_HW_PORTCONVERTER_H
HW-specific instance graph with a virtual entry node linking to all publicly visible modules.
PortConversionBuilder(PortConverterImpl &converter)
virtual FailureOr< std::unique_ptr< PortConversion > > build(hw::PortInfo port)
virtual ~PortConversionBuilder()=default
Base class for the port conversion of a particular port.
virtual void buildInputSignals()=0
virtual void mapInputSignals(OpBuilder &b, Operation *inst, Value instValue, SmallVectorImpl< Value > &newOperands, ArrayRef< Backedge > newResults)=0
Update an instance port to the new port information.
virtual ~PortConversion()=default
PortConversion(PortConverterImpl &converter, hw::PortInfo origPort)
virtual LogicalResult init()
PortConverterImpl & converter
virtual void mapOutputSignals(OpBuilder &b, Operation *inst, Value instValue, SmallVectorImpl< Value > &newOperands, ArrayRef< Backedge > newResults)=0
virtual void buildOutputSignals()=0
hw::HWMutableModuleLike getModule()
void createNewOutput(hw::PortInfo origPort, const Twine &suffix, Type type, Value output, hw::PortInfo &newPort, PortAttrPolicy attrPolicy=PortAttrPolicy::Drop)
Same as above.
LogicalResult run()
Run port conversion.
SmallVector< std::unique_ptr< PortConversion > > loweredOutputs
SmallVector< std::pair< unsigned, hw::PortInfo >, 0 > newInputs
igraph::InstanceGraphNode * moduleNode
Value createNewInput(hw::PortInfo origPort, const Twine &suffix, Type type, hw::PortInfo &newPort, PortAttrPolicy attrPolicy=PortAttrPolicy::Drop)
These two methods take care of allocating new ports in the correct place based on the position of 'or...
SmallVector< std::unique_ptr< PortConversion > > loweredInputs
hw::HWMutableModuleLike mod
hw::HWMutableModuleLike getModule() const
void updateInstance(hw::InstanceOp)
Updates an instance of the module.
std::unique_ptr< PortConversionBuilder > ssb
SmallVector< std::pair< unsigned, hw::PortInfo >, 0 > newOutputs
PortConverter(hw::InstanceGraph &graph, hw::HWMutableModuleLike mod, Args &&...args)
This is a Node in the InstanceGraph.
PortAttrPolicy
Controls whether a newly created port inherits the original port's attributes.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition hw.py:1
This holds the name, type, direction of a module's ports.