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