MLIR  22.0.0git
DialectConversion.h
Go to the documentation of this file.
1 //===- DialectConversion.h - MLIR dialect conversion pass -------*- 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 declares a generic pass for converting between MLIR dialects.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef MLIR_TRANSFORMS_DIALECTCONVERSION_H_
14 #define MLIR_TRANSFORMS_DIALECTCONVERSION_H_
15 
16 #include "mlir/Config/mlir-config.h"
18 #include "llvm/ADT/MapVector.h"
19 #include "llvm/ADT/StringMap.h"
20 #include <type_traits>
21 
22 namespace mlir {
23 
24 // Forward declarations.
25 class Attribute;
26 class Block;
27 struct ConversionConfig;
28 class ConversionPatternRewriter;
29 class MLIRContext;
30 class Operation;
31 struct OperationConverter;
32 class Type;
33 class Value;
34 
35 //===----------------------------------------------------------------------===//
36 // Type Conversion
37 //===----------------------------------------------------------------------===//
38 
39 /// Type conversion class. Specific conversions and materializations can be
40 /// registered using addConversion and addMaterialization, respectively.
42 public:
43  virtual ~TypeConverter() = default;
44  TypeConverter() = default;
45  // Copy the registered conversions, but not the caches
47  : conversions(other.conversions),
48  sourceMaterializations(other.sourceMaterializations),
49  targetMaterializations(other.targetMaterializations),
50  typeAttributeConversions(other.typeAttributeConversions) {}
52  conversions = other.conversions;
53  sourceMaterializations = other.sourceMaterializations;
54  targetMaterializations = other.targetMaterializations;
55  typeAttributeConversions = other.typeAttributeConversions;
56  return *this;
57  }
58 
59  /// This class provides all of the information necessary to convert a type
60  /// signature.
62  public:
63  SignatureConversion(unsigned numOrigInputs)
64  : remappedInputs(numOrigInputs) {}
65 
66  /// This struct represents a range of new types or a range of values that
67  /// remaps an existing signature input.
68  struct InputMapping {
69  size_t inputNo, size;
71 
72  /// Return "true" if this input was replaces with one or multiple values.
73  bool replacedWithValues() const { return !replacementValues.empty(); }
74  };
75 
76  /// Return the argument types for the new signature.
77  ArrayRef<Type> getConvertedTypes() const { return argTypes; }
78 
79  /// Get the input mapping for the given argument.
80  std::optional<InputMapping> getInputMapping(unsigned input) const {
81  return remappedInputs[input];
82  }
83 
84  //===------------------------------------------------------------------===//
85  // Conversion Hooks
86  //===------------------------------------------------------------------===//
87 
88  /// Remap an input of the original signature with a new set of types. The
89  /// new types are appended to the new signature conversion.
90  void addInputs(unsigned origInputNo, ArrayRef<Type> types);
91 
92  /// Append new input types to the signature conversion, this should only be
93  /// used if the new types are not intended to remap an existing input.
94  void addInputs(ArrayRef<Type> types);
95 
96  /// Remap an input of the original signature to `replacements`
97  /// values. This drops the original argument.
98  void remapInput(unsigned origInputNo, ArrayRef<Value> replacements);
99 
100  private:
101  /// Remap an input of the original signature with a range of types in the
102  /// new signature.
103  void remapInput(unsigned origInputNo, unsigned newInputNo,
104  unsigned newInputCount = 1);
105 
106  /// The remapping information for each of the original arguments.
107  SmallVector<std::optional<InputMapping>, 4> remappedInputs;
108 
109  /// The set of new argument types.
110  SmallVector<Type, 4> argTypes;
111  };
112 
113  /// The general result of a type attribute conversion callback, allowing
114  /// for early termination. The default constructor creates the na case.
116  public:
117  constexpr AttributeConversionResult() : impl() {}
118  AttributeConversionResult(Attribute attr) : impl(attr, resultTag) {}
119 
121  static AttributeConversionResult na();
123 
124  bool hasResult() const;
125  bool isNa() const;
126  bool isAbort() const;
127 
128  Attribute getResult() const;
129 
130  private:
131  AttributeConversionResult(Attribute attr, unsigned tag) : impl(attr, tag) {}
132 
133  llvm::PointerIntPair<Attribute, 2> impl;
134  // Note that na is 0 so that we can use PointerIntPair's default
135  // constructor.
136  static constexpr unsigned naTag = 0;
137  static constexpr unsigned resultTag = 1;
138  static constexpr unsigned abortTag = 2;
139  };
140 
141  /// Register a conversion function. A conversion function must be convertible
142  /// to any of the following forms (where `T` is `Value` or a class derived
143  /// from `Type`, including `Type` itself):
144  ///
145  /// * std::optional<Type>(T)
146  /// - This form represents a 1-1 type conversion. It should return nullptr
147  /// or `std::nullopt` to signify failure. If `std::nullopt` is returned,
148  /// the converter is allowed to try another conversion function to
149  /// perform the conversion.
150  /// * std::optional<LogicalResult>(T, SmallVectorImpl<Type> &)
151  /// - This form represents a 1-N type conversion. It should return
152  /// `failure` or `std::nullopt` to signify a failed conversion. If the
153  /// new set of types is empty, the type is removed and any usages of the
154  /// existing value are expected to be removed during conversion. If
155  /// `std::nullopt` is returned, the converter is allowed to try another
156  /// conversion function to perform the conversion.
157  ///
158  /// Conversion functions that accept `Value` as the first argument are
159  /// context-aware. I.e., they can take into account IR when converting the
160  /// type of the given value. Context-unaware conversion functions accept
161  /// `Type` or a derived class as the first argument.
162  ///
163  /// Note: Context-unaware conversions are cached, but context-aware
164  /// conversions are not.
165  ///
166  /// Note: When attempting to convert a type, e.g. via 'convertType', the
167  /// mostly recently added conversions will be invoked first.
168  template <typename FnT, typename T = typename llvm::function_traits<
169  std::decay_t<FnT>>::template arg_t<0>>
170  void addConversion(FnT &&callback) {
171  registerConversion(wrapCallback<T>(std::forward<FnT>(callback)));
172  }
173 
174  /// All of the following materializations require function objects that are
175  /// convertible to the following form:
176  /// `Value(OpBuilder &, T, ValueRange, Location)`,
177  /// where `T` is any subclass of `Type`. This function is responsible for
178  /// creating an operation, using the OpBuilder and Location provided, that
179  /// "casts" a range of values into a single value of the given type `T`. It
180  /// must return a Value of the type `T` on success and `nullptr` if
181  /// it failed but other materialization should be attempted. Materialization
182  /// functions must be provided when a type conversion may persist after the
183  /// conversion has finished.
184  ///
185  /// Note: Target materializations may optionally accept an additional Type
186  /// parameter, which is the original type of the SSA value. Furthermore, `T`
187  /// can be a TypeRange; in that case, the function must return a
188  /// SmallVector<Value>.
189 
190  /// This method registers a materialization that will be called when
191  /// converting a replacement value back to its original source type.
192  /// This is used when some uses of the original value persist beyond the main
193  /// conversion.
194  template <typename FnT, typename T = typename llvm::function_traits<
195  std::decay_t<FnT>>::template arg_t<1>>
196  void addSourceMaterialization(FnT &&callback) {
197  sourceMaterializations.emplace_back(
198  wrapSourceMaterialization<T>(std::forward<FnT>(callback)));
199  }
200 
201  /// This method registers a materialization that will be called when
202  /// converting a value to a target type according to a pattern's type
203  /// converter.
204  ///
205  /// Note: Target materializations can optionally inspect the "original"
206  /// type. This type may be different from the type of the input value.
207  /// For example, let's assume that a conversion pattern "P1" replaced an SSA
208  /// value "v1" (type "t1") with "v2" (type "t2"). Then a different conversion
209  /// pattern "P2" matches an op that has "v1" as an operand. Let's furthermore
210  /// assume that "P2" determines that the converted target type of "t1" is
211  /// "t3", which may be different from "t2". In this example, the target
212  /// materialization will be invoked with: outputType = "t3", inputs = "v2",
213  /// originalType = "t1". Note that the original type "t1" cannot be recovered
214  /// from just "t3" and "v2"; that's why the originalType parameter exists.
215  ///
216  /// Note: During a 1:N conversion, the result types can be a TypeRange. In
217  /// that case the materialization produces a SmallVector<Value>.
218  template <typename FnT, typename T = typename llvm::function_traits<
219  std::decay_t<FnT>>::template arg_t<1>>
220  void addTargetMaterialization(FnT &&callback) {
221  targetMaterializations.emplace_back(
222  wrapTargetMaterialization<T>(std::forward<FnT>(callback)));
223  }
224 
225  /// Register a conversion function for attributes within types. Type
226  /// converters may call this function in order to allow hoking into the
227  /// translation of attributes that exist within types. For example, a type
228  /// converter for the `memref` type could use these conversions to convert
229  /// memory spaces or layouts in an extensible way.
230  ///
231  /// The conversion functions take a non-null Type or subclass of Type and a
232  /// non-null Attribute (or subclass of Attribute), and returns a
233  /// `AttributeConversionResult`. This result can either contain an
234  /// `Attribute`, which may be `nullptr`, representing the conversion's
235  /// success, `AttributeConversionResult::na()` (the default empty value),
236  /// indicating that the conversion function did not apply and that further
237  /// conversion functions should be checked, or
238  /// `AttributeConversionResult::abort()` indicating that the conversion
239  /// process should be aborted.
240  ///
241  /// Registered conversion functions are callled in the reverse of the order in
242  /// which they were registered.
243  template <
244  typename FnT,
245  typename T =
246  typename llvm::function_traits<std::decay_t<FnT>>::template arg_t<0>,
247  typename A =
248  typename llvm::function_traits<std::decay_t<FnT>>::template arg_t<1>>
249  void addTypeAttributeConversion(FnT &&callback) {
250  registerTypeAttributeConversion(
251  wrapTypeAttributeConversion<T, A>(std::forward<FnT>(callback)));
252  }
253 
254  /// Convert the given type. This function returns failure if no valid
255  /// conversion exists, success otherwise. If the new set of types is empty,
256  /// the type is removed and any usages of the existing value are expected to
257  /// be removed during conversion.
258  ///
259  /// Note: This overload invokes only context-unaware type conversion
260  /// functions. Users should call the other overload if possible.
261  LogicalResult convertType(Type t, SmallVectorImpl<Type> &results) const;
262 
263  /// Convert the type of the given value. This function returns failure if no
264  /// valid conversion exists, success otherwise. If the new set of types is
265  /// empty, the type is removed and any usages of the existing value are
266  /// expected to be removed during conversion.
267  ///
268  /// Note: This overload invokes both context-aware and context-unaware type
269  /// conversion functions.
270  LogicalResult convertType(Value v, SmallVectorImpl<Type> &results) const;
271 
272  /// This hook simplifies defining 1-1 type conversions. This function returns
273  /// the type to convert to on success, and a null type on failure.
274  Type convertType(Type t) const;
275  Type convertType(Value v) const;
276 
277  /// Attempts a 1-1 type conversion, expecting the result type to be
278  /// `TargetType`. Returns the converted type cast to `TargetType` on success,
279  /// and a null type on conversion or cast failure.
280  template <typename TargetType>
281  TargetType convertType(Type t) const {
282  return dyn_cast_or_null<TargetType>(convertType(t));
283  }
284  template <typename TargetType>
285  TargetType convertType(Value v) const {
286  return dyn_cast_or_null<TargetType>(convertType(v));
287  }
288 
289  /// Convert the given types, filling 'results' as necessary. This returns
290  /// "failure" if the conversion of any of the types fails, "success"
291  /// otherwise.
292  LogicalResult convertTypes(TypeRange types,
293  SmallVectorImpl<Type> &results) const;
294 
295  /// Convert the types of the given values, filling 'results' as necessary.
296  /// This returns "failure" if the conversion of any of the types fails,
297  /// "success" otherwise.
298  LogicalResult convertTypes(ValueRange values,
299  SmallVectorImpl<Type> &results) const;
300 
301  /// Return true if the given type is legal for this type converter, i.e. the
302  /// type converts to itself.
303  bool isLegal(Type type) const;
304  bool isLegal(Value value) const;
305 
306  /// Return true if all of the given types are legal for this type converter.
307  bool isLegal(TypeRange range) const {
308  return llvm::all_of(range, [this](Type type) { return isLegal(type); });
309  }
310  bool isLegal(ValueRange range) const {
311  return llvm::all_of(range, [this](Value value) { return isLegal(value); });
312  }
313 
314  /// Return true if the given operation has legal operand and result types.
315  bool isLegal(Operation *op) const;
316 
317  /// Return true if the types of block arguments within the region are legal.
318  bool isLegal(Region *region) const;
319 
320  /// Return true if the inputs and outputs of the given function type are
321  /// legal.
322  bool isSignatureLegal(FunctionType ty) const;
323 
324  /// This method allows for converting a specific argument of a signature. It
325  /// takes as inputs the original argument input number, type.
326  /// On success, it populates 'result' with any new mappings.
327  LogicalResult convertSignatureArg(unsigned inputNo, Type type,
328  SignatureConversion &result) const;
329  LogicalResult convertSignatureArgs(TypeRange types,
330  SignatureConversion &result,
331  unsigned origInputOffset = 0) const;
332  LogicalResult convertSignatureArg(unsigned inputNo, Value value,
333  SignatureConversion &result) const;
334  LogicalResult convertSignatureArgs(ValueRange values,
335  SignatureConversion &result,
336  unsigned origInputOffset = 0) const;
337 
338  /// This function converts the type signature of the given block, by invoking
339  /// 'convertSignatureArg' for each argument. This function should return a
340  /// valid conversion for the signature on success, std::nullopt otherwise.
341  std::optional<SignatureConversion> convertBlockSignature(Block *block) const;
342 
343  /// Materialize a conversion from a set of types into one result type by
344  /// generating a cast sequence of some kind. See the respective
345  /// `add*Materialization` for more information on the context for these
346  /// methods.
348  Type resultType, ValueRange inputs) const;
350  Type resultType, ValueRange inputs,
351  Type originalType = {}) const;
352  SmallVector<Value> materializeTargetConversion(OpBuilder &builder,
353  Location loc,
354  TypeRange resultType,
355  ValueRange inputs,
356  Type originalType = {}) const;
357 
358  /// Convert an attribute present `attr` from within the type `type` using
359  /// the registered conversion functions. If no applicable conversion has been
360  /// registered, return std::nullopt. Note that the empty attribute/`nullptr`
361  /// is a valid return value for this function.
362  std::optional<Attribute> convertTypeAttribute(Type type,
363  Attribute attr) const;
364 
365 private:
366  /// The signature of the callback used to convert a type. If the new set of
367  /// types is empty, the type is removed and any usages of the existing value
368  /// are expected to be removed during conversion.
369  using ConversionCallbackFn = std::function<std::optional<LogicalResult>(
370  PointerUnion<Type, Value>, SmallVectorImpl<Type> &)>;
371 
372  /// The signature of the callback used to materialize a source conversion.
373  ///
374  /// Arguments: builder, result type, inputs, location
375  using SourceMaterializationCallbackFn =
376  std::function<Value(OpBuilder &, Type, ValueRange, Location)>;
377 
378  /// The signature of the callback used to materialize a target conversion.
379  ///
380  /// Arguments: builder, result types, inputs, location, original type
381  using TargetMaterializationCallbackFn = std::function<SmallVector<Value>(
382  OpBuilder &, TypeRange, ValueRange, Location, Type)>;
383 
384  /// The signature of the callback used to convert a type attribute.
385  using TypeAttributeConversionCallbackFn =
386  std::function<AttributeConversionResult(Type, Attribute)>;
387 
388  /// Generate a wrapper for the given callback. This allows for accepting
389  /// different callback forms, that all compose into a single version.
390  /// With callback of form: `std::optional<Type>(T)`, where `T` can be a
391  /// `Value` or a `Type` (or a class derived from `Type`).
392  template <typename T, typename FnT>
393  std::enable_if_t<std::is_invocable_v<FnT, T>, ConversionCallbackFn>
394  wrapCallback(FnT &&callback) {
395  return wrapCallback<T>([callback = std::forward<FnT>(callback)](
396  T typeOrValue, SmallVectorImpl<Type> &results) {
397  if (std::optional<Type> resultOpt = callback(typeOrValue)) {
398  bool wasSuccess = static_cast<bool>(*resultOpt);
399  if (wasSuccess)
400  results.push_back(*resultOpt);
401  return std::optional<LogicalResult>(success(wasSuccess));
402  }
403  return std::optional<LogicalResult>();
404  });
405  }
406  /// With callback of form: `std::optional<LogicalResult>(
407  /// T, SmallVectorImpl<Type> &)`, where `T` is a type.
408  template <typename T, typename FnT>
409  std::enable_if_t<std::is_invocable_v<FnT, T, SmallVectorImpl<Type> &> &&
410  std::is_base_of_v<Type, T>,
411  ConversionCallbackFn>
412  wrapCallback(FnT &&callback) const {
413  return [callback = std::forward<FnT>(callback)](
414  PointerUnion<Type, Value> typeOrValue,
415  SmallVectorImpl<Type> &results) -> std::optional<LogicalResult> {
416  T derivedType;
417  if (Type t = dyn_cast<Type>(typeOrValue)) {
418  derivedType = dyn_cast<T>(t);
419  } else if (Value v = dyn_cast<Value>(typeOrValue)) {
420  derivedType = dyn_cast<T>(v.getType());
421  } else {
422  llvm_unreachable("unexpected variant");
423  }
424  if (!derivedType)
425  return std::nullopt;
426  return callback(derivedType, results);
427  };
428  }
429  /// With callback of form: `std::optional<LogicalResult>(
430  /// T, SmallVectorImpl<Type>)`, where `T` is a `Value`.
431  template <typename T, typename FnT>
432  std::enable_if_t<std::is_invocable_v<FnT, T, SmallVectorImpl<Type> &> &&
433  std::is_same_v<T, Value>,
434  ConversionCallbackFn>
435  wrapCallback(FnT &&callback) {
436  hasContextAwareTypeConversions = true;
437  return [callback = std::forward<FnT>(callback)](
438  PointerUnion<Type, Value> typeOrValue,
439  SmallVectorImpl<Type> &results) -> std::optional<LogicalResult> {
440  if (Type t = dyn_cast<Type>(typeOrValue)) {
441  // Context-aware type conversion was called with a type.
442  return std::nullopt;
443  } else if (Value v = dyn_cast<Value>(typeOrValue)) {
444  return callback(v, results);
445  }
446  llvm_unreachable("unexpected variant");
447  return std::nullopt;
448  };
449  }
450 
451  /// Register a type conversion.
452  void registerConversion(ConversionCallbackFn callback) {
453  conversions.emplace_back(std::move(callback));
454  cachedDirectConversions.clear();
455  cachedMultiConversions.clear();
456  }
457 
458  /// Generate a wrapper for the given source materialization callback. The
459  /// callback may take any subclass of `Type` and the wrapper will check for
460  /// the target type to be of the expected class before calling the callback.
461  template <typename T, typename FnT>
462  SourceMaterializationCallbackFn
463  wrapSourceMaterialization(FnT &&callback) const {
464  return [callback = std::forward<FnT>(callback)](
465  OpBuilder &builder, Type resultType, ValueRange inputs,
466  Location loc) -> Value {
467  if (T derivedType = dyn_cast<T>(resultType))
468  return callback(builder, derivedType, inputs, loc);
469  return Value();
470  };
471  }
472 
473  /// Generate a wrapper for the given target materialization callback.
474  /// The callback may take any subclass of `Type` and the wrapper will check
475  /// for the target type to be of the expected class before calling the
476  /// callback.
477  ///
478  /// With callback of form:
479  /// - Value(OpBuilder &, T, ValueRange, Location, Type)
480  /// - SmallVector<Value>(OpBuilder &, TypeRange, ValueRange, Location, Type)
481  template <typename T, typename FnT>
482  std::enable_if_t<
483  std::is_invocable_v<FnT, OpBuilder &, T, ValueRange, Location, Type>,
484  TargetMaterializationCallbackFn>
485  wrapTargetMaterialization(FnT &&callback) const {
486  return [callback = std::forward<FnT>(callback)](
487  OpBuilder &builder, TypeRange resultTypes, ValueRange inputs,
488  Location loc, Type originalType) -> SmallVector<Value> {
489  SmallVector<Value> result;
490  if constexpr (std::is_same<T, TypeRange>::value) {
491  // This is a 1:N target materialization. Return the produces values
492  // directly.
493  result = callback(builder, resultTypes, inputs, loc, originalType);
494  } else if constexpr (std::is_assignable<Type, T>::value) {
495  // This is a 1:1 target materialization. Invoke the callback only if a
496  // single SSA value is requested.
497  if (resultTypes.size() == 1) {
498  // Invoke the callback only if the type class of the callback matches
499  // the requested result type.
500  if (T derivedType = dyn_cast<T>(resultTypes.front())) {
501  // 1:1 materializations produce single values, but we store 1:N
502  // target materialization functions in the type converter. Wrap the
503  // result value in a SmallVector<Value>.
504  Value val =
505  callback(builder, derivedType, inputs, loc, originalType);
506  if (val)
507  result.push_back(val);
508  }
509  }
510  } else {
511  static_assert(sizeof(T) == 0, "T must be a Type or a TypeRange");
512  }
513  return result;
514  };
515  }
516  /// With callback of form:
517  /// - Value(OpBuilder &, T, ValueRange, Location)
518  /// - SmallVector<Value>(OpBuilder &, TypeRange, ValueRange, Location)
519  template <typename T, typename FnT>
520  std::enable_if_t<
521  std::is_invocable_v<FnT, OpBuilder &, T, ValueRange, Location>,
522  TargetMaterializationCallbackFn>
523  wrapTargetMaterialization(FnT &&callback) const {
524  return wrapTargetMaterialization<T>(
525  [callback = std::forward<FnT>(callback)](
526  OpBuilder &builder, T resultTypes, ValueRange inputs, Location loc,
527  Type originalType) {
528  return callback(builder, resultTypes, inputs, loc);
529  });
530  }
531 
532  /// Generate a wrapper for the given memory space conversion callback. The
533  /// callback may take any subclass of `Attribute` and the wrapper will check
534  /// for the target attribute to be of the expected class before calling the
535  /// callback.
536  template <typename T, typename A, typename FnT>
537  TypeAttributeConversionCallbackFn
538  wrapTypeAttributeConversion(FnT &&callback) const {
539  return [callback = std::forward<FnT>(callback)](
540  Type type, Attribute attr) -> AttributeConversionResult {
541  if (T derivedType = dyn_cast<T>(type)) {
542  if (A derivedAttr = dyn_cast_or_null<A>(attr))
543  return callback(derivedType, derivedAttr);
544  }
546  };
547  }
548 
549  /// Register a memory space conversion, clearing caches.
550  void
551  registerTypeAttributeConversion(TypeAttributeConversionCallbackFn callback) {
552  typeAttributeConversions.emplace_back(std::move(callback));
553  // Clear type conversions in case a memory space is lingering inside.
554  cachedDirectConversions.clear();
555  cachedMultiConversions.clear();
556  }
557 
558  /// The set of registered conversion functions.
559  SmallVector<ConversionCallbackFn, 4> conversions;
560 
561  /// The list of registered materialization functions.
562  SmallVector<SourceMaterializationCallbackFn, 2> sourceMaterializations;
563  SmallVector<TargetMaterializationCallbackFn, 2> targetMaterializations;
564 
565  /// The list of registered type attribute conversion functions.
566  SmallVector<TypeAttributeConversionCallbackFn, 2> typeAttributeConversions;
567 
568  /// A set of cached conversions to avoid recomputing in the common case.
569  /// Direct 1-1 conversions are the most common, so this cache stores the
570  /// successful 1-1 conversions as well as all failed conversions.
571  mutable DenseMap<Type, Type> cachedDirectConversions;
572  /// This cache stores the successful 1->N conversions, where N != 1.
573  mutable DenseMap<Type, SmallVector<Type, 2>> cachedMultiConversions;
574  /// A mutex used for cache access
575  mutable llvm::sys::SmartRWMutex<true> cacheMutex;
576  /// Whether the type converter has context-aware type conversions. I.e.,
577  /// conversion rules that depend on the SSA value instead of just the type.
578  /// Type conversion caching is deactivated when there are context-aware
579  /// conversions because the type converter may return different results for
580  /// the same input type.
581  bool hasContextAwareTypeConversions = false;
582 };
583 
584 //===----------------------------------------------------------------------===//
585 // Conversion Patterns
586 //===----------------------------------------------------------------------===//
587 
588 /// Base class for the conversion patterns. This pattern class enables type
589 /// conversions, and other uses specific to the conversion framework. As such,
590 /// patterns of this type can only be used with the 'apply*' methods below.
592 public:
595 
596  /// Hook for derived classes to implement combined matching and rewriting.
597  /// This overload supports only 1:1 replacements. The 1:N overload is called
598  /// by the driver. By default, it calls this 1:1 overload or fails to match
599  /// if 1:N replacements were found.
600  virtual LogicalResult
602  ConversionPatternRewriter &rewriter) const {
603  llvm_unreachable("matchAndRewrite is not implemented");
604  }
605 
606  /// Hook for derived classes to implement combined matching and rewriting.
607  /// This overload supports 1:N replacements.
608  virtual LogicalResult
610  ConversionPatternRewriter &rewriter) const {
611  return dispatchTo1To1(*this, op, operands, rewriter);
612  }
613 
614  /// Attempt to match and rewrite the IR root at the specified operation.
615  LogicalResult matchAndRewrite(Operation *op,
616  PatternRewriter &rewriter) const final;
617 
618  /// Return the type converter held by this pattern, or nullptr if the pattern
619  /// does not require type conversion.
620  const TypeConverter *getTypeConverter() const { return typeConverter; }
621 
622  template <typename ConverterTy>
623  std::enable_if_t<std::is_base_of<TypeConverter, ConverterTy>::value,
624  const ConverterTy *>
626  return static_cast<const ConverterTy *>(typeConverter);
627  }
628 
629 protected:
630  /// See `RewritePattern::RewritePattern` for information on the other
631  /// available constructors.
632  using RewritePattern::RewritePattern;
633  /// Construct a conversion pattern with the given converter, and forward the
634  /// remaining arguments to RewritePattern.
635  template <typename... Args>
637  : RewritePattern(std::forward<Args>(args)...),
639 
640  /// Given an array of value ranges, which are the inputs to a 1:N adaptor,
641  /// try to extract the single value of each range to construct a the inputs
642  /// for a 1:1 adaptor.
643  ///
644  /// Returns failure if at least one range has 0 or more than 1 value.
645  FailureOr<SmallVector<Value>>
647 
648  /// Overloaded method used to dispatch to the 1:1 'matchAndRewrite' method
649  /// if possible and emit diagnostic with a failure return value otherwise.
650  /// 'self' should be '*this' of the derived-pattern and is used to dispatch
651  /// to the correct 'matchAndRewrite' method in the derived pattern.
652  template <typename SelfPattern, typename SourceOp>
653  static LogicalResult dispatchTo1To1(const SelfPattern &self, SourceOp op,
654  ArrayRef<ValueRange> operands,
655  ConversionPatternRewriter &rewriter);
656 
657  /// Same as above, but accepts an adaptor as operand.
658  template <typename SelfPattern, typename SourceOp>
659  static LogicalResult dispatchTo1To1(
660  const SelfPattern &self, SourceOp op,
661  typename SourceOp::template GenericAdaptor<ArrayRef<ValueRange>> adaptor,
662  ConversionPatternRewriter &rewriter);
663 
664 protected:
665  /// An optional type converter for use by this pattern.
666  const TypeConverter *typeConverter = nullptr;
667 };
668 
669 /// OpConversionPattern is a wrapper around ConversionPattern that allows for
670 /// matching and rewriting against an instance of a derived operation class as
671 /// opposed to a raw Operation.
672 template <typename SourceOp>
674 public:
675  using OpAdaptor = typename SourceOp::Adaptor;
677  typename SourceOp::template GenericAdaptor<ArrayRef<ValueRange>>;
678 
680  : ConversionPattern(SourceOp::getOperationName(), benefit, context) {}
682  PatternBenefit benefit = 1)
683  : ConversionPattern(typeConverter, SourceOp::getOperationName(), benefit,
684  context) {}
685 
686  /// Wrappers around the ConversionPattern methods that pass the derived op
687  /// type.
688  LogicalResult
690  ConversionPatternRewriter &rewriter) const final {
691  auto sourceOp = cast<SourceOp>(op);
692  return matchAndRewrite(sourceOp, OpAdaptor(operands, sourceOp), rewriter);
693  }
694  LogicalResult
696  ConversionPatternRewriter &rewriter) const final {
697  auto sourceOp = cast<SourceOp>(op);
698  return matchAndRewrite(sourceOp, OneToNOpAdaptor(operands, sourceOp),
699  rewriter);
700  }
701 
702  /// Methods that operate on the SourceOp type. One of these must be
703  /// overridden by the derived pattern class.
704  virtual LogicalResult
705  matchAndRewrite(SourceOp op, OpAdaptor adaptor,
706  ConversionPatternRewriter &rewriter) const {
707  llvm_unreachable("matchAndRewrite is not implemented");
708  }
709  virtual LogicalResult
710  matchAndRewrite(SourceOp op, OneToNOpAdaptor adaptor,
711  ConversionPatternRewriter &rewriter) const {
712  return dispatchTo1To1(*this, op, adaptor, rewriter);
713  }
714 
715 private:
717 };
718 
719 /// OpInterfaceConversionPattern is a wrapper around ConversionPattern that
720 /// allows for matching and rewriting against an instance of an OpInterface
721 /// class as opposed to a raw Operation.
722 template <typename SourceOp>
724 public:
727  SourceOp::getInterfaceID(), benefit, context) {}
729  MLIRContext *context, PatternBenefit benefit = 1)
731  SourceOp::getInterfaceID(), benefit, context) {}
732 
733  /// Wrappers around the ConversionPattern methods that pass the derived op
734  /// type.
735  LogicalResult
737  ConversionPatternRewriter &rewriter) const final {
738  return matchAndRewrite(cast<SourceOp>(op), operands, rewriter);
739  }
740  LogicalResult
742  ConversionPatternRewriter &rewriter) const final {
743  return matchAndRewrite(cast<SourceOp>(op), operands, rewriter);
744  }
745 
746  /// Methods that operate on the SourceOp type. One of these must be
747  /// overridden by the derived pattern class.
748  virtual LogicalResult
749  matchAndRewrite(SourceOp op, ArrayRef<Value> operands,
750  ConversionPatternRewriter &rewriter) const {
751  llvm_unreachable("matchAndRewrite is not implemented");
752  }
753  virtual LogicalResult
754  matchAndRewrite(SourceOp op, ArrayRef<ValueRange> operands,
755  ConversionPatternRewriter &rewriter) const {
756  return dispatchTo1To1(*this, op, operands, rewriter);
757  }
758 
759 private:
761 };
762 
763 /// OpTraitConversionPattern is a wrapper around ConversionPattern that allows
764 /// for matching and rewriting against instances of an operation that possess a
765 /// given trait.
766 template <template <typename> class TraitType>
768 public:
771  TypeID::get<TraitType>(), benefit, context) {}
773  MLIRContext *context, PatternBenefit benefit = 1)
775  TypeID::get<TraitType>(), benefit, context) {}
776 };
777 
778 /// Generic utility to convert op result types according to type converter
779 /// without knowing exact op type.
780 /// Clones existing op with new result types and returns it.
781 FailureOr<Operation *>
782 convertOpResultTypes(Operation *op, ValueRange operands,
783  const TypeConverter &converter,
784  ConversionPatternRewriter &rewriter);
785 
786 /// Add a pattern to the given pattern list to convert the signature of a
787 /// FunctionOpInterface op with the given type converter. This only supports
788 /// ops which use FunctionType to represent their type.
790  StringRef functionLikeOpName, RewritePatternSet &patterns,
791  const TypeConverter &converter);
792 
793 template <typename FuncOpT>
795  RewritePatternSet &patterns, const TypeConverter &converter) {
796  populateFunctionOpInterfaceTypeConversionPattern(FuncOpT::getOperationName(),
797  patterns, converter);
798 }
799 
801  RewritePatternSet &patterns, const TypeConverter &converter);
802 
803 //===----------------------------------------------------------------------===//
804 // Conversion PatternRewriter
805 //===----------------------------------------------------------------------===//
806 
807 namespace detail {
808 struct ConversionPatternRewriterImpl;
809 } // namespace detail
810 
811 /// This class implements a pattern rewriter for use with ConversionPatterns. It
812 /// extends the base PatternRewriter and provides special conversion specific
813 /// hooks.
815 public:
817 
818  /// Return the configuration of the current dialect conversion.
819  const ConversionConfig &getConfig() const;
820 
821  /// Apply a signature conversion to given block. This replaces the block with
822  /// a new block containing the updated signature. The operations of the given
823  /// block are inlined into the newly-created block, which is returned.
824  ///
825  /// If no block argument types are changing, the original block will be
826  /// left in place and returned.
827  ///
828  /// A signature converison must be provided. (Type converters can construct
829  /// a signature conversion with `convertBlockSignature`.)
830  ///
831  /// Optionally, a type converter can be provided to build materializations.
832  /// Note: If no type converter was provided or the type converter does not
833  /// specify any suitable source/target materialization rules, the dialect
834  /// conversion may fail to legalize unresolved materializations.
835  Block *
838  const TypeConverter *converter = nullptr);
839 
840  /// Apply a signature conversion to each block in the given region. This
841  /// replaces each block with a new block containing the updated signature. If
842  /// an updated signature would match the current signature, the respective
843  /// block is left in place as is. (See `applySignatureConversion` for
844  /// details.) The new entry block of the region is returned.
845  ///
846  /// SignatureConversions are computed with the specified type converter.
847  /// This function returns "failure" if the type converter failed to compute
848  /// a SignatureConversion for at least one block.
849  ///
850  /// Optionally, a special SignatureConversion can be specified for the entry
851  /// block. This is because the types of the entry block arguments are often
852  /// tied semantically to the operation.
853  FailureOr<Block *> convertRegionTypes(
854  Region *region, const TypeConverter &converter,
855  TypeConverter::SignatureConversion *entryConversion = nullptr);
856 
857  /// Replace all the uses of the block argument `from` with `to`. This
858  /// function supports both 1:1 and 1:N replacements.
859  ///
860  /// Note: If `allowPatternRollback` is set to "true", this function replaces
861  /// all current and future uses of the block argument. This same block
862  /// block argument must not be replaced multiple times. Uses are not replaced
863  /// immediately but in a delayed fashion. Patterns may still see the original
864  /// uses when inspecting IR.
866 
867  /// Return the converted value of 'key' with a type defined by the type
868  /// converter of the currently executing pattern. Return nullptr in the case
869  /// of failure, the remapped value otherwise.
871 
872  /// Return the converted values that replace 'keys' with types defined by the
873  /// type converter of the currently executing pattern. Returns failure if the
874  /// remap failed, success otherwise.
875  LogicalResult getRemappedValues(ValueRange keys,
876  SmallVectorImpl<Value> &results);
877 
878  //===--------------------------------------------------------------------===//
879  // PatternRewriter Hooks
880  //===--------------------------------------------------------------------===//
881 
882  /// Indicate that the conversion rewriter can recover from rewrite failure.
883  /// Recovery is supported via rollback, allowing for continued processing of
884  /// patterns even if a failure is encountered during the rewrite step.
885  bool canRecoverFromRewriteFailure() const override { return true; }
886 
887  /// Replace the given operation with the new values. The number of op results
888  /// and replacement values must match. The types may differ: the dialect
889  /// conversion driver will reconcile any surviving type mismatches at the end
890  /// of the conversion process with source materializations. The given
891  /// operation is erased.
892  void replaceOp(Operation *op, ValueRange newValues) override;
893 
894  /// Replace the given operation with the results of the new op. The number of
895  /// op results must match. The types may differ: the dialect conversion
896  /// driver will reconcile any surviving type mismatches at the end of the
897  /// conversion process with source materializations. The original operation
898  /// is erased.
899  void replaceOp(Operation *op, Operation *newOp) override;
900 
901  /// Replace the given operation with the new value ranges. The number of op
902  /// results and value ranges must match. The given operation is erased.
904  SmallVector<SmallVector<Value>> &&newValues);
905  template <typename RangeT = ValueRange>
908  llvm::to_vector_of<SmallVector<Value>>(newValues));
909  }
910  template <typename RangeT>
911  void replaceOpWithMultiple(Operation *op, RangeT &&newValues) {
913  ArrayRef(llvm::to_vector_of<ValueRange>(newValues)));
914  }
915 
916  /// PatternRewriter hook for erasing a dead operation. The uses of this
917  /// operation *must* be made dead by the end of the conversion process,
918  /// otherwise an assert will be issued.
919  void eraseOp(Operation *op) override;
920 
921  /// PatternRewriter hook for erase all operations in a block. This is not yet
922  /// implemented for dialect conversion.
923  void eraseBlock(Block *block) override;
924 
925  /// PatternRewriter hook for inlining the ops of a block into another block.
926  void inlineBlockBefore(Block *source, Block *dest, Block::iterator before,
927  ValueRange argValues = {}) override;
929 
930  /// PatternRewriter hook for updating the given operation in-place.
931  /// Note: These methods only track updates to the given operation itself,
932  /// and not nested regions. Updates to regions will still require notification
933  /// through other more specific hooks above.
934  void startOpModification(Operation *op) override;
935 
936  /// PatternRewriter hook for updating the given operation in-place.
937  void finalizeOpModification(Operation *op) override;
938 
939  /// PatternRewriter hook for updating the given operation in-place.
940  void cancelOpModification(Operation *op) override;
941 
942  /// Return a reference to the internal implementation.
943  detail::ConversionPatternRewriterImpl &getImpl();
944 
945 private:
946  // Allow OperationConverter to construct new rewriters.
947  friend struct OperationConverter;
948 
949  /// Conversion pattern rewriters must not be used outside of dialect
950  /// conversions. They apply some IR rewrites in a delayed fashion and could
951  /// bring the IR into an inconsistent state when used standalone.
953  const ConversionConfig &config);
954 
955  // Hide unsupported pattern rewriter API.
957 
958  std::unique_ptr<detail::ConversionPatternRewriterImpl> impl;
959 };
960 
961 template <typename SelfPattern, typename SourceOp>
962 LogicalResult
963 ConversionPattern::dispatchTo1To1(const SelfPattern &self, SourceOp op,
964  ArrayRef<ValueRange> operands,
965  ConversionPatternRewriter &rewriter) {
966  FailureOr<SmallVector<Value>> oneToOneOperands =
967  self.getOneToOneAdaptorOperands(operands);
968  if (failed(oneToOneOperands))
969  return rewriter.notifyMatchFailure(op,
970  "pattern '" + self.getDebugName() +
971  "' does not support 1:N conversion");
972  return self.matchAndRewrite(op, *oneToOneOperands, rewriter);
973 }
974 
975 template <typename SelfPattern, typename SourceOp>
977  const SelfPattern &self, SourceOp op,
978  typename SourceOp::template GenericAdaptor<ArrayRef<ValueRange>> adaptor,
979  ConversionPatternRewriter &rewriter) {
980  FailureOr<SmallVector<Value>> oneToOneOperands =
981  self.getOneToOneAdaptorOperands(adaptor.getOperands());
982  if (failed(oneToOneOperands))
983  return rewriter.notifyMatchFailure(op,
984  "pattern '" + self.getDebugName() +
985  "' does not support 1:N conversion");
986  return self.matchAndRewrite(
987  op, typename SourceOp::Adaptor(*oneToOneOperands, adaptor), rewriter);
988 }
989 
990 //===----------------------------------------------------------------------===//
991 // ConversionTarget
992 //===----------------------------------------------------------------------===//
993 
994 /// This class describes a specific conversion target.
996 public:
997  /// This enumeration corresponds to the specific action to take when
998  /// considering an operation legal for this conversion target.
999  enum class LegalizationAction {
1000  /// The target supports this operation.
1001  Legal,
1002 
1003  /// This operation has dynamic legalization constraints that must be checked
1004  /// by the target.
1005  Dynamic,
1006 
1007  /// The target explicitly does not support this operation.
1008  Illegal,
1009  };
1010 
1011  /// A structure containing additional information describing a specific legal
1012  /// operation instance.
1014  /// A flag that indicates if this operation is 'recursively' legal. This
1015  /// means that if an operation is legal, either statically or dynamically,
1016  /// all of the operations nested within are also considered legal.
1017  bool isRecursivelyLegal = false;
1018  };
1019 
1020  /// The signature of the callback used to determine if an operation is
1021  /// dynamically legal on the target.
1023  std::function<std::optional<bool>(Operation *)>;
1024 
1025  ConversionTarget(MLIRContext &ctx) : ctx(ctx) {}
1026  virtual ~ConversionTarget() = default;
1027 
1028  //===--------------------------------------------------------------------===//
1029  // Legality Registration
1030  //===--------------------------------------------------------------------===//
1031 
1032  /// Register a legality action for the given operation.
1033  void setOpAction(OperationName op, LegalizationAction action);
1034  template <typename OpT>
1036  setOpAction(OperationName(OpT::getOperationName(), &ctx), action);
1037  }
1038 
1039  /// Register the given operations as legal.
1042  }
1043  template <typename OpT>
1044  void addLegalOp() {
1045  addLegalOp(OperationName(OpT::getOperationName(), &ctx));
1046  }
1047  template <typename OpT, typename OpT2, typename... OpTs>
1048  void addLegalOp() {
1049  addLegalOp<OpT>();
1050  addLegalOp<OpT2, OpTs...>();
1051  }
1052 
1053  /// Register the given operation as dynamically legal and set the dynamic
1054  /// legalization callback to the one provided.
1056  const DynamicLegalityCallbackFn &callback) {
1058  setLegalityCallback(op, callback);
1059  }
1060  template <typename OpT>
1062  addDynamicallyLegalOp(OperationName(OpT::getOperationName(), &ctx),
1063  callback);
1064  }
1065  template <typename OpT, typename OpT2, typename... OpTs>
1067  addDynamicallyLegalOp<OpT>(callback);
1068  addDynamicallyLegalOp<OpT2, OpTs...>(callback);
1069  }
1070  template <typename OpT, class Callable>
1071  std::enable_if_t<!std::is_invocable_v<Callable, Operation *>>
1072  addDynamicallyLegalOp(Callable &&callback) {
1073  addDynamicallyLegalOp<OpT>(
1074  [=](Operation *op) { return callback(cast<OpT>(op)); });
1075  }
1076 
1077  /// Register the given operation as illegal, i.e. this operation is known to
1078  /// not be supported by this target.
1081  }
1082  template <typename OpT>
1083  void addIllegalOp() {
1084  addIllegalOp(OperationName(OpT::getOperationName(), &ctx));
1085  }
1086  template <typename OpT, typename OpT2, typename... OpTs>
1087  void addIllegalOp() {
1088  addIllegalOp<OpT>();
1089  addIllegalOp<OpT2, OpTs...>();
1090  }
1091 
1092  /// Mark an operation, that *must* have either been set as `Legal` or
1093  /// `DynamicallyLegal`, as being recursively legal. This means that in
1094  /// addition to the operation itself, all of the operations nested within are
1095  /// also considered legal. An optional dynamic legality callback may be
1096  /// provided to mark subsets of legal instances as recursively legal.
1098  const DynamicLegalityCallbackFn &callback);
1099  template <typename OpT>
1101  OperationName opName(OpT::getOperationName(), &ctx);
1102  markOpRecursivelyLegal(opName, callback);
1103  }
1104  template <typename OpT, typename OpT2, typename... OpTs>
1106  markOpRecursivelyLegal<OpT>(callback);
1107  markOpRecursivelyLegal<OpT2, OpTs...>(callback);
1108  }
1109  template <typename OpT, class Callable>
1110  std::enable_if_t<!std::is_invocable_v<Callable, Operation *>>
1111  markOpRecursivelyLegal(Callable &&callback) {
1112  markOpRecursivelyLegal<OpT>(
1113  [=](Operation *op) { return callback(cast<OpT>(op)); });
1114  }
1115 
1116  /// Register a legality action for the given dialects.
1117  void setDialectAction(ArrayRef<StringRef> dialectNames,
1118  LegalizationAction action);
1119 
1120  /// Register the operations of the given dialects as legal.
1121  template <typename... Names>
1122  void addLegalDialect(StringRef name, Names... names) {
1123  SmallVector<StringRef, 2> dialectNames({name, names...});
1125  }
1126  template <typename... Args>
1128  SmallVector<StringRef, 2> dialectNames({Args::getDialectNamespace()...});
1130  }
1131 
1132  /// Register the operations of the given dialects as dynamically legal, i.e.
1133  /// requiring custom handling by the callback.
1134  template <typename... Names>
1136  StringRef name, Names... names) {
1137  SmallVector<StringRef, 2> dialectNames({name, names...});
1139  setLegalityCallback(dialectNames, callback);
1140  }
1141  template <typename... Args>
1143  addDynamicallyLegalDialect(std::move(callback),
1144  Args::getDialectNamespace()...);
1145  }
1146 
1147  /// Register unknown operations as dynamically legal. For operations(and
1148  /// dialects) that do not have a set legalization action, treat them as
1149  /// dynamically legal and invoke the given callback.
1151  setLegalityCallback(fn);
1152  }
1153 
1154  /// Register the operations of the given dialects as illegal, i.e.
1155  /// operations of this dialect are not supported by the target.
1156  template <typename... Names>
1157  void addIllegalDialect(StringRef name, Names... names) {
1158  SmallVector<StringRef, 2> dialectNames({name, names...});
1160  }
1161  template <typename... Args>
1163  SmallVector<StringRef, 2> dialectNames({Args::getDialectNamespace()...});
1165  }
1166 
1167  //===--------------------------------------------------------------------===//
1168  // Legality Querying
1169  //===--------------------------------------------------------------------===//
1170 
1171  /// Get the legality action for the given operation.
1172  std::optional<LegalizationAction> getOpAction(OperationName op) const;
1173 
1174  /// If the given operation instance is legal on this target, a structure
1175  /// containing legality information is returned. If the operation is not
1176  /// legal, std::nullopt is returned. Also returns std::nullopt if operation
1177  /// legality wasn't registered by user or dynamic legality callbacks returned
1178  /// None.
1179  ///
1180  /// Note: Legality is actually a 4-state: Legal(recursive=true),
1181  /// Legal(recursive=false), Illegal or Unknown, where Unknown is treated
1182  /// either as Legal or Illegal depending on context.
1183  std::optional<LegalOpDetails> isLegal(Operation *op) const;
1184 
1185  /// Returns true is operation instance is illegal on this target. Returns
1186  /// false if operation is legal, operation legality wasn't registered by user
1187  /// or dynamic legality callbacks returned None.
1188  bool isIllegal(Operation *op) const;
1189 
1190 private:
1191  /// Set the dynamic legality callback for the given operation.
1192  void setLegalityCallback(OperationName name,
1193  const DynamicLegalityCallbackFn &callback);
1194 
1195  /// Set the dynamic legality callback for the given dialects.
1196  void setLegalityCallback(ArrayRef<StringRef> dialects,
1197  const DynamicLegalityCallbackFn &callback);
1198 
1199  /// Set the dynamic legality callback for the unknown ops.
1200  void setLegalityCallback(const DynamicLegalityCallbackFn &callback);
1201 
1202  /// The set of information that configures the legalization of an operation.
1203  struct LegalizationInfo {
1204  /// The legality action this operation was given.
1206 
1207  /// If some legal instances of this operation may also be recursively legal.
1208  bool isRecursivelyLegal = false;
1209 
1210  /// The legality callback if this operation is dynamically legal.
1211  DynamicLegalityCallbackFn legalityFn;
1212  };
1213 
1214  /// Get the legalization information for the given operation.
1215  std::optional<LegalizationInfo> getOpInfo(OperationName op) const;
1216 
1217  /// A deterministic mapping of operation name and its respective legality
1218  /// information.
1219  llvm::MapVector<OperationName, LegalizationInfo> legalOperations;
1220 
1221  /// A set of legality callbacks for given operation names that are used to
1222  /// check if an operation instance is recursively legal.
1223  DenseMap<OperationName, DynamicLegalityCallbackFn> opRecursiveLegalityFns;
1224 
1225  /// A deterministic mapping of dialect name to the specific legality action to
1226  /// take.
1227  llvm::StringMap<LegalizationAction> legalDialects;
1228 
1229  /// A set of dynamic legality callbacks for given dialect names.
1230  llvm::StringMap<DynamicLegalityCallbackFn> dialectLegalityFns;
1231 
1232  /// An optional legality callback for unknown operations.
1233  DynamicLegalityCallbackFn unknownLegalityFn;
1234 
1235  /// The current context this target applies to.
1236  MLIRContext &ctx;
1237 };
1238 
1239 #if MLIR_ENABLE_PDL_IN_PATTERNMATCH
1240 //===----------------------------------------------------------------------===//
1241 // PDL Configuration
1242 //===----------------------------------------------------------------------===//
1243 
1244 /// A PDL configuration that is used to supported dialect conversion
1245 /// functionality.
1247  : public PDLPatternConfigBase<PDLConversionConfig> {
1248 public:
1249  PDLConversionConfig(const TypeConverter *converter) : converter(converter) {}
1250  ~PDLConversionConfig() final = default;
1251 
1252  /// Return the type converter used by this configuration, which may be nullptr
1253  /// if no type conversions are expected.
1254  const TypeConverter *getTypeConverter() const { return converter; }
1255 
1256  /// Hooks that are invoked at the beginning and end of a rewrite of a matched
1257  /// pattern.
1258  void notifyRewriteBegin(PatternRewriter &rewriter) final;
1259  void notifyRewriteEnd(PatternRewriter &rewriter) final;
1260 
1261 private:
1262  /// An optional type converter to use for the pattern.
1263  const TypeConverter *converter;
1264 };
1265 
1266 /// Register the dialect conversion PDL functions with the given pattern set.
1267 void registerConversionPDLFunctions(RewritePatternSet &patterns);
1268 
1269 #else
1270 
1271 // Stubs for when PDL in rewriting is not enabled.
1272 
1273 inline void registerConversionPDLFunctions(RewritePatternSet &patterns) {}
1274 
1275 class PDLConversionConfig final {
1276 public:
1277  PDLConversionConfig(const TypeConverter * /*converter*/) {}
1278 };
1279 
1280 #endif // MLIR_ENABLE_PDL_IN_PATTERNMATCH
1281 
1282 //===----------------------------------------------------------------------===//
1283 // ConversionConfig
1284 //===----------------------------------------------------------------------===//
1285 
1286 /// An enum to control folding behavior during dialect conversion.
1288  /// Never attempt to fold.
1289  Never,
1290  /// Only attempt to fold not legal operations before applying patterns.
1292  /// Only attempt to fold not legal operations after applying patterns.
1293  AfterPatterns,
1294 };
1295 
1296 /// Dialect conversion configuration.
1298  /// An optional callback used to notify about match failure diagnostics during
1299  /// the conversion. Diagnostics reported to this callback may only be
1300  /// available in debug mode.
1302 
1303  /// Partial conversion only. All operations that are found not to be
1304  /// legalizable are placed in this set. (Note that if there is an op
1305  /// explicitly marked as illegal, the conversion terminates and the set will
1306  /// not necessarily be complete.)
1308 
1309  /// Analysis conversion only. All operations that are found to be legalizable
1310  /// are placed in this set. Note that no actual rewrites are applied to the
1311  /// IR during an analysis conversion and only pre-existing operations are
1312  /// added to the set.
1314 
1315  /// An optional listener that is notified about all IR modifications in case
1316  /// dialect conversion succeeds. If the dialect conversion fails and no IR
1317  /// modifications are visible (i.e., they were all rolled back), or if the
1318  /// dialect conversion is an "analysis conversion", no notifications are
1319  /// sent (apart from `notifyPatternBegin`/notifyPatternEnd`).
1320  ///
1321  /// Note: Notifications are sent in a delayed fashion, when the dialect
1322  /// conversion is guaranteed to succeed. At that point, some IR modifications
1323  /// may already have been materialized. Consequently, operations/blocks that
1324  /// are passed to listener callbacks should not be accessed. (Ops/blocks are
1325  /// guaranteed to be valid pointers and accessing op names is allowed. But
1326  /// there are no guarantees about the state of ops/blocks at the time that a
1327  /// callback is triggered.)
1328  ///
1329  /// Example: Consider a dialect conversion a new op ("test.foo") is created
1330  /// and inserted, and later moved to another block. (Moving ops also triggers
1331  /// "notifyOperationInserted".)
1332  ///
1333  /// (1) notifyOperationInserted: "test.foo" (into block "b1")
1334  /// (2) notifyOperationInserted: "test.foo" (moved to another block "b2")
1335  ///
1336  /// When querying "op->getBlock()" during the first "notifyOperationInserted",
1337  /// "b2" would be returned because "moving an op" is a kind of rewrite that is
1338  /// immediately performed by the dialect conversion (and rolled back upon
1339  /// failure).
1340  //
1341  // Note: When receiving a "notifyBlockInserted"/"notifyOperationInserted"
1342  // callback, the previous region/block is provided to the callback, but not
1343  // the iterator pointing to the exact location within the region/block. That
1344  // is because these notifications are sent with a delay (after the IR has
1345  // already been modified) and iterators into past IR state cannot be
1346  // represented at the moment.
1348 
1349  /// If set to "true", the dialect conversion attempts to build source/target
1350  /// materializations through the type converter API in lieu of
1351  /// "builtin.unrealized_conversion_cast ops". The conversion process fails if
1352  /// at least one materialization could not be built.
1353  ///
1354  /// If set to "false", the dialect conversion does not build any custom
1355  /// materializations and instead inserts "builtin.unrealized_conversion_cast"
1356  /// ops to ensure that the resulting IR is valid.
1358 
1359  /// If set to "true", pattern rollback is allowed. The conversion driver
1360  /// rolls back IR modifications in the following situations.
1361  ///
1362  /// 1. Pattern implementation returns "failure" after modifying IR.
1363  /// 2. Pattern produces IR (in-place modification or new IR) that is illegal
1364  /// and cannot be legalized by subsequent foldings / pattern applications.
1365  ///
1366  /// Experimental: If set to "false", the conversion driver will produce an
1367  /// LLVM fatal error instead of rolling back IR modifications. Moreover, in
1368  /// case of a failed conversion, the original IR is not restored. The
1369  /// resulting IR may be a mix of original and rewritten IR. (Same as a failed
1370  /// greedy pattern rewrite.) Use the cmake build option
1371  /// `-DMLIR_ENABLE_EXPENSIVE_PATTERN_API_CHECKS=ON` (ideally together with
1372  /// ASAN) to detect invalid pattern API usage.
1373  ///
1374  /// When pattern rollback is disabled, the conversion driver has to maintain
1375  /// less internal state. This is more efficient, but not supported by all
1376  /// lowering patterns. For details, see
1377  /// https://discourse.llvm.org/t/rfc-a-new-one-shot-dialect-conversion-driver/79083.
1379 
1380  /// The folding mode to use during conversion.
1383 
1384  /// If set to "true", the materialization kind ("source" or "target") will be
1385  /// attached to "builtin.unrealized_conversion_cast" ops. This flag is useful
1386  /// for debugging, to find out what kind of materialization rule may be
1387  /// missing.
1389 };
1390 
1391 //===----------------------------------------------------------------------===//
1392 // Reconcile Unrealized Casts
1393 //===----------------------------------------------------------------------===//
1394 
1395 /// Try to reconcile all given UnrealizedConversionCastOps and store the
1396 /// left-over ops in `remainingCastOps` (if provided).
1397 ///
1398 /// This function processes cast ops in a worklist-driven fashion. For each
1399 /// cast op, if the chain of input casts eventually reaches a cast op where the
1400 /// input types match the output types of the matched op, replace the matched
1401 /// op with the inputs.
1402 ///
1403 /// Example:
1404 /// %1 = unrealized_conversion_cast %0 : !A to !B
1405 /// %2 = unrealized_conversion_cast %1 : !B to !C
1406 /// %3 = unrealized_conversion_cast %2 : !C to !A
1407 ///
1408 /// In the above example, %0 can be used instead of %3 and all cast ops are
1409 /// folded away.
1412  SmallVectorImpl<UnrealizedConversionCastOp> *remainingCastOps = nullptr);
1413 
1414 //===----------------------------------------------------------------------===//
1415 // Op Conversion Entry Points
1416 //===----------------------------------------------------------------------===//
1417 
1418 /// Below we define several entry points for operation conversion. It is
1419 /// important to note that the patterns provided to the conversion framework may
1420 /// have additional constraints. See the `PatternRewriter Hooks` section of the
1421 /// ConversionPatternRewriter, to see what additional constraints are imposed on
1422 /// the use of the PatternRewriter.
1423 
1424 /// Apply a partial conversion on the given operations and all nested
1425 /// operations. This method converts as many operations to the target as
1426 /// possible, ignoring operations that failed to legalize. This method only
1427 /// returns failure if there ops explicitly marked as illegal.
1428 LogicalResult
1430  const ConversionTarget &target,
1433 LogicalResult
1437 
1438 /// Apply a complete conversion on the given operations, and all nested
1439 /// operations. This method returns failure if the conversion of any operation
1440 /// fails, or if there are unreachable blocks in any of the regions nested
1441 /// within 'ops'.
1442 LogicalResult applyFullConversion(ArrayRef<Operation *> ops,
1443  const ConversionTarget &target,
1446 LogicalResult applyFullConversion(Operation *op, const ConversionTarget &target,
1449 
1450 /// Apply an analysis conversion on the given operations, and all nested
1451 /// operations. This method analyzes which operations would be successfully
1452 /// converted to the target if a conversion was applied. All operations that
1453 /// were found to be legalizable to the given 'target' are placed within the
1454 /// provided 'config.legalizableOps' set; note that no actual rewrites are
1455 /// applied to the operations on success. This method only returns failure if
1456 /// there are unreachable blocks in any of the regions nested within 'ops'.
1457 LogicalResult
1461 LogicalResult
1465 } // namespace mlir
1466 
1467 #endif // MLIR_TRANSFORMS_DIALECTCONVERSION_H_
Attributes are known-constant values of operations.
Definition: Attributes.h:25
This class represents an argument of a Block.
Definition: Value.h:309
Block represents an ordered list of Operations.
Definition: Block.h:33
OpListType::iterator iterator
Definition: Block.h:140
This class implements a pattern rewriter for use with ConversionPatterns.
void replaceOp(Operation *op, ValueRange newValues) override
Replace the given operation with the new values.
LogicalResult getRemappedValues(ValueRange keys, SmallVectorImpl< Value > &results)
Return the converted values that replace 'keys' with types defined by the type converter of the curre...
FailureOr< Block * > convertRegionTypes(Region *region, const TypeConverter &converter, TypeConverter::SignatureConversion *entryConversion=nullptr)
Apply a signature conversion to each block in the given region.
const ConversionConfig & getConfig() const
Return the configuration of the current dialect conversion.
void replaceOpWithMultiple(Operation *op, SmallVector< SmallVector< Value >> &&newValues)
Replace the given operation with the new value ranges.
Block * applySignatureConversion(Block *block, TypeConverter::SignatureConversion &conversion, const TypeConverter *converter=nullptr)
Apply a signature conversion to given block.
void replaceOpWithMultiple(Operation *op, ArrayRef< RangeT > newValues)
void startOpModification(Operation *op) override
PatternRewriter hook for updating the given operation in-place.
void eraseOp(Operation *op) override
PatternRewriter hook for erasing a dead operation.
void replaceOpWithMultiple(Operation *op, RangeT &&newValues)
detail::ConversionPatternRewriterImpl & getImpl()
Return a reference to the internal implementation.
void inlineBlockBefore(Block *source, Block *dest, Block::iterator before, ValueRange argValues={}) override
PatternRewriter hook for inlining the ops of a block into another block.
void eraseBlock(Block *block) override
PatternRewriter hook for erase all operations in a block.
void cancelOpModification(Operation *op) override
PatternRewriter hook for updating the given operation in-place.
bool canRecoverFromRewriteFailure() const override
Indicate that the conversion rewriter can recover from rewrite failure.
Value getRemappedValue(Value key)
Return the converted value of 'key' with a type defined by the type converter of the currently execut...
void finalizeOpModification(Operation *op) override
PatternRewriter hook for updating the given operation in-place.
void replaceUsesOfBlockArgument(BlockArgument from, ValueRange to)
Replace all the uses of the block argument from with to.
Base class for the conversion patterns.
FailureOr< SmallVector< Value > > getOneToOneAdaptorOperands(ArrayRef< ValueRange > operands) const
Given an array of value ranges, which are the inputs to a 1:N adaptor, try to extract the single valu...
static LogicalResult dispatchTo1To1(const SelfPattern &self, SourceOp op, ArrayRef< ValueRange > operands, ConversionPatternRewriter &rewriter)
Overloaded method used to dispatch to the 1:1 'matchAndRewrite' method if possible and emit diagnosti...
const TypeConverter * typeConverter
An optional type converter for use by this pattern.
ConversionPattern(const TypeConverter &typeConverter, Args &&...args)
Construct a conversion pattern with the given converter, and forward the remaining arguments to Rewri...
const TypeConverter * getTypeConverter() const
Return the type converter held by this pattern, or nullptr if the pattern does not require type conve...
std::enable_if_t< std::is_base_of< TypeConverter, ConverterTy >::value, const ConverterTy * > getTypeConverter() const
virtual LogicalResult matchAndRewrite(Operation *op, ArrayRef< Value > operands, ConversionPatternRewriter &rewriter) const
Hook for derived classes to implement combined matching and rewriting.
virtual LogicalResult matchAndRewrite(Operation *op, ArrayRef< ValueRange > operands, ConversionPatternRewriter &rewriter) const
Hook for derived classes to implement combined matching and rewriting.
This class describes a specific conversion target.
void setDialectAction(ArrayRef< StringRef > dialectNames, LegalizationAction action)
Register a legality action for the given dialects.
void setOpAction(LegalizationAction action)
void addLegalOp(OperationName op)
Register the given operations as legal.
void addDynamicallyLegalDialect(DynamicLegalityCallbackFn callback)
void setOpAction(OperationName op, LegalizationAction action)
Register a legality action for the given operation.
void addDynamicallyLegalDialect(const DynamicLegalityCallbackFn &callback, StringRef name, Names... names)
Register the operations of the given dialects as dynamically legal, i.e.
void addDynamicallyLegalOp(const DynamicLegalityCallbackFn &callback)
void addLegalDialect(StringRef name, Names... names)
Register the operations of the given dialects as legal.
std::optional< LegalOpDetails > isLegal(Operation *op) const
If the given operation instance is legal on this target, a structure containing legality information ...
std::enable_if_t<!std::is_invocable_v< Callable, Operation * > > markOpRecursivelyLegal(Callable &&callback)
void markUnknownOpDynamicallyLegal(const DynamicLegalityCallbackFn &fn)
Register unknown operations as dynamically legal.
std::optional< LegalizationAction > getOpAction(OperationName op) const
Get the legality action for the given operation.
void addDynamicallyLegalOp(OperationName op, const DynamicLegalityCallbackFn &callback)
Register the given operation as dynamically legal and set the dynamic legalization callback to the on...
void addIllegalDialect(StringRef name, Names... names)
Register the operations of the given dialects as illegal, i.e.
std::enable_if_t<!std::is_invocable_v< Callable, Operation * > > addDynamicallyLegalOp(Callable &&callback)
void addDynamicallyLegalOp(const DynamicLegalityCallbackFn &callback)
void markOpRecursivelyLegal(const DynamicLegalityCallbackFn &callback={})
void addIllegalOp(OperationName op)
Register the given operation as illegal, i.e.
LegalizationAction
This enumeration corresponds to the specific action to take when considering an operation legal for t...
@ Illegal
The target explicitly does not support this operation.
@ Dynamic
This operation has dynamic legalization constraints that must be checked by the target.
@ Legal
The target supports this operation.
ConversionTarget(MLIRContext &ctx)
void markOpRecursivelyLegal(OperationName name, const DynamicLegalityCallbackFn &callback)
Mark an operation, that must have either been set as Legal or DynamicallyLegal, as being recursively ...
void markOpRecursivelyLegal(const DynamicLegalityCallbackFn &callback={})
std::function< std::optional< bool >(Operation *)> DynamicLegalityCallbackFn
The signature of the callback used to determine if an operation is dynamically legal on the target.
bool isIllegal(Operation *op) const
Returns true is operation instance is illegal on this target.
virtual ~ConversionTarget()=default
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
Definition: Diagnostics.h:155
This class represents a frozen set of patterns that can be processed by a pattern applicator.
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:76
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:63
This class helps build Operations.
Definition: Builders.h:205
void setListener(Listener *newListener)
Sets the listener of this builder to the one provided.
Definition: Builders.h:314
OpConversionPattern is a wrapper around ConversionPattern that allows for matching and rewriting agai...
LogicalResult matchAndRewrite(Operation *op, ArrayRef< ValueRange > operands, ConversionPatternRewriter &rewriter) const final
Hook for derived classes to implement combined matching and rewriting.
typename SourceOp::Adaptor OpAdaptor
virtual LogicalResult matchAndRewrite(SourceOp op, OneToNOpAdaptor adaptor, ConversionPatternRewriter &rewriter) const
OpConversionPattern(MLIRContext *context, PatternBenefit benefit=1)
typename SourceOp::template GenericAdaptor< ArrayRef< ValueRange > > OneToNOpAdaptor
OpConversionPattern(const TypeConverter &typeConverter, MLIRContext *context, PatternBenefit benefit=1)
virtual LogicalResult matchAndRewrite(SourceOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const
Methods that operate on the SourceOp type.
LogicalResult matchAndRewrite(Operation *op, ArrayRef< Value > operands, ConversionPatternRewriter &rewriter) const final
Wrappers around the ConversionPattern methods that pass the derived op type.
OpInterfaceConversionPattern is a wrapper around ConversionPattern that allows for matching and rewri...
LogicalResult matchAndRewrite(Operation *op, ArrayRef< ValueRange > operands, ConversionPatternRewriter &rewriter) const final
Hook for derived classes to implement combined matching and rewriting.
virtual LogicalResult matchAndRewrite(SourceOp op, ArrayRef< ValueRange > operands, ConversionPatternRewriter &rewriter) const
LogicalResult matchAndRewrite(Operation *op, ArrayRef< Value > operands, ConversionPatternRewriter &rewriter) const final
Wrappers around the ConversionPattern methods that pass the derived op type.
OpInterfaceConversionPattern(MLIRContext *context, PatternBenefit benefit=1)
OpInterfaceConversionPattern(const TypeConverter &typeConverter, MLIRContext *context, PatternBenefit benefit=1)
virtual LogicalResult matchAndRewrite(SourceOp op, ArrayRef< Value > operands, ConversionPatternRewriter &rewriter) const
Methods that operate on the SourceOp type.
OpTraitConversionPattern is a wrapper around ConversionPattern that allows for matching and rewriting...
OpTraitConversionPattern(const TypeConverter &typeConverter, MLIRContext *context, PatternBenefit benefit=1)
OpTraitConversionPattern(MLIRContext *context, PatternBenefit benefit=1)
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
A PDL configuration that is used to supported dialect conversion functionality.
void notifyRewriteEnd(PatternRewriter &rewriter) final
void notifyRewriteBegin(PatternRewriter &rewriter) final
Hooks that are invoked at the beginning and end of a rewrite of a matched pattern.
const TypeConverter * getTypeConverter() const
Return the type converter used by this configuration, which may be nullptr if no type conversions are...
PDLConversionConfig(const TypeConverter *converter)
~PDLConversionConfig() final=default
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
Definition: PatternMatch.h:34
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
Definition: PatternMatch.h:783
This class contains all of the data related to a pattern, but does not contain any methods or logic f...
Definition: PatternMatch.h:73
StringRef getDebugName() const
Return a readable name for this pattern.
Definition: PatternMatch.h:140
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
RewritePattern is the common base class for all DAG to DAG replacements.
Definition: PatternMatch.h:238
std::enable_if_t<!std::is_convertible< CallbackT, Twine >::value, LogicalResult > notifyMatchFailure(Location loc, CallbackT &&reasonCallback)
Used to notify the listener that the IR failed to be rewritten because of a match failure,...
Definition: PatternMatch.h:716
virtual void inlineBlockBefore(Block *source, Block *dest, Block::iterator before, ValueRange argValues={})
Inline the operations of block 'source' into block 'dest' before the given position.
The general result of a type attribute conversion callback, allowing for early termination.
static AttributeConversionResult result(Attribute attr)
This class provides all of the information necessary to convert a type signature.
void addInputs(unsigned origInputNo, ArrayRef< Type > types)
Remap an input of the original signature with a new set of types.
std::optional< InputMapping > getInputMapping(unsigned input) const
Get the input mapping for the given argument.
ArrayRef< Type > getConvertedTypes() const
Return the argument types for the new signature.
void remapInput(unsigned origInputNo, ArrayRef< Value > replacements)
Remap an input of the original signature to replacements values.
Type conversion class.
std::optional< Attribute > convertTypeAttribute(Type type, Attribute attr) const
Convert an attribute present attr from within the type type using the registered conversion functions...
Value materializeSourceConversion(OpBuilder &builder, Location loc, Type resultType, ValueRange inputs) const
Materialize a conversion from a set of types into one result type by generating a cast sequence of so...
void addConversion(FnT &&callback)
Register a conversion function.
bool isLegal(ValueRange range) const
bool isLegal(Type type) const
Return true if the given type is legal for this type converter, i.e.
LogicalResult convertSignatureArgs(TypeRange types, SignatureConversion &result, unsigned origInputOffset=0) const
TypeConverter()=default
TargetType convertType(Type t) const
Attempts a 1-1 type conversion, expecting the result type to be TargetType.
LogicalResult convertSignatureArg(unsigned inputNo, Type type, SignatureConversion &result) const
This method allows for converting a specific argument of a signature.
TypeConverter(const TypeConverter &other)
TypeConverter & operator=(const TypeConverter &other)
bool isLegal(TypeRange range) const
Return true if all of the given types are legal for this type converter.
LogicalResult convertType(Type t, SmallVectorImpl< Type > &results) const
Convert the given type.
std::optional< SignatureConversion > convertBlockSignature(Block *block) const
This function converts the type signature of the given block, by invoking 'convertSignatureArg' for e...
void addSourceMaterialization(FnT &&callback)
All of the following materializations require function objects that are convertible to the following ...
virtual ~TypeConverter()=default
void addTypeAttributeConversion(FnT &&callback)
Register a conversion function for attributes within types.
void addTargetMaterialization(FnT &&callback)
This method registers a materialization that will be called when converting a value to a target type ...
LogicalResult convertTypes(TypeRange types, SmallVectorImpl< Type > &results) const
Convert the given types, filling 'results' as necessary.
bool isSignatureLegal(FunctionType ty) const
Return true if the inputs and outputs of the given function type are legal.
TargetType convertType(Value v) const
Value materializeTargetConversion(OpBuilder &builder, Location loc, Type resultType, ValueRange inputs, Type originalType={}) const
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:107
This class provides an abstraction over the various different ranges of value types.
Definition: TypeRange.h:37
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:387
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
@ Type
An inlay hint that for a type annotation.
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition: Remarks.h:491
Include the generated interface declarations.
void populateFunctionOpInterfaceTypeConversionPattern(StringRef functionLikeOpName, RewritePatternSet &patterns, const TypeConverter &converter)
Add a pattern to the given pattern list to convert the signature of a FunctionOpInterface op with the...
void populateAnyFunctionOpInterfaceTypeConversionPattern(RewritePatternSet &patterns, const TypeConverter &converter)
DialectConversionFoldingMode
An enum to control folding behavior during dialect conversion.
@ Never
Never attempt to fold.
@ AfterPatterns
Only attempt to fold not legal operations after applying patterns.
@ BeforePatterns
Only attempt to fold not legal operations before applying patterns.
const FrozenRewritePatternSet GreedyRewriteConfig config
LogicalResult applyFullConversion(ArrayRef< Operation * > ops, const ConversionTarget &target, const FrozenRewritePatternSet &patterns, ConversionConfig config=ConversionConfig())
Apply a complete conversion on the given operations, and all nested operations.
FailureOr< Operation * > convertOpResultTypes(Operation *op, ValueRange operands, const TypeConverter &converter, ConversionPatternRewriter &rewriter)
Generic utility to convert op result types according to type converter without knowing exact op type.
const FrozenRewritePatternSet & patterns
LogicalResult applyAnalysisConversion(ArrayRef< Operation * > ops, ConversionTarget &target, const FrozenRewritePatternSet &patterns, ConversionConfig config=ConversionConfig())
Apply an analysis conversion on the given operations, and all nested operations.
void reconcileUnrealizedCasts(ArrayRef< UnrealizedConversionCastOp > castOps, SmallVectorImpl< UnrealizedConversionCastOp > *remainingCastOps=nullptr)
Try to reconcile all given UnrealizedConversionCastOps and store the left-over ops in remainingCastOp...
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
void registerConversionPDLFunctions(RewritePatternSet &patterns)
Register the dialect conversion PDL functions with the given pattern set.
LogicalResult applyPartialConversion(ArrayRef< Operation * > ops, const ConversionTarget &target, const FrozenRewritePatternSet &patterns, ConversionConfig config=ConversionConfig())
Below we define several entry points for operation conversion.
Dialect conversion configuration.
bool allowPatternRollback
If set to "true", pattern rollback is allowed.
RewriterBase::Listener * listener
An optional listener that is notified about all IR modifications in case dialect conversion succeeds.
DialectConversionFoldingMode foldingMode
The folding mode to use during conversion.
function_ref< void(Diagnostic &)> notifyCallback
An optional callback used to notify about match failure diagnostics during the conversion.
DenseSet< Operation * > * legalizableOps
Analysis conversion only.
bool attachDebugMaterializationKind
If set to "true", the materialization kind ("source" or "target") will be attached to "builtin....
DenseSet< Operation * > * unlegalizedOps
Partial conversion only.
bool buildMaterializations
If set to "true", the dialect conversion attempts to build source/target materializations through the...
A structure containing additional information describing a specific legal operation instance.
bool isRecursivelyLegal
A flag that indicates if this operation is 'recursively' legal.
This class acts as a special tag that makes the desire to match any operation that implements a given...
Definition: PatternMatch.h:164
This class acts as a special tag that makes the desire to match any operation that implements a given...
Definition: PatternMatch.h:169
This struct represents a range of new types or a range of values that remaps an existing signature in...
bool replacedWithValues() const
Return "true" if this input was replaces with one or multiple values.