CIRCT 20.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
37public:
38 /// Run port conversion.
39 LogicalResult run();
40 Block *getBody() const { return body; }
41 hw::HWMutableModuleLike getModule() const { return mod; }
42
43 /// These two methods take care of allocating new ports in the correct place
44 /// based on the position of 'origPort'. The new port is based on the original
45 /// name and suffix. The specification for the new port is given by `newPort`
46 /// and is recorded internally. Any changes to 'newPort' after calling this
47 /// will not be reflected in the modules new port list. Will also add the new
48 /// input to the block arguments of the body of the module.
49 Value createNewInput(hw::PortInfo origPort, const Twine &suffix, Type type,
50 hw::PortInfo &newPort);
51 /// Same as above. 'output' is the value fed into the new port and is required
52 /// if 'body' is non-null. Important note: cannot be a backedge which gets
53 /// replaced since this isn't attached to an op until later in the pass.
54 void createNewOutput(hw::PortInfo origPort, const Twine &suffix, Type type,
55 Value output, hw::PortInfo &newPort);
56
57protected:
59
60 std::unique_ptr<PortConversionBuilder> ssb;
61
62private:
63 /// Updates an instance of the module. This is called after the module has
64 /// been updated. It will update the instance to match the new port
65 void updateInstance(hw::InstanceOp);
66
67 // If the module has a block and it wants to be modified, this'll be
68 // non-null.
69 Block *body = nullptr;
70
72 hw::HWMutableModuleLike mod;
73 OpBuilder b;
74
75 // Keep around a reference to the specific port conversion classes to
76 // facilitate updating the instance ops. Indexed by the original port
77 // location.
78 SmallVector<std::unique_ptr<PortConversion>> loweredInputs;
79 SmallVector<std::unique_ptr<PortConversion>> loweredOutputs;
80
81 // Tracking information to modify the module. Populated by the
82 // 'createNew(Input|Output)' methods. Will be cleared once port changes have
83 // materialized. Default length is 0 to save memory in case we'll be keeping
84 // this around for later use.
85 SmallVector<std::pair<unsigned, hw::PortInfo>, 0> newInputs;
86 SmallVector<std::pair<unsigned, hw::PortInfo>, 0> newOutputs;
87
88 // Maintain a handle to the terminator of the body, if any. This will get
89 // continuously updated during port conversion whenever a new output is added
90 // to the module.
91 Operation *terminator = nullptr;
92};
93
94/// Base class for the port conversion of a particular port. Abstracts the
95/// details of a particular port conversion from the port layout. Subclasses
96/// keep around port mapping information to use when updating instances.
98public:
101 virtual ~PortConversion() = default;
102
103 // An optional initialization step that can be overridden by subclasses.
104 // This allows subclasses to perform a failable post-construction
105 // initialization step.
106 virtual LogicalResult init() { return success(); }
107
108 // Lower the specified port into a wire-level signaling protocol. The two
109 // virtual methods 'build*Signals' should be overridden by subclasses. They
110 // should use the 'create*' methods in 'PortConverter' to create the
111 // necessary ports.
118
119 /// Update an instance port to the new port information.
120 virtual void mapInputSignals(OpBuilder &b, Operation *inst, Value instValue,
121 SmallVectorImpl<Value> &newOperands,
122 ArrayRef<Backedge> newResults) = 0;
123 virtual void mapOutputSignals(OpBuilder &b, Operation *inst, Value instValue,
124 SmallVectorImpl<Value> &newOperands,
125 ArrayRef<Backedge> newResults) = 0;
126
127 MLIRContext *getContext() { return getModule()->getContext(); }
128 bool isUntouched() const { return isUntouchedFlag; }
129
130protected:
131 // Build the input and output signals for the port. This pertains to modifying
132 // the module itself.
133 virtual void buildInputSignals() = 0;
134 virtual void buildOutputSignals() = 0;
135
137 Block *body;
139
140 hw::HWMutableModuleLike getModule() { return converter.getModule(); }
141
142 // We don't need full LLVM-style RTTI support for PortConversion (would
143 // require some mechanism of registering user-provided PortConversion-derived
144 // classes), we only need to dynamically tell whether any given PortConversion
145 // is the UntouchedPortConversion.
146 bool isUntouchedFlag = false;
147}; // namespace hw
148
149// A PortConversionBuilder will, given an input type, build the appropriate
150// port conversion for that type.
152public:
154 virtual ~PortConversionBuilder() = default;
155
156 // Builds the appropriate port conversion for the port. Users should
157 // override this method with their own llvm::TypeSwitch-based dispatch code,
158 // and by default call this method when no port conversion applies.
159 virtual FailureOr<std::unique_ptr<PortConversion>> build(hw::PortInfo port);
160
162};
163
164// A PortConverter wraps a single HWMutableModuleLike operation, and is
165// initialized from an instance graph node. The port converter is templated
166// on a PortConversionBuilder, which is used to build the appropriate
167// port conversion for each port type.
168template <typename PortConversionBuilderImpl>
170public:
171 template <typename... Args>
172 PortConverter(hw::InstanceGraph &graph, hw::HWMutableModuleLike mod,
173 Args &&...args)
174 : PortConverterImpl(graph.lookup(cast<hw::HWModuleLike>(*mod))) {
175 ssb = std::make_unique<PortConversionBuilderImpl>(*this, args...);
176 }
177};
178
179} // namespace hw
180} // namespace circt
181
182#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()
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.
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
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...
PortConverter(hw::InstanceGraph &graph, hw::HWMutableModuleLike mod, Args &&...args)
This is a Node in the InstanceGraph.
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.