CIRCT  20.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 /// Get FieldRef pointing to the specified inner symbol target, which must be
128 /// valid. Returns null FieldRef if target points to something with no value,
129 /// such as a port of an external module.
131 
132 /// Ensure that the the InnerSymAttr has a symbol on the field specified.
133 /// Returns the updated InnerSymAttr as well as the name of the symbol attached
134 /// to the specified field.
135 std::pair<hw::InnerSymAttr, StringAttr>
136 getOrAddInnerSym(MLIRContext *context, hw::InnerSymAttr attr, uint64_t fieldID,
137  llvm::function_ref<hw::InnerSymbolNamespace &()> getNamespace);
138 
139 /// Returns an inner symbol identifier for the specified target (op or port),
140 /// adding one if necessary.
141 StringAttr
143  llvm::function_ref<hw::InnerSymbolNamespace &()> getNamespace);
144 
146  llvm::function_ref<hw::InnerSymbolNamespace &(FModuleLike mod)>;
147 
148 /// Returns an inner symbol identifier for the specified target (op or port),
149 /// adding one if necessary.
150 StringAttr getOrAddInnerSym(const hw::InnerSymTarget &target,
151  GetNamespaceCallback getNamespace);
152 
153 /// Obtain an inner reference to the target (operation or port),
154 /// adding an inner symbol as necessary.
155 hw::InnerRefAttr getInnerRefTo(const hw::InnerSymTarget &target,
156  GetNamespaceCallback getNamespace);
157 
158 /// Returns an inner symbol identifier for the specified operation, adding one
159 /// if necessary.
160 static inline StringAttr getOrAddInnerSym(Operation *op,
161  GetNamespaceCallback getNamespace) {
162  return getOrAddInnerSym(hw::InnerSymTarget(op), getNamespace);
163 }
164 /// Returns an inner symbol identifier for the specified operation's field
165 /// adding one if necessary.
166 static inline StringAttr getOrAddInnerSym(Operation *op, uint64_t fieldID,
167  GetNamespaceCallback getNamespace) {
168  return getOrAddInnerSym(hw::InnerSymTarget(op, fieldID), getNamespace);
169 }
170 
171 /// Obtain an inner reference to an operation, possibly adding an inner symbol.
172 static inline hw::InnerRefAttr
173 getInnerRefTo(Operation *op, GetNamespaceCallback getNamespace) {
174  return getInnerRefTo(hw::InnerSymTarget(op), getNamespace);
175 }
176 
177 /// Obtain an inner reference to an operation's field, possibly adding an inner
178 /// symbol.
179 static inline hw::InnerRefAttr
180 getInnerRefTo(Operation *op, uint64_t fieldID,
181  GetNamespaceCallback getNamespace) {
182  return getInnerRefTo(hw::InnerSymTarget(op, fieldID), getNamespace);
183 }
184 
185 /// Returns an inner symbol identifier for the specified port, adding one if
186 /// necessary.
187 static inline StringAttr getOrAddInnerSym(FModuleLike mod, size_t portIdx,
188  GetNamespaceCallback getNamespace) {
189  return getOrAddInnerSym(hw::InnerSymTarget(portIdx, mod), getNamespace);
190 }
191 
192 /// Returns an inner symbol identifier for the specified port's field, adding
193 /// one if necessary.
194 static inline StringAttr getOrAddInnerSym(FModuleLike mod, size_t portIdx,
195  uint64_t fieldID,
196  GetNamespaceCallback getNamespace) {
197  return getOrAddInnerSym(hw::InnerSymTarget(portIdx, mod, fieldID),
198  getNamespace);
199 }
200 
201 /// Obtain an inner reference to a port, possibly adding an inner symbol.
202 static inline hw::InnerRefAttr
203 getInnerRefTo(FModuleLike mod, size_t portIdx,
204  GetNamespaceCallback getNamespace) {
205  return getInnerRefTo(hw::InnerSymTarget(portIdx, mod), getNamespace);
206 }
207 
208 /// Obtain an inner reference to a port's field, possibly adding an inner
209 /// symbol.
210 static inline hw::InnerRefAttr
211 getInnerRefTo(FModuleLike mod, size_t portIdx, uint64_t fieldID,
212  GetNamespaceCallback getNamespace) {
213  return getInnerRefTo(hw::InnerSymTarget(portIdx, mod, fieldID), getNamespace);
214 }
215 
216 //===----------------------------------------------------------------------===//
217 // Type utilities
218 //===----------------------------------------------------------------------===//
219 
220 /// If it is a base type, return it as is. If reftype, return wrapped base type.
221 /// Otherwise, return null.
222 inline FIRRTLBaseType getBaseType(Type type) {
223  return TypeSwitch<Type, FIRRTLBaseType>(type)
224  .Case<FIRRTLBaseType>([](auto base) { return base; })
225  .Case<LHSType>([](auto lhs) { return lhs.getType(); })
226  .Case<RefType>([](auto ref) { return ref.getType(); })
227  .Default([](Type type) { return nullptr; });
228 }
229 
230 /// Get base type if isa<> the requested type, else null.
231 template <typename T>
232 inline T getBaseOfType(Type type) {
233  return dyn_cast_or_null<T>(getBaseType(type));
234 }
235 
236 /// Return a FIRRTLType with its base type component mutated by the given
237 /// function. (i.e., ref<T> -> ref<f(T)> and T -> f(T)).
239  function_ref<FIRRTLBaseType(FIRRTLBaseType)> fn) {
240  return TypeSwitch<FIRRTLType, FIRRTLType>(type)
241  .Case<FIRRTLBaseType>([&](auto base) { return fn(base); })
242  .Case<RefType>([&](auto ref) {
243  return RefType::get(fn(ref.getType()), ref.getForceable(),
244  ref.getLayer());
245  });
246 }
247 
248 /// Return a FIRRTLType with its base type component mutated by the given
249 /// function. Return null when the function returns null.
250 /// (i.e., ref<T> -> ref<f(T)> if f(T) != null else null, and T -> f(T)).
251 inline FIRRTLType
253  function_ref<FIRRTLBaseType(FIRRTLBaseType)> fn) {
254  return TypeSwitch<FIRRTLType, FIRRTLType>(type)
255  .Case<FIRRTLBaseType>([&](auto base) { return fn(base); })
256  .Case<RefType>([&](auto ref) -> FIRRTLType {
257  auto result = fn(ref.getType());
258  if (!result)
259  return {};
260  return RefType::get(result, ref.getForceable(), ref.getLayer());
261  });
262 }
263 
264 /// Given a type, return the corresponding lowered type for the HW dialect.
265 /// Non-FIRRTL types are simply passed through. This returns a null type if it
266 /// cannot be lowered. The optional function is required to specify how to lower
267 /// AliasTypes.
268 Type lowerType(
269  Type type, std::optional<Location> loc = {},
270  llvm::function_ref<hw::TypeAliasType(Type, BaseTypeAliasType, Location)>
271  getTypeDeclFn = {});
272 
273 //===----------------------------------------------------------------------===//
274 // Parser-related utilities
275 //
276 // These cannot always be relegated to the parser and sometimes need to be
277 // available for passes. This has specifically come up for Annotation lowering
278 // where there is FIRRTL stuff that needs to be parsed out of an annotation.
279 //===----------------------------------------------------------------------===//
280 
281 /// Parse a string that may encode a FIRRTL location into a LocationAttr.
282 std::pair<bool, std::optional<mlir::LocationAttr>> maybeStringToLocation(
283  StringRef spelling, bool skipParsing, StringAttr &locatorFilenameCache,
284  FileLineColLoc &fileLineColLocCache, MLIRContext *context);
285 
286 //===----------------------------------------------------------------------===//
287 // Parallel utilities
288 //===----------------------------------------------------------------------===//
289 
290 /// Wrapper for llvm::parallelTransformReduce that performs the transform_reduce
291 /// serially when MLIR multi-threading is disabled.
292 /// Does not add a ParallelDiagnosticHandler like mlir::parallelFor.
293 template <class IterTy, class ResultTy, class ReduceFuncTy,
294  class TransformFuncTy>
295 static ResultTy transformReduce(MLIRContext *context, IterTy begin, IterTy end,
296  ResultTy init, ReduceFuncTy reduce,
297  TransformFuncTy transform) {
298  // Parallel when enabled
299  if (context->isMultithreadingEnabled())
300  return llvm::parallelTransformReduce(begin, end, init, reduce, transform);
301 
302  // Serial fallback (from llvm::parallelTransformReduce)
303  for (IterTy i = begin; i != end; ++i)
304  init = reduce(std::move(init), transform(*i));
305  return std::move(init);
306 }
307 
308 /// Range wrapper
309 template <class RangeTy, class ResultTy, class ReduceFuncTy,
310  class TransformFuncTy>
311 static ResultTy transformReduce(MLIRContext *context, RangeTy &&r,
312  ResultTy init, ReduceFuncTy reduce,
313  TransformFuncTy transform) {
314  return transformReduce(context, std::begin(r), std::end(r), init, reduce,
315  transform);
316 }
317 
318 //===----------------------------------------------------------------------===//
319 // File utilities
320 //===----------------------------------------------------------------------===//
321 
322 /// Truncate `a` to the common prefix of `a` and `b`.
323 void makeCommonPrefix(SmallString<64> &a, StringRef b);
324 
325 //===----------------------------------------------------------------------===//
326 // Object related utilities
327 //===----------------------------------------------------------------------===//
328 
329 /// Add the tracker annotation to the op and get a PathOp to the op.
330 PathOp createPathRef(Operation *op, hw::HierPathOp nla,
331  mlir::ImplicitLocOpBuilder &builderOM);
332 
333 } // namespace firrtl
334 } // namespace circt
335 
336 #endif // CIRCT_DIALECT_FIRRTL_FIRRTLUTILS_H
static Value lookThroughWires(Value value)
Trace a value through wires to its original definition.
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:55
llvm::function_ref< hw::InnerSymbolNamespace &(FModuleLike mod)> GetNamespaceCallback
Definition: FIRRTLUtils.h:146
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:252
FieldRef getFieldRefForTarget(const hw::InnerSymTarget &ist)
Get FieldRef pointing to the specified inner symbol target, which must be valid.
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:222
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Get the FieldRef from a value.
mlir::TypedValue< FIRRTLBaseType > FIRRTLBaseValue
Definition: FIRRTLTypes.h:394
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:238
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
PathOp createPathRef(Operation *op, hw::HierPathOp nla, mlir::ImplicitLocOpBuilder &builderOM)
Add the tracker annotation to the op and get a PathOp to the op.
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:232
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:295
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:395
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:25
void makeCommonPrefix(SmallString< 64 > &a, StringRef b)
Truncate a to the common prefix of a and b.
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