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