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