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