CIRCT  19.0.0git
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 
26 #include "circt/Dialect/HW/HWOps.h"
28 #include "circt/Support/LLVM.h"
29 
30 namespace circt {
31 namespace hw {
32 
33 class PortConversionBuilder;
34 class PortConversion;
35 
37 public:
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 
57 protected:
59 
60  std::unique_ptr<PortConversionBuilder> ssb;
61 
62 private:
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.
98 public:
100  : converter(converter), body(converter.getBody()), origPort(origPort) {}
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.
112  void lowerPort() {
115  else
117  }
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 
130 protected:
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.
152 public:
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.
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.
168 template <typename PortConversionBuilderImpl>
170 public:
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
@ Output
Definition: HW.h:35
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.
Definition: PortConverter.h:97
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)
Definition: PortConverter.h:99
virtual LogicalResult init()
MLIRContext * getContext()
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
Definition: PortConverter.h:79
SmallVector< std::pair< unsigned, hw::PortInfo >, 0 > newInputs
Definition: PortConverter.h:85
igraph::InstanceGraphNode * moduleNode
Definition: PortConverter.h:71
SmallVector< std::unique_ptr< PortConversion > > loweredInputs
Definition: PortConverter.h:78
hw::HWMutableModuleLike mod
Definition: PortConverter.h:72
void createNewOutput(hw::PortInfo origPort, const Twine &suffix, Type type, Value output, hw::PortInfo &newPort)
Same as above.
hw::HWMutableModuleLike getModule() const
Definition: PortConverter.h:41
void updateInstance(hw::InstanceOp)
Updates an instance of the module.
std::unique_ptr< PortConversionBuilder > ssb
Definition: PortConverter.h:60
PortConverterImpl(igraph::InstanceGraphNode *moduleNode)
SmallVector< std::pair< unsigned, hw::PortInfo >, 0 > newOutputs
Definition: PortConverter.h:86
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: DebugAnalysis.h:21
Definition: hw.py:1
This holds the name, type, direction of a module's ports.