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