CIRCT 23.0.0git
Loading...
Searching...
No Matches
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
18#include "mlir/IR/BuiltinOps.h"
19
20namespace circt {
21namespace hw {
22struct InnerSymbolNamespace;
23} // namespace hw
24
25namespace firrtl {
26/// Emit a connect between two values.
27void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs);
28void emitConnect(ImplicitLocOpBuilder &builder, Value lhs, Value rhs);
29
30/// Utiility for generating a constant attribute.
31IntegerAttr getIntAttr(Type type, const APInt &value);
32
33/// Utility for generating a constant zero attribute.
34IntegerAttr getIntZerosAttr(Type type);
35
36/// Utility for generating a constant all ones attribute.
37IntegerAttr getIntOnesAttr(Type type);
38
39/// Return the single assignment to a Property value.
41
42/// Return the module-scoped driver of a value only looking through one connect.
43Value 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.
47Value 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`.
53Value getModuleScopedDriver(Value val, bool lookThroughWires,
54 bool lookThroughNodes, bool lookThroughCasts);
55
56//===----------------------------------------------------------------------===//
57// TieOffCache
58//===----------------------------------------------------------------------===//
59
60/// Helper class to cache tie-off values for different FIRRTL types.
61/// This avoids creating duplicate InvalidValueOp or UnknownValueOp for the
62/// same type.
64public:
65 TieOffCache(ImplicitLocOpBuilder &builder) : builder(builder) {}
66
67 /// Get or create an UnknownValueOp for the given property type.
68 Value getUnknown(PropertyType type);
69
70private:
71 ImplicitLocOpBuilder &builder;
73};
74
75// Instance choice option case macro name utilities.
77public:
78 InstanceChoiceMacroTable(Operation *op);
79
80 // Get the macro for an option case. Return null if it doesn't exist.
81 FlatSymbolRefAttr getMacro(StringAttr optionName, StringAttr caseName) const;
82
83 // Get all option/case pairs in the IR occurrence order.
84 auto getKeys() const { return cache.keys(); }
85
86private:
87 // Option/Case -> Macro Symbol
89};
90
91//===----------------------------------------------------------------------===//
92// Template utilities
93//===----------------------------------------------------------------------===//
94
95/// Return true if a value is module-scoped driven by a value of a specific
96/// type.
97template <typename A, typename... B>
98static bool isModuleScopedDrivenBy(Value val, bool lookThroughWires,
99 bool lookThroughNodes,
100 bool lookThroughCasts) {
101 val = getModuleScopedDriver(val, lookThroughWires, lookThroughNodes,
102 lookThroughCasts);
103
104 if (!val)
105 return false;
106
107 auto *op = val.getDefiningOp();
108 if (!op)
109 return false;
110
111 return isa<A, B...>(op);
112}
113
114/// Walk all the drivers of a value, passing in the connect operations drive the
115/// value. If the value is an aggregate it will find connects to subfields. If
116/// the callback returns false, this function will stop walking. Returns false
117/// if walking was broken, and true otherwise.
119 llvm::function_ref<bool(const FieldRef &dst, const FieldRef &src)>;
121 bool lookThroughNodes, bool lookThroughCasts,
122 WalkDriverCallback callback);
123
124/// Get the FieldRef from a value. This will travel backwards to through the
125/// IR, following Subfield and Subindex to find the op which declares the
126/// location. Optionally look through recognized cast operations, which
127/// likely will result in source having slightly different type.
128FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts = false);
129
130/// Get the delta indexing from a value, as a FieldRef.
131FieldRef getDeltaRef(Value value, bool lookThroughCasts = false);
132
133/// Get a string identifier representing the FieldRef. Return this string and a
134/// boolean indicating if a valid "root" for the identifier was found. If
135/// nameSafe is true, this will generate a string that is better suited for
136/// naming something in the IR. E.g., if the fieldRef is a subfield of a
137/// subindex, without name safe the output would be:
138///
139/// foo[42].bar
140///
141/// With nameSafe, this would be:
142///
143/// foo_42_bar
144std::pair<std::string, bool> getFieldName(const FieldRef &fieldRef,
145 bool nameSafe = false);
146
147Value getValueByFieldID(ImplicitLocOpBuilder builder, Value value,
148 unsigned fieldID);
149
150/// Walk leaf ground types in the `firrtlType` and apply the function `fn`.
151/// The first argument of `fn` is field ID, and the second argument is a
152/// leaf ground type, and the third argument indicates if the element was
153/// flipped in a bundle.
154void walkGroundTypes(
155 FIRRTLType firrtlType,
156 llvm::function_ref<void(uint64_t, FIRRTLBaseType, bool)> fn);
157
158//===----------------------------------------------------------------------===//
159// Inner symbol and InnerRef helpers.
160//===----------------------------------------------------------------------===//
161
162/// Return the inner sym target for the specified value and fieldID.
163/// If root is a blockargument, this must be FModuleLike.
165
166/// Get FieldRef pointing to the specified inner symbol target, which must be
167/// valid. Returns null FieldRef if target points to something with no value,
168/// such as a port of an external module.
170
171/// Ensure that the the InnerSymAttr has a symbol on the field specified.
172/// Returns the updated InnerSymAttr as well as the name of the symbol attached
173/// to the specified field.
174std::pair<hw::InnerSymAttr, StringAttr>
175getOrAddInnerSym(MLIRContext *context, hw::InnerSymAttr attr, uint64_t fieldID,
176 llvm::function_ref<hw::InnerSymbolNamespace &()> getNamespace);
177
178/// Returns an inner symbol identifier for the specified target (op or port),
179/// adding one if necessary.
180StringAttr
182 llvm::function_ref<hw::InnerSymbolNamespace &()> getNamespace);
183
185 llvm::function_ref<hw::InnerSymbolNamespace &(FModuleLike mod)>;
186
187/// Returns an inner symbol identifier for the specified target (op or port),
188/// adding one if necessary.
189StringAttr getOrAddInnerSym(const hw::InnerSymTarget &target,
190 GetNamespaceCallback getNamespace);
191
192/// Obtain an inner reference to the target (operation or port),
193/// adding an inner symbol as necessary.
194hw::InnerRefAttr getInnerRefTo(const hw::InnerSymTarget &target,
195 GetNamespaceCallback getNamespace);
196
197/// Returns an inner symbol identifier for the specified operation, adding one
198/// if necessary.
199static inline StringAttr getOrAddInnerSym(Operation *op,
200 GetNamespaceCallback getNamespace) {
201 return getOrAddInnerSym(hw::InnerSymTarget(op), getNamespace);
202}
203/// Returns an inner symbol identifier for the specified operation's field
204/// adding one if necessary.
205static inline StringAttr getOrAddInnerSym(Operation *op, uint64_t fieldID,
206 GetNamespaceCallback getNamespace) {
207 return getOrAddInnerSym(hw::InnerSymTarget(op, fieldID), getNamespace);
208}
209
210/// Obtain an inner reference to an operation, possibly adding an inner symbol.
211static inline hw::InnerRefAttr
212getInnerRefTo(Operation *op, GetNamespaceCallback getNamespace) {
213 return getInnerRefTo(hw::InnerSymTarget(op), getNamespace);
214}
215
216/// Obtain an inner reference to an operation's field, possibly adding an inner
217/// symbol.
218static inline hw::InnerRefAttr
219getInnerRefTo(Operation *op, uint64_t fieldID,
220 GetNamespaceCallback getNamespace) {
221 return getInnerRefTo(hw::InnerSymTarget(op, fieldID), getNamespace);
222}
223
224/// Returns an inner symbol identifier for the specified port, adding one if
225/// necessary.
226static inline StringAttr getOrAddInnerSym(FModuleLike mod, size_t portIdx,
227 GetNamespaceCallback getNamespace) {
228 return getOrAddInnerSym(hw::InnerSymTarget(portIdx, mod), getNamespace);
229}
230
231/// Returns an inner symbol identifier for the specified port's field, adding
232/// one if necessary.
233static inline StringAttr getOrAddInnerSym(FModuleLike mod, size_t portIdx,
234 uint64_t fieldID,
235 GetNamespaceCallback getNamespace) {
236 return getOrAddInnerSym(hw::InnerSymTarget(portIdx, mod, fieldID),
237 getNamespace);
238}
239
240/// Obtain an inner reference to a port, possibly adding an inner symbol.
241static inline hw::InnerRefAttr
242getInnerRefTo(FModuleLike mod, size_t portIdx,
243 GetNamespaceCallback getNamespace) {
244 return getInnerRefTo(hw::InnerSymTarget(portIdx, mod), getNamespace);
245}
246
247/// Obtain an inner reference to a port's field, possibly adding an inner
248/// symbol.
249static inline hw::InnerRefAttr
250getInnerRefTo(FModuleLike mod, size_t portIdx, uint64_t fieldID,
251 GetNamespaceCallback getNamespace) {
252 return getInnerRefTo(hw::InnerSymTarget(portIdx, mod, fieldID), getNamespace);
253}
254
255//===----------------------------------------------------------------------===//
256// Type utilities
257//===----------------------------------------------------------------------===//
258
259/// If it is a base type, return it as is. If reftype, return wrapped base type.
260/// Otherwise, return null.
261inline FIRRTLBaseType getBaseType(Type type) {
262 return TypeSwitch<Type, FIRRTLBaseType>(type)
263 .Case<FIRRTLBaseType>([](auto base) { return base; })
264 .Case<LHSType>([](auto lhs) { return lhs.getType(); })
265 .Case<RefType>([](auto ref) { return ref.getType(); })
266 .Default([](Type type) { return nullptr; });
267}
268
269/// Get base type if isa<> the requested type, else null.
270template <typename T>
271inline T getBaseOfType(Type type) {
272 return dyn_cast_or_null<T>(getBaseType(type));
273}
274
275/// Return a FIRRTLType with its base type component mutated by the given
276/// function. (i.e., ref<T> -> ref<f(T)> and T -> f(T)).
278 function_ref<FIRRTLBaseType(FIRRTLBaseType)> fn) {
279 return TypeSwitch<FIRRTLType, FIRRTLType>(type)
280 .Case<FIRRTLBaseType>([&](auto base) { return fn(base); })
281 .Case<RefType>([&](auto ref) {
282 return RefType::get(fn(ref.getType()), ref.getForceable(),
283 ref.getLayer());
284 });
285}
286
287/// Return a FIRRTLType with its base type component mutated by the given
288/// function. Return null when the function returns null.
289/// (i.e., ref<T> -> ref<f(T)> if f(T) != null else null, and T -> f(T)).
290inline FIRRTLType
292 function_ref<FIRRTLBaseType(FIRRTLBaseType)> fn) {
293 return TypeSwitch<FIRRTLType, FIRRTLType>(type)
294 .Case<FIRRTLBaseType>([&](auto base) { return fn(base); })
295 .Case<RefType>([&](auto ref) -> FIRRTLType {
296 auto result = fn(ref.getType());
297 if (!result)
298 return {};
299 return RefType::get(result, ref.getForceable(), ref.getLayer());
300 });
301}
302
303/// Given a type, return the corresponding lowered type for the HW dialect.
304/// Non-FIRRTL types are simply passed through. This returns a null type if it
305/// cannot be lowered. The optional function is required to specify how to lower
306/// AliasTypes.
307Type lowerType(
308 Type type, std::optional<Location> loc = {},
309 llvm::function_ref<hw::TypeAliasType(Type, BaseTypeAliasType, Location)>
310 getTypeDeclFn = {});
311
312//===----------------------------------------------------------------------===//
313// Parser-related utilities
314//
315// These cannot always be relegated to the parser and sometimes need to be
316// available for passes. This has specifically come up for Annotation lowering
317// where there is FIRRTL stuff that needs to be parsed out of an annotation.
318//===----------------------------------------------------------------------===//
319
320/// Parse a string that may encode a FIRRTL location into a LocationAttr.
321std::pair<bool, std::optional<mlir::LocationAttr>> maybeStringToLocation(
322 StringRef spelling, bool skipParsing, StringAttr &locatorFilenameCache,
323 FileLineColLoc &fileLineColLocCache, MLIRContext *context);
324
325// Parse a format string and build operations for FIRRTL "special"
326// substitutions.
327//
328// This function handles:
329// - percent format strings (%b, %d, %x, %c, %%)
330// - special format strings ({{SimulationTime}}, {{HierarchicalModuleName}})
331//
332// The formatStringResult output parameter is set to the validated format
333// string. The operands output parameter is set to the list of actual operands
334// (including special ops created for {{...}} substitutions).
335mlir::ParseResult
336parseFormatString(mlir::OpBuilder &builder, mlir::Location loc,
337 llvm::StringRef formatString,
338 llvm::ArrayRef<mlir::Value> specOperands,
339 mlir::StringAttr &formatStringResult,
340 llvm::SmallVectorImpl<mlir::Value> &operands);
341
342//===----------------------------------------------------------------------===//
343// File utilities
344//===----------------------------------------------------------------------===//
345
346/// Truncate `a` to the common prefix of `a` and `b`.
347void makeCommonPrefix(SmallString<64> &a, StringRef b);
348
349//===----------------------------------------------------------------------===//
350// Object related utilities
351//===----------------------------------------------------------------------===//
352
353/// Add the tracker annotation to the op and get a PathOp to the op.
354PathOp createPathRef(Operation *op, hw::HierPathOp nla,
355 mlir::ImplicitLocOpBuilder &builderOM);
356
357} // namespace firrtl
358} // namespace circt
359
360#endif // CIRCT_DIALECT_FIRRTL_FIRRTLUTILS_H
static std::unique_ptr< Context > context
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
llvm::MapVector< std::pair< StringAttr, StringAttr >, FlatSymbolRefAttr > cache
Definition FIRRTLUtils.h:88
FlatSymbolRefAttr getMacro(StringAttr optionName, StringAttr caseName) const
Helper class to cache tie-off values for different FIRRTL types.
Definition FIRRTLUtils.h:63
ImplicitLocOpBuilder & builder
Definition FIRRTLUtils.h:71
TieOffCache(ImplicitLocOpBuilder &builder)
Definition FIRRTLUtils.h:65
SmallDenseMap< Type, Value, 8 > cache
Definition FIRRTLUtils.h:72
Value getUnknown(PropertyType type)
Get or create an UnknownValueOp for the given property type.
The target of an inner symbol, the entity the symbol is a handle for.
llvm::function_ref< hw::InnerSymbolNamespace &(FModuleLike mod)> GetNamespaceCallback
FIRRTLType mapBaseTypeNullable(FIRRTLType type, function_ref< FIRRTLBaseType(FIRRTLBaseType)> fn)
Return a FIRRTLType with its base type component mutated by the given function.
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.
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Get the FieldRef from a value.
mlir::TypedValue< FIRRTLBaseType > FIRRTLBaseValue
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.
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:98
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.
PropAssignOp getPropertyAssignment(FIRRTLPropertyValue value)
Return the single assignment to a Property value.
mlir::ParseResult parseFormatString(mlir::OpBuilder &builder, mlir::Location loc, llvm::StringRef formatString, llvm::ArrayRef< mlir::Value > specOperands, mlir::StringAttr &formatStringResult, llvm::SmallVectorImpl< mlir::Value > &operands)
Value getValueSource(Value val, bool lookThroughWires, bool lookThroughNodes, bool lookThroughCasts)
Return the value that drives another FIRRTL value within module scope.
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.
mlir::TypedValue< PropertyType > FIRRTLPropertyValue
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.
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 hw.py:1