CIRCT 20.0.0git
Loading...
Searching...
No Matches
FIRRTLIntrinsics.h
Go to the documentation of this file.
1//===- FIRRTLIntrinsics.h - FIRRTL intrinsics ------------------*- 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 helpers for the lowering of intrinsics.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef CIRCT_DIALECT_FIRRTL_FIRRTLINTRINSICS_H
14#define CIRCT_DIALECT_FIRRTL_FIRRTLINTRINSICS_H
15
18#include "mlir/IR/Diagnostics.h"
19#include "mlir/Transforms/DialectConversion.h"
20
21namespace circt {
22namespace firrtl {
23
24/// Helper class for checking and extracting information from the generic
25/// instrinsic op.
27 GenericIntrinsicOp op;
28
29 GenericIntrinsic(GenericIntrinsicOp op) : op(op) {}
30
31 InFlightDiagnostic emitError() { return op.emitError(op.getIntrinsic()); }
32
33 //===--------------------------------------------------------------------===//
34 // Input checking
35 //===--------------------------------------------------------------------===//
36
37 ParseResult hasNInputs(unsigned n, unsigned c = 0);
38 unsigned getNumInputs();
39
40 template <typename C>
41 ParseResult checkInputType(unsigned n, const Twine &msg, C &&call) {
42 if (n >= op.getNumOperands())
43 return emitError() << " missing input " << n;
44 if (!std::invoke(std::forward<C>(call), op.getOperand(n).getType()))
45 return emitError() << " input " << n << " " << msg;
46 return success();
47 }
48
49 template <typename C>
50 ParseResult checkInputType(unsigned n, C &&call) {
51 return checkInputType(n, "not of correct type", std::forward<C>(call));
52 }
53
54 template <typename T>
55 ParseResult typedInput(unsigned n) {
56 return checkInputType(n, [](auto ty) { return isa<T>(ty); });
57 }
58
59 ParseResult hasResetInput(unsigned n) {
60 return checkInputType(n, "must be reset type", [](auto ty) {
61 auto baseType = dyn_cast<FIRRTLBaseType>(ty);
62 return baseType && baseType.isResetType();
63 });
64 }
65
66 template <typename T>
67 ParseResult sizedInput(unsigned n, int32_t size) {
68 return checkInputType(n, "not size " + Twine(size), [size](auto ty) {
69 auto t = dyn_cast<T>(ty);
70 return t && t.getWidth() == size;
71 });
72 }
73
74 //===--------------------------------------------------------------------===//
75 // Parameter checking
76 //===--------------------------------------------------------------------===//
77
78 ParseResult hasNParam(unsigned n, unsigned c = 0);
79
80 ParseResult namedParam(StringRef paramName, bool optional = false);
81
82 ParseResult namedIntParam(StringRef paramName, bool optional = false);
83
84 ParamDeclAttr getParamByName(StringRef name) {
85 for (auto param : op.getParameters().getAsRange<ParamDeclAttr>())
86 if (param.getName().getValue() == name)
87 return param;
88 return {};
89 }
90
91 /// Get parameter value by name, if present, as requested type.
92 template <typename T>
93 T getParamValue(StringRef name) {
94 auto p = getParamByName(name);
95 if (!p)
96 return {};
97 return cast<T>(p.getValue());
98 }
99
100 //===--------------------------------------------------------------------===//
101 // Output checking
102 //===--------------------------------------------------------------------===//
103
104 ParseResult hasOutput() {
105 if (op.getNumResults() == 0)
106 return emitError() << " missing output";
107 return success();
108 }
109 ParseResult hasNoOutput() {
110 if (op.getNumResults() != 0)
111 return emitError() << " should not have outputs";
112 return success();
113 }
114
115 template <typename T>
116 ParseResult typedOutput() {
117 if (failed(hasOutput()))
118 return failure();
119 if (!isa<T>(op.getResult().getType()))
120 return emitError() << " output not of correct type";
121 return success();
122 }
123
124 template <typename T>
125 ParseResult sizedOutput(int32_t size) {
126 if (failed(typedOutput<T>()))
127 return failure();
128 if (cast<T>(op.getResult().getType()).getWidth() != size)
129 return emitError() << " output not size " << size;
130 return success();
131 }
132
133 //===--------------------------------------------------------------------===//
134 // Output bundle element checking
135 //===--------------------------------------------------------------------===//
136
137 mlir::TypedValue<BundleType> getOutputBundle() {
138 return dyn_cast_or_null<mlir::TypedValue<BundleType>>(op.getResult());
139 }
140
141 ParseResult hasNOutputElements(unsigned n);
142
143 template <typename C>
144 ParseResult checkOutputElement(unsigned n, StringRef name, const Twine &msg,
145 C &&call) {
146 auto b = getOutputBundle();
147 if (!b)
148 return emitError() << " missing output bundle";
149 auto ty = b.getType();
150 if (n >= ty.getNumElements())
151 return emitError() << " missing output element " << n;
152 auto elementName = ty.getElementName(n);
153 if (elementName != name)
154 return emitError() << " output element " << n << " is named "
155 << elementName << " not " << name;
156 if (!std::invoke(std::forward<C>(call),
157 ty.getElementTypePreservingConst(n)))
158 return emitError() << " output element " << n << " " << msg;
159 return success();
160 }
161
162 template <typename C>
163 ParseResult checkOutputElement(unsigned n, StringRef name, C &&call) {
164 return checkOutputElement(n, name, "not of correct type",
165 std::forward<C>(call));
166 }
167
168 ParseResult hasOutputElement(unsigned n, StringRef name) {
169 return checkOutputElement(n, name, [](auto ty) { return true; });
170 }
171
172 template <typename T>
173 ParseResult typedOutputElement(unsigned n, StringRef name) {
174 return checkOutputElement(n, name, [](auto ty) { return isa<T>(ty); });
175 }
176
177 template <typename T>
178 ParseResult sizedOutputElement(unsigned n, StringRef name, int32_t size) {
179 return checkOutputElement(n, name, "not size " + Twine(size),
180 [size](auto ty) {
181 auto t = dyn_cast<T>(ty);
182 return t && t.getWidth() == size;
183 });
184 }
185};
186
187/// Base class for Intrinsic Converters.
188///
189/// Intrinsic converters contain validation logic, along with a converter
190/// method to transform generic intrinsic ops to their implementation.
191
192/// Instances of a converter must be stateless and are expected to be able
193/// to be used simultaneously on different intrinsic operations in parallel.
195public:
196 virtual void anchor(); // vtable anchor
197
198 virtual ~IntrinsicConverter() = default;
199
200 /// Checks whether the intrinsic is well-formed.
201 ///
202 /// This or's multiple ParseResults together, returning true on failure.
203 virtual bool check(GenericIntrinsic gi) {
204 llvm::report_fatal_error(
205 "check() or checkAndConvert() must be implemented");
206 return true;
207 }
208
209 /// Transform the intrinsic to its implementation.
210 virtual void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor,
211 PatternRewriter &rewriter) {
212 llvm::report_fatal_error(
213 "convert() or checkAndConvert() must be implemented");
214 }
215
216 /// Perform both check and convert, defaults to using check() and convert().
217 /// Return failure if check fails (no changes to IR should be made).
218 /// Otherwise, transform the intrinsic and return success.
219 /// Prefer overriding check and convert, but overriding this can avoid
220 /// recomputing work done during check needed for the conversion.
221 virtual LogicalResult checkAndConvert(GenericIntrinsic gi,
222 GenericIntrinsicOpAdaptor adaptor,
223 PatternRewriter &rewriter) {
224 if (check(gi))
225 return failure();
226 convert(gi, adaptor, rewriter);
227 return success();
228 };
229};
230
231template <typename OpTy>
233public:
234 /// Transform the intrinsic to its implementation.
235 /// Handles the simple case of just forwarding to new op kind.
236 void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor,
237 PatternRewriter &rewriter) final {
238 // Pass along result type and operands. No attributes.
239 rewriter.replaceOpWithNewOp<OpTy>(gi.op, gi.op.getResultTypes(),
240 adaptor.getOperands());
241 }
242};
243
244/// Lowering helper which collects all intrinsic converters.
246public:
248 llvm::DenseMap<StringAttr, std::unique_ptr<IntrinsicConverter>>;
249
250private:
251 /// Reference to the MLIR context.
252 MLIRContext *context;
253
254 /// Mapping from intrinsic names to converters.
256
257public:
259
260 /// Registers a converter to one or more intrinsic names.
261 template <typename T, typename... Args>
262 void add(Args... args) {
263 (addConverter<T>(args), ...);
264 }
265
266 /// Lowers all intrinsics in a module. Returns number converted or failure.
267 FailureOr<size_t> lower(FModuleOp mod, bool allowUnknownIntrinsics = false);
268
269private:
270 template <typename T>
271 typename std::enable_if_t<std::is_base_of_v<IntrinsicConverter, T>>
272 addConverter(StringRef name) {
273 auto nameAttr = StringAttr::get(context, name);
274 assert(!conversions.contains(nameAttr) &&
275 "duplicate conversion for intrinsic");
276 conversions.try_emplace(nameAttr, std::make_unique<T>());
277 }
278};
279
280/// A dialect interface to provide lowering conversions.
282 : public mlir::DialectInterface::Base<IntrinsicLoweringDialectInterface> {
283 IntrinsicLoweringDialectInterface(Dialect *dialect) : Base(dialect) {}
284
285 virtual void
287};
288
290 : public mlir::DialectInterfaceCollection<
291 IntrinsicLoweringDialectInterface> {
292 using Base::Base;
293
294 // Collect the intrinsic lowerings defined by each dialect.
295 void populateIntrinsicLowerings(IntrinsicLowerings &lowerings) const;
296};
297
303
304} // namespace firrtl
305} // namespace circt
306
307#endif // CIRCT_DIALECT_FIRRTL_FIRRTLINTRINSICS_H
assert(baseType &&"element must be base type")
Base class for Intrinsic Converters.
virtual bool check(GenericIntrinsic gi)
Checks whether the intrinsic is well-formed.
virtual ~IntrinsicConverter()=default
virtual void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor, PatternRewriter &rewriter)
Transform the intrinsic to its implementation.
virtual LogicalResult checkAndConvert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor, PatternRewriter &rewriter)
Perform both check and convert, defaults to using check() and convert().
Lowering helper which collects all intrinsic converters.
FailureOr< size_t > lower(FModuleOp mod, bool allowUnknownIntrinsics=false)
Lowers all intrinsics in a module. Returns number converted or failure.
IntrinsicLowerings(MLIRContext *context)
std::enable_if_t< std::is_base_of_v< IntrinsicConverter, T > > addConverter(StringRef name)
llvm::DenseMap< StringAttr, std::unique_ptr< IntrinsicConverter > > ConversionMapTy
void add(Args... args)
Registers a converter to one or more intrinsic names.
MLIRContext * context
Reference to the MLIR context.
ConversionMapTy conversions
Mapping from intrinsic names to converters.
void convert(GenericIntrinsic gi, GenericIntrinsicOpAdaptor adaptor, PatternRewriter &rewriter) final
Transform the intrinsic to its implementation.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void populateIntrinsicLowerings(IntrinsicLowerings &lowerings) const override
Helper class for checking and extracting information from the generic instrinsic op.
ParseResult sizedInput(unsigned n, int32_t size)
mlir::TypedValue< BundleType > getOutputBundle()
T getParamValue(StringRef name)
Get parameter value by name, if present, as requested type.
ParseResult hasResetInput(unsigned n)
ParseResult checkInputType(unsigned n, const Twine &msg, C &&call)
GenericIntrinsic(GenericIntrinsicOp op)
ParseResult typedInput(unsigned n)
ParseResult hasNOutputElements(unsigned n)
ParseResult checkOutputElement(unsigned n, StringRef name, C &&call)
ParseResult namedIntParam(StringRef paramName, bool optional=false)
ParamDeclAttr getParamByName(StringRef name)
ParseResult checkOutputElement(unsigned n, StringRef name, const Twine &msg, C &&call)
ParseResult namedParam(StringRef paramName, bool optional=false)
ParseResult sizedOutput(int32_t size)
ParseResult sizedOutputElement(unsigned n, StringRef name, int32_t size)
ParseResult hasNParam(unsigned n, unsigned c=0)
ParseResult hasOutputElement(unsigned n, StringRef name)
ParseResult hasNInputs(unsigned n, unsigned c=0)
ParseResult typedOutputElement(unsigned n, StringRef name)
ParseResult checkInputType(unsigned n, C &&call)
A dialect interface to provide lowering conversions.
virtual void populateIntrinsicLowerings(IntrinsicLowerings &lowerings) const =0
void populateIntrinsicLowerings(IntrinsicLowerings &lowerings) const