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