CIRCT  19.0.0git
FIRRTLUtils.h
Go to the documentation of this file.
1 //===- FIRRTLUtils.h - FIRRTL IR Utilities ----------------------*- 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 // This file defines various utilties to help generate and process FIRRTL IR.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef CIRCT_DIALECT_FIRRTL_FIRRTLUTILS_H
14 #define CIRCT_DIALECT_FIRRTL_FIRRTLUTILS_H
15 
17 #include "mlir/IR/BuiltinOps.h"
18 #include "llvm/Support/Parallel.h"
19 
20 namespace circt {
21 namespace hw {
22 struct InnerSymbolNamespace;
23 } // namespace hw
24 
25 namespace firrtl {
26 /// Emit a connect between two values.
27 void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs);
28 void emitConnect(ImplicitLocOpBuilder &builder, Value lhs, Value rhs);
29 
30 /// Utiility for generating a constant attribute.
31 IntegerAttr getIntAttr(Type type, const APInt &value);
32 
33 /// Utility for generating a constant zero attribute.
34 IntegerAttr getIntZerosAttr(Type type);
35 
36 /// Utility for generating a constant all ones attribute.
37 IntegerAttr getIntOnesAttr(Type type);
38 
39 /// Return the single assignment to a Property value.
40 PropAssignOp getPropertyAssignment(FIRRTLPropertyValue value);
41 
42 /// Return the module-scoped driver of a value only looking through one connect.
43 Value getDriverFromConnect(Value val);
44 
45 /// Return the value that drives another FIRRTL value within module scope. This
46 /// is parameterized by looking through or not through certain constructs.
47 Value getValueSource(Value val, bool lookThroughWires, bool lookThroughNodes,
48  bool lookThroughCasts);
49 
50 /// Return the value that drives another FIRRTL value within module scope. This
51 /// is parameterized by looking through or not through certain constructs. This
52 /// assumes a single driver and should only be run after `ExpandWhens`.
53 Value getModuleScopedDriver(Value val, bool lookThroughWires,
54  bool lookThroughNodes, bool lookThroughCasts);
55 
56 /// Return true if a value is module-scoped driven by a value of a specific
57 /// type.
58 template <typename A, typename... B>
59 static bool isModuleScopedDrivenBy(Value val, bool lookThroughWires,
60  bool lookThroughNodes,
61  bool lookThroughCasts) {
62  val = getModuleScopedDriver(val, lookThroughWires, lookThroughNodes,
63  lookThroughCasts);
64 
65  if (!val)
66  return false;
67 
68  auto *op = val.getDefiningOp();
69  if (!op)
70  return false;
71 
72  return isa<A, B...>(op);
73 }
74 
75 /// Walk all the drivers of a value, passing in the connect operations drive the
76 /// value. If the value is an aggregate it will find connects to subfields. If
77 /// the callback returns false, this function will stop walking. Returns false
78 /// if walking was broken, and true otherwise.
80  llvm::function_ref<bool(const FieldRef &dst, const FieldRef &src)>;
82  bool lookThroughNodes, bool lookThroughCasts,
83  WalkDriverCallback callback);
84 
85 /// Get the FieldRef from a value. This will travel backwards to through the
86 /// IR, following Subfield and Subindex to find the op which declares the
87 /// location. Optionally look through recognized cast operations, which
88 /// likely will result in source having slightly different type.
89 FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts = false);
90 
91 /// Get the delta indexing from a value, as a FieldRef.
92 FieldRef getDeltaRef(Value value, bool lookThroughCasts = false);
93 
94 /// Get a string identifier representing the FieldRef. Return this string and a
95 /// boolean indicating if a valid "root" for the identifier was found. If
96 /// nameSafe is true, this will generate a string that is better suited for
97 /// naming something in the IR. E.g., if the fieldRef is a subfield of a
98 /// subindex, without name safe the output would be:
99 ///
100 /// foo[42].bar
101 ///
102 /// With nameSafe, this would be:
103 ///
104 /// foo_42_bar
105 std::pair<std::string, bool> getFieldName(const FieldRef &fieldRef,
106  bool nameSafe = false);
107 
108 Value getValueByFieldID(ImplicitLocOpBuilder builder, Value value,
109  unsigned fieldID);
110 
111 /// Walk leaf ground types in the `firrtlType` and apply the function `fn`.
112 /// The first argument of `fn` is field ID, and the second argument is a
113 /// leaf ground type, and the third argument indicates if the element was
114 /// flipped in a bundle.
115 void walkGroundTypes(
116  FIRRTLType firrtlType,
117  llvm::function_ref<void(uint64_t, FIRRTLBaseType, bool)> fn);
118 
119 //===----------------------------------------------------------------------===//
120 // Inner symbol and InnerRef helpers.
121 //===----------------------------------------------------------------------===//
122 
123 /// Return the inner sym target for the specified value and fieldID.
124 /// If root is a blockargument, this must be FModuleLike.
126 
127 /// Ensure that the the InnerSymAttr has a symbol on the field specified.
128 /// Returns the updated InnerSymAttr as well as the name of the symbol attached
129 /// to the specified field.
130 std::pair<hw::InnerSymAttr, StringAttr>
131 getOrAddInnerSym(MLIRContext *context, hw::InnerSymAttr attr, uint64_t fieldID,
132  llvm::function_ref<hw::InnerSymbolNamespace &()> getNamespace);
133 
134 /// Returns an inner symbol identifier for the specified target (op or port),
135 /// adding one if necessary.
136 StringAttr
138  llvm::function_ref<hw::InnerSymbolNamespace &()> getNamespace);
139 
141  llvm::function_ref<hw::InnerSymbolNamespace &(FModuleLike mod)>;
142 
143 /// Returns an inner symbol identifier for the specified target (op or port),
144 /// adding one if necessary.
145 StringAttr getOrAddInnerSym(const hw::InnerSymTarget &target,
146  GetNamespaceCallback getNamespace);
147 
148 /// Obtain an inner reference to the target (operation or port),
149 /// adding an inner symbol as necessary.
150 hw::InnerRefAttr getInnerRefTo(const hw::InnerSymTarget &target,
151  GetNamespaceCallback getNamespace);
152 
153 /// Returns an inner symbol identifier for the specified operation, adding one
154 /// if necessary.
155 static inline StringAttr getOrAddInnerSym(Operation *op,
156  GetNamespaceCallback getNamespace) {
157  return getOrAddInnerSym(hw::InnerSymTarget(op), getNamespace);
158 }
159 /// Returns an inner symbol identifier for the specified operation's field
160 /// adding one if necessary.
161 static inline StringAttr getOrAddInnerSym(Operation *op, uint64_t fieldID,
162  GetNamespaceCallback getNamespace) {
163  return getOrAddInnerSym(hw::InnerSymTarget(op, fieldID), getNamespace);
164 }
165 
166 /// Obtain an inner reference to an operation, possibly adding an inner symbol.
167 static inline hw::InnerRefAttr
168 getInnerRefTo(Operation *op, GetNamespaceCallback getNamespace) {
169  return getInnerRefTo(hw::InnerSymTarget(op), getNamespace);
170 }
171 
172 /// Obtain an inner reference to an operation's field, possibly adding an inner
173 /// symbol.
174 static inline hw::InnerRefAttr
175 getInnerRefTo(Operation *op, uint64_t fieldID,
176  GetNamespaceCallback getNamespace) {
177  return getInnerRefTo(hw::InnerSymTarget(op, fieldID), getNamespace);
178 }
179 
180 /// Returns an inner symbol identifier for the specified port, adding one if
181 /// necessary.
182 static inline StringAttr getOrAddInnerSym(FModuleLike mod, size_t portIdx,
183  GetNamespaceCallback getNamespace) {
184  return getOrAddInnerSym(hw::InnerSymTarget(portIdx, mod), getNamespace);
185 }
186 
187 /// Returns an inner symbol identifier for the specified port's field, adding
188 /// one if necessary.
189 static inline StringAttr getOrAddInnerSym(FModuleLike mod, size_t portIdx,
190  uint64_t fieldID,
191  GetNamespaceCallback getNamespace) {
192  return getOrAddInnerSym(hw::InnerSymTarget(portIdx, mod, fieldID),
193  getNamespace);
194 }
195 
196 /// Obtain an inner reference to a port, possibly adding an inner symbol.
197 static inline hw::InnerRefAttr
198 getInnerRefTo(FModuleLike mod, size_t portIdx,
199  GetNamespaceCallback getNamespace) {
200  return getInnerRefTo(hw::InnerSymTarget(portIdx, mod), getNamespace);
201 }
202 
203 /// Obtain an inner reference to a port's field, possibly adding an inner
204 /// symbol.
205 static inline hw::InnerRefAttr
206 getInnerRefTo(FModuleLike mod, size_t portIdx, uint64_t fieldID,
207  GetNamespaceCallback getNamespace) {
208  return getInnerRefTo(hw::InnerSymTarget(portIdx, mod, fieldID), getNamespace);
209 }
210 
211 //===----------------------------------------------------------------------===//
212 // Type utilities
213 //===----------------------------------------------------------------------===//
214 
215 /// If it is a base type, return it as is. If reftype, return wrapped base type.
216 /// Otherwise, return null.
217 inline FIRRTLBaseType getBaseType(Type type) {
218  return TypeSwitch<Type, FIRRTLBaseType>(type)
219  .Case<FIRRTLBaseType>([](auto base) { return base; })
220  .Case<RefType>([](auto ref) { return ref.getType(); })
221  .Default([](Type type) { return nullptr; });
222 }
223 
224 /// Get base type if isa<> the requested type, else null.
225 template <typename T>
226 inline T getBaseOfType(Type type) {
227  return dyn_cast_or_null<T>(getBaseType(type));
228 }
229 
230 /// Return a FIRRTLType with its base type component mutated by the given
231 /// function. (i.e., ref<T> -> ref<f(T)> and T -> f(T)).
233  function_ref<FIRRTLBaseType(FIRRTLBaseType)> fn) {
234  return TypeSwitch<FIRRTLType, FIRRTLType>(type)
235  .Case<FIRRTLBaseType>([&](auto base) { return fn(base); })
236  .Case<RefType>([&](auto ref) {
237  return RefType::get(fn(ref.getType()), ref.getForceable(),
238  ref.getLayer());
239  });
240 }
241 
242 /// Return a FIRRTLType with its base type component mutated by the given
243 /// function. Return null when the function returns null.
244 /// (i.e., ref<T> -> ref<f(T)> if f(T) != null else null, and T -> f(T)).
245 inline FIRRTLType
247  function_ref<FIRRTLBaseType(FIRRTLBaseType)> fn) {
248  return TypeSwitch<FIRRTLType, FIRRTLType>(type)
249  .Case<FIRRTLBaseType>([&](auto base) { return fn(base); })
250  .Case<RefType>([&](auto ref) -> FIRRTLType {
251  auto result = fn(ref.getType());
252  if (!result)
253  return {};
254  return RefType::get(result, ref.getForceable(), ref.getLayer());
255  });
256 }
257 
258 /// Given a type, return the corresponding lowered type for the HW dialect.
259 /// Non-FIRRTL types are simply passed through. This returns a null type if it
260 /// cannot be lowered. The optional function is required to specify how to lower
261 /// AliasTypes.
262 Type lowerType(
263  Type type, std::optional<Location> loc = {},
264  llvm::function_ref<hw::TypeAliasType(Type, BaseTypeAliasType, Location)>
265  getTypeDeclFn = {});
266 
267 //===----------------------------------------------------------------------===//
268 // Parser-related utilities
269 //
270 // These cannot always be relegated to the parser and sometimes need to be
271 // available for passes. This has specifically come up for Annotation lowering
272 // where there is FIRRTL stuff that needs to be parsed out of an annotation.
273 //===----------------------------------------------------------------------===//
274 
275 /// Parse a string that may encode a FIRRTL location into a LocationAttr.
276 std::pair<bool, std::optional<mlir::LocationAttr>> maybeStringToLocation(
277  StringRef spelling, bool skipParsing, StringAttr &locatorFilenameCache,
278  FileLineColLoc &fileLineColLocCache, MLIRContext *context);
279 
280 //===----------------------------------------------------------------------===//
281 // Parallel utilities
282 //===----------------------------------------------------------------------===//
283 
284 /// Wrapper for llvm::parallelTransformReduce that performs the transform_reduce
285 /// serially when MLIR multi-threading is disabled.
286 /// Does not add a ParallelDiagnosticHandler like mlir::parallelFor.
287 template <class IterTy, class ResultTy, class ReduceFuncTy,
288  class TransformFuncTy>
289 static ResultTy transformReduce(MLIRContext *context, IterTy begin, IterTy end,
290  ResultTy init, ReduceFuncTy reduce,
291  TransformFuncTy transform) {
292  // Parallel when enabled
293  if (context->isMultithreadingEnabled())
294  return llvm::parallelTransformReduce(begin, end, init, reduce, transform);
295 
296  // Serial fallback (from llvm::parallelTransformReduce)
297  for (IterTy i = begin; i != end; ++i)
298  init = reduce(std::move(init), transform(*i));
299  return std::move(init);
300 }
301 
302 /// Range wrapper
303 template <class RangeTy, class ResultTy, class ReduceFuncTy,
304  class TransformFuncTy>
305 static ResultTy transformReduce(MLIRContext *context, RangeTy &&r,
306  ResultTy init, ReduceFuncTy reduce,
307  TransformFuncTy transform) {
308  return transformReduce(context, std::begin(r), std::end(r), init, reduce,
309  transform);
310 }
311 
312 } // namespace firrtl
313 } // namespace circt
314 
315 #endif // CIRCT_DIALECT_FIRRTL_FIRRTLUTILS_H
static Value lookThroughWires(Value value)
Trace a value through wires to its original definition.
Builder builder
This class represents a reference to a specific field or element of an aggregate value.
Definition: FieldRef.h:28
The target of an inner symbol, the entity the symbol is a handle for.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Definition: CalyxOps.cpp:54
llvm::function_ref< hw::InnerSymbolNamespace &(FModuleLike mod)> GetNamespaceCallback
Definition: FIRRTLUtils.h:141
FIRRTLType mapBaseTypeNullable(FIRRTLType type, function_ref< FIRRTLBaseType(FIRRTLBaseType)> fn)
Return a FIRRTLType with its base type component mutated by the given function.
Definition: FIRRTLUtils.h:246
FieldRef getDeltaRef(Value value, bool lookThroughCasts=false)
Get the delta indexing from a value, as a FieldRef.
FIRRTLBaseType getBaseType(Type type)
If it is a base type, return it as is.
Definition: FIRRTLUtils.h:217
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Get the FieldRef from a value.
mlir::TypedValue< FIRRTLBaseType > FIRRTLBaseValue
Definition: FIRRTLTypes.h:392
void walkGroundTypes(FIRRTLType firrtlType, llvm::function_ref< void(uint64_t, FIRRTLBaseType, bool)> fn)
Walk leaf ground types in the firrtlType and apply the function fn.
FIRRTLType mapBaseType(FIRRTLType type, function_ref< FIRRTLBaseType(FIRRTLBaseType)> fn)
Return a FIRRTLType with its base type component mutated by the given function.
Definition: FIRRTLUtils.h:232
static bool isModuleScopedDrivenBy(Value val, bool lookThroughWires, bool lookThroughNodes, bool lookThroughCasts)
Return true if a value is module-scoped driven by a value of a specific type.
Definition: FIRRTLUtils.h:59
IntegerAttr getIntAttr(Type type, const APInt &value)
Utiility for generating a constant attribute.
std::pair< bool, std::optional< mlir::LocationAttr > > maybeStringToLocation(llvm::StringRef spelling, bool skipParsing, mlir::StringAttr &locatorFilenameCache, FileLineColLoc &fileLineColLocCache, MLIRContext *context)
std::pair< hw::InnerSymAttr, StringAttr > getOrAddInnerSym(MLIRContext *context, hw::InnerSymAttr attr, uint64_t fieldID, llvm::function_ref< hw::InnerSymbolNamespace &()> getNamespace)
Ensure that the the InnerSymAttr has a symbol on the field specified.
hw::InnerRefAttr getInnerRefTo(const hw::InnerSymTarget &target, GetNamespaceCallback getNamespace)
Obtain an inner reference to the target (operation or port), adding an inner symbol as necessary.
T getBaseOfType(Type type)
Get base type if isa<> the requested type, else null.
Definition: FIRRTLUtils.h:226
PropAssignOp getPropertyAssignment(FIRRTLPropertyValue value)
Return the single assignment to a Property value.
Value getValueSource(Value val, bool lookThroughWires, bool lookThroughNodes, bool lookThroughCasts)
Return the value that drives another FIRRTL value within module scope.
static ResultTy transformReduce(MLIRContext *context, IterTy begin, IterTy end, ResultTy init, ReduceFuncTy reduce, TransformFuncTy transform)
Wrapper for llvm::parallelTransformReduce that performs the transform_reduce serially when MLIR multi...
Definition: FIRRTLUtils.h:289
Value getModuleScopedDriver(Value val, bool lookThroughWires, bool lookThroughNodes, bool lookThroughCasts)
Return the value that drives another FIRRTL value within module scope.
Value getDriverFromConnect(Value val)
Return the module-scoped driver of a value only looking through one connect.
Value getValueByFieldID(ImplicitLocOpBuilder builder, Value value, unsigned fieldID)
This gets the value targeted by a field id.
std::pair< std::string, bool > getFieldName(const FieldRef &fieldRef, bool nameSafe=false)
Get a string identifier representing the FieldRef.
llvm::function_ref< bool(const FieldRef &dst, const FieldRef &src)> WalkDriverCallback
Walk all the drivers of a value, passing in the connect operations drive the value.
Definition: FIRRTLUtils.h:80
mlir::TypedValue< PropertyType > FIRRTLPropertyValue
Definition: FIRRTLTypes.h:393
Type lowerType(Type type, std::optional< Location > loc={}, llvm::function_ref< hw::TypeAliasType(Type, BaseTypeAliasType, Location)> getTypeDeclFn={})
Given a type, return the corresponding lowered type for the HW dialect.
hw::InnerSymTarget getTargetFor(FieldRef ref)
Return the inner sym target for the specified value and fieldID.
bool walkDrivers(FIRRTLBaseValue value, bool lookThroughWires, bool lookThroughNodes, bool lookThroughCasts, WalkDriverCallback callback)
IntegerAttr getIntOnesAttr(Type type)
Utility for generating a constant all ones attribute.
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs)
Emit a connect between two values.
Definition: FIRRTLUtils.cpp:24
IntegerAttr getIntZerosAttr(Type type)
Utility for generating a constant zero attribute.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
Definition: hw.py:1