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