MLIR  16.0.0git
TransformInterfaces.h
Go to the documentation of this file.
1 //===- TransformInterfaces.h - Transform Dialect Interfaces -----*- 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 #ifndef MLIR_DIALECT_TRANSFORM_IR_TRANSFORMINTERFACES_H
10 #define MLIR_DIALECT_TRANSFORM_IR_TRANSFORMINTERFACES_H
11 
12 #include "mlir/IR/OpDefinition.h"
13 
16 #include "llvm/ADT/ScopeExit.h"
17 
18 namespace mlir {
19 
20 /// The result of a transform IR operation application. This can have one of the
21 /// three states:
22 /// - success;
23 /// - silenceable (recoverable) failure with yet-unreported diagnostic;
24 /// - definite failure.
25 /// Silenceable failure is intended to communicate information about
26 /// transformations that did not apply but in a way that supports recovery,
27 /// for example, they did not modify the payload IR or modified it in some
28 /// predictable way. They are associated with a Diagnostic that provides more
29 /// details on the failure. Silenceable failure can be discarded, turning the
30 /// result into success, or "reported", emitting the diagnostic and turning the
31 /// result into definite failure.
32 /// Transform IR operations containing other operations are allowed to do either
33 /// with the results of the nested transformations, but must propagate definite
34 /// failures as their diagnostics have been already reported to the user.
35 class [[nodiscard]] DiagnosedSilenceableFailure {
36 public:
37  explicit DiagnosedSilenceableFailure(LogicalResult result) : result(result) {}
44 
45  /// Constructs a DiagnosedSilenceableFailure in the success state.
48  }
49 
50  /// Constructs a DiagnosedSilenceableFailure in the failure state. Typically,
51  /// a diagnostic has been emitted before this.
54  }
55 
56  /// Constructs a DiagnosedSilenceableFailure in the silenceable failure state,
57  /// ready to emit the given diagnostic. This is considered a failure
58  /// regardless of the diagnostic severity.
60  return DiagnosedSilenceableFailure(std::forward<Diagnostic>(diag));
61  }
65  std::forward<SmallVector<Diagnostic>>(diag));
66  }
67 
68  /// Converts all kinds of failure into a LogicalResult failure, emitting the
69  /// diagnostic if necessary. Must not be called more than once.
71 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
72  assert(!reported && "attempting to report a diagnostic more than once");
73  reported = true;
74 #endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
75  if (!diagnostics.empty()) {
76  for (auto &&diagnostic : diagnostics) {
77  diagnostic.getLocation().getContext()->getDiagEngine().emit(
78  std::move(diagnostic));
79  }
80  diagnostics.clear();
81  result = ::mlir::failure();
82  }
83  return result;
84  }
85 
86  /// Returns `true` if this is a success.
87  bool succeeded() const {
88  return ::mlir::succeeded(result) && diagnostics.empty();
89  }
90 
91  /// Returns `true` if this is a definite failure.
92  bool isDefiniteFailure() const {
93  return ::mlir::failed(result) && diagnostics.empty();
94  }
95 
96  /// Returns `true` if this is a silenceable failure.
97  bool isSilenceableFailure() const { return !diagnostics.empty(); }
98 
99  /// Returns the diagnostic message without emitting it. Expects this object
100  /// to be a silenceable failure.
101  std::string getMessage() const {
102  std::string res;
103  for (auto &diagnostic : diagnostics) {
104  res.append(diagnostic.str());
105  res.append("\n");
106  }
107  return res;
108  }
109 
110  /// Returns a string representation of the failure mode (for error reporting).
111  std::string getStatusString() const {
112  if (succeeded())
113  return "success";
114  if (isSilenceableFailure())
115  return "silenceable failure";
116  return "definite failure";
117  }
118 
119  /// Converts silenceable failure into LogicalResult success without reporting
120  /// the diagnostic, preserves the other states.
122  if (!diagnostics.empty()) {
123  diagnostics.clear();
124  result = ::mlir::success();
125  }
126  return result;
127  }
128 
129  /// Take the diagnostics and silence.
131  assert(!diagnostics.empty() && "expected a diagnostic to be present");
132  diags.append(std::make_move_iterator(diagnostics.begin()),
133  std::make_move_iterator(diagnostics.end()));
134  }
135 
136  /// Streams the given values into the last diagnostic.
137  /// Expects this object to be a silenceable failure.
138  template <typename T>
140  assert(isSilenceableFailure() &&
141  "can only append output in silenceable failure state");
142  diagnostics.back() << std::forward<T>(value);
143  return *this;
144  }
145  template <typename T>
147  return std::move(this->operator<<(std::forward<T>(value)));
148  }
149 
150  /// Attaches a note to the last diagnostic.
151  /// Expects this object to be a silenceable failure.
153  assert(isSilenceableFailure() &&
154  "can only attach notes to silenceable failures");
155  return diagnostics.back().attachNote(loc);
156  }
157 
158 private:
159  explicit DiagnosedSilenceableFailure(Diagnostic &&diagnostic)
160  : result(failure()) {
161  diagnostics.emplace_back(std::move(diagnostic));
162  }
163  explicit DiagnosedSilenceableFailure(SmallVector<Diagnostic> &&diagnostics)
164  : diagnostics(std::move(diagnostics)), result(failure()) {}
165 
166  /// The diagnostics associated with this object. If non-empty, the object is
167  /// considered to be in the silenceable failure state regardless of the
168  /// `result` field.
169  SmallVector<Diagnostic, 1> diagnostics;
170 
171  /// The "definite" logical state, either success or failure.
172  /// Ignored if the diagnostics message is present.
173  LogicalResult result;
174 
175 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
176  /// Whether the associated diagnostics have been reported.
177  /// Diagnostics reporting consumes the diagnostics, so we need a mechanism to
178  /// differentiate reported diagnostics from a state where it was never
179  /// created.
180  bool reported = false;
181 #endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
182 };
183 
184 class DiagnosedDefiniteFailure;
185 
186 DiagnosedDefiniteFailure emitDefiniteFailure(Location loc,
187  const Twine &message = {});
188 
189 /// A compatibility class connecting `InFlightDiagnostic` to
190 /// `DiagnosedSilenceableFailure` while providing an interface similar to the
191 /// former. Implicitly convertible to `DiagnosticSilenceableFailure` in definite
192 /// failure state and to `LogicalResult` failure. Reports the error on
193 /// conversion or on destruction. Instances of this class can be created by
194 /// `emitDefiniteFailure()`.
197  const Twine &message);
198 
199 public:
200  /// Only move-constructible because it carries an in-flight diagnostic.
202 
203  /// Forward the message to the diagnostic.
204  template <typename T>
206  diag << std::forward<T>(value);
207  return *this;
208  }
209  template <typename T>
211  return std::move(this->operator<<(std::forward<T>(value)));
212  }
213 
214  /// Attaches a note to the error.
216  return diag.attachNote(loc);
217  }
218 
219  /// Implicit conversion to DiagnosedSilenceableFailure in the definite failure
220  /// state. Reports the error.
222  diag.report();
224  }
225 
226  /// Implicit conversion to LogicalResult in the failure state. Reports the
227  /// error.
228  operator LogicalResult() {
229  diag.report();
230  return failure();
231  }
232 
233 private:
234  /// Constructs a definite failure at the given location with the given
235  /// message.
236  explicit DiagnosedDefiniteFailure(Location loc, const Twine &message)
237  : diag(emitError(loc, message)) {}
238 
239  /// Copy-construction and any assignment is disallowed to prevent repeated
240  /// error reporting.
243  operator=(const DiagnosedDefiniteFailure &) = delete;
244  DiagnosedDefiniteFailure &operator=(DiagnosedDefiniteFailure &&) = delete;
245 
246  /// The error message.
247  InFlightDiagnostic diag;
248 };
249 
250 /// Emits a definite failure with the given message. The returned object allows
251 /// for last-minute modification to the error message, such as attaching notes
252 /// and completing the message. It will be reported when the object is
253 /// destructed or converted.
255  const Twine &message) {
256  return DiagnosedDefiniteFailure(loc, message);
257 }
259  const Twine &message = {}) {
260  return emitDefiniteFailure(op->getLoc(), message);
261 }
262 
263 /// Emits a silenceable failure with the given message. A silenceable failure
264 /// must be either suppressed or converted into a definite failure and reported
265 /// to the user.
266 inline DiagnosedSilenceableFailure
267 emitSilenceableFailure(Location loc, const Twine &message = {}) {
268  Diagnostic diag(loc, DiagnosticSeverity::Error);
269  diag << message;
271 }
272 inline DiagnosedSilenceableFailure
273 emitSilenceableFailure(Operation *op, const Twine &message = {}) {
274  return emitSilenceableFailure(op->getLoc(), message);
275 }
276 
277 namespace transform {
278 
279 class TransformOpInterface;
280 
281 /// Options controlling the application of transform operations by the
282 /// TransformState.
284 public:
286 
287  /// Requests computationally expensive checks of the transform and payload IR
288  /// well-formedness to be performed before each transformation. In particular,
289  /// these ensure that the handles still point to valid operations when used.
291  expensiveChecksEnabled = enable;
292  return *this;
293  }
294 
295  /// Returns true if the expensive checks are requested.
296  bool getExpensiveChecksEnabled() const { return expensiveChecksEnabled; }
297 
298 private:
299  bool expensiveChecksEnabled = true;
300 };
301 
302 /// Entry point to the Transform dialect infrastructure. Applies the
303 /// transformation specified by `transform` to payload IR contained in
304 /// `payloadRoot`. The `transform` operation may contain other operations that
305 /// will be executed following the internal logic of the operation. It must
306 /// have the `PossibleTopLevelTransformOp` trait and not have any operands.
307 /// This function internally keeps track of the transformation state.
309 applyTransforms(Operation *payloadRoot, TransformOpInterface transform,
310  const TransformOptions &options = TransformOptions());
311 
312 /// The state maintained across applications of various ops implementing the
313 /// TransformOpInterface. The operations implementing this interface and the
314 /// surrounding structure are referred to as transform IR. The operations to
315 /// which transformations apply are referred to as payload IR. The state thus
316 /// contains the many-to-many mapping between values defined in the transform IR
317 /// ops and payload IR ops. The "expensive-checks" option can be passed to
318 /// the constructor at transformation execution time that transform IR values
319 /// used as operands by a transform IR operation are not associated with
320 /// dangling pointers to payload IR operations that are known to have been
321 /// erased by previous transformation through the same or a different transform
322 /// IR value.
323 ///
324 /// A reference to this class is passed as an argument to "apply" methods of the
325 /// transform op interface. Thus the "apply" method can call
326 /// `state.getPayloadOps( getSomeOperand() )` to obtain the list of operations
327 /// associated with its operand and subject to transformation. The method is
328 /// expected to populate the `TransformResults` class instance in order to
329 /// update the mapping. The `applyTransform` method takes care of propagating
330 /// the state of `TransformResults` into the instance of this class.
331 ///
332 /// When applying transform IR operations with regions, the client is expected
333 /// to create a RegionScope RAII object to create a new "stack frame" for
334 /// values defined inside the region. The mappings from and to these values will
335 /// be automatically dropped when the object goes out of scope, typically at the
336 /// end of the "apply" function of the parent operation. If a region contains
337 /// blocks with arguments, the client can map those arguments to payload IR ops
338 /// using "mapBlockArguments".
340  /// Mapping between a Value in the transform IR and the corresponding set of
341  /// operations in the payload IR.
343 
344  /// Mapping between a payload IR operation and the transform IR values it is
345  /// associated with.
348 
349  /// Bidirectional mappings between transform IR values and payload IR
350  /// operations.
351  struct Mappings {
352  TransformOpMapping direct;
354  };
355 
357  TransformOpInterface transform,
358  const TransformOptions &options);
359 
360 public:
361  /// Returns the op at which the transformation state is rooted. This is
362  /// typically helpful for transformations that apply globally.
363  Operation *getTopLevel() const;
364 
365  /// Returns the list of ops that the given transform IR value corresponds to.
366  /// This is helpful for transformations that apply to a particular handle.
368 
369  /// Populates `handles` with all handles pointing to the given Payload IR op.
370  /// Returns success if such handles exist, failure otherwise.
372  SmallVectorImpl<Value> &handles) const;
373 
374  /// Applies the transformation specified by the given transform op and updates
375  /// the state accordingly.
376  DiagnosedSilenceableFailure applyTransform(TransformOpInterface transform);
377 
378  /// Records the mapping between a block argument in the transform IR and a
379  /// list of operations in the payload IR. The arguments must be defined in
380  /// blocks of the currently processed transform IR region, typically after a
381  /// region scope is defined.
382  ///
383  /// Returns failure if the payload does not satisfy the conditions associated
384  /// with the type of the handle value.
386  ArrayRef<Operation *> operations) {
387 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
388  assert(argument.getParentRegion() == regionStack.back() &&
389  "mapping block arguments from a region other than the active one");
390 #endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
391  return setPayloadOps(argument, operations);
392  }
393 
394  // Forward declarations to support limited visibility.
395  class RegionScope;
396 
397  /// Creates a new region scope for the given region. The region is expected to
398  /// be nested in the currently processed region.
399  // Implementation note: this method is inline but implemented outside of the
400  // class body to comply with visibility and full-declaration requirements.
401  inline RegionScope make_region_scope(Region &region);
402 
403  /// A RAII object maintaining a "stack frame" for a transform IR region. When
404  /// applying a transform IR operation that contains a region, the caller is
405  /// expected to create a RegionScope before applying the ops contained in the
406  /// region. This ensures that the mappings between values defined in the
407  /// transform IR region and payload IR operations are cleared when the region
408  /// processing ends; such values cannot be accessed outside the region.
409  class RegionScope {
410  public:
411  /// Forgets the mapping from or to values defined in the associated
412  /// transform IR region.
414  state.mappings.erase(region);
415 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
416  state.regionStack.pop_back();
417 #endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
418  }
419 
420  private:
421  /// Creates a new scope for mappings between values defined in the given
422  /// transform IR region and payload IR operations.
423  RegionScope(TransformState &state, Region &region)
424  : state(state), region(&region) {
425  auto res = state.mappings.try_emplace(this->region);
426  assert(res.second && "the region scope is already present");
427  (void)res;
428 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
429  assert(state.regionStack.back()->isProperAncestor(&region) &&
430  "scope started at a non-nested region");
431  state.regionStack.push_back(&region);
432 #endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
433  }
434 
435  /// Back-reference to the transform state.
436  TransformState &state;
437 
438  /// The region this scope is associated with.
439  Region *region;
440 
442  };
443  friend class RegionScope;
444 
445  /// Base class for TransformState extensions that allow TransformState to
446  /// contain user-specified information in the state object. Clients are
447  /// expected to derive this class, add the desired fields, and make the
448  /// derived class compatible with the MLIR TypeID mechanism:
449  ///
450  /// ```mlir
451  /// class MyExtension final : public TransformState::Extension {
452  /// public:
453  /// MyExtension(TranfsormState &state, int myData)
454  /// : Extension(state) {...}
455  /// private:
456  /// int mySupplementaryData;
457  /// };
458  /// ```
459  ///
460  /// Instances of this and derived classes are not expected to be created by
461  /// the user, instead they are directly constructed within a TransformState. A
462  /// TransformState can only contain one extension with the given TypeID.
463  /// Extensions can be obtained from a TransformState instance, and can be
464  /// removed when they are no longer required.
465  ///
466  /// ```mlir
467  /// transformState.addExtension<MyExtension>(/*myData=*/42);
468  /// MyExtension *ext = transformState.getExtension<MyExtension>();
469  /// ext->doSomething();
470  /// ```
471  class Extension {
472  // Allow TransformState to allocate Extensions.
473  friend class TransformState;
474 
475  public:
476  /// Base virtual destructor.
477  // Out-of-line definition ensures symbols are emitted in a single object
478  // file.
479  virtual ~Extension();
480 
481  protected:
482  /// Constructs an extension of the given TransformState object.
483  Extension(TransformState &state) : state(state) {}
484 
485  /// Provides read-only access to the parent TransformState object.
486  const TransformState &getTransformState() const { return state; }
487 
488  /// Replaces the given payload op with another op. If the replacement op is
489  /// null, removes the association of the payload op with its handle. Returns
490  /// failure if the op is not associated with any handle.
492 
493  private:
494  /// Back-reference to the state that is being extended.
495  TransformState &state;
496  };
497 
498  /// Adds a new Extension of the type specified as template parameter,
499  /// constructing it with the arguments provided. The extension is owned by the
500  /// TransformState. It is expected that the state does not already have an
501  /// extension of the same type. Extension constructors are expected to take
502  /// a reference to TransformState as first argument, automatically supplied
503  /// by this call.
504  template <typename Ty, typename... Args>
505  Ty &addExtension(Args &&...args) {
506  static_assert(
508  "only an class derived from TransformState::Extension is allowed here");
509  auto ptr = std::make_unique<Ty>(*this, std::forward<Args>(args)...);
510  auto result = extensions.try_emplace(TypeID::get<Ty>(), std::move(ptr));
511  assert(result.second && "extension already added");
512  return *static_cast<Ty *>(result.first->second.get());
513  }
514 
515  /// Returns the extension of the specified type.
516  template <typename Ty>
517  Ty *getExtension() {
518  static_assert(
520  "only an class derived from TransformState::Extension is allowed here");
521  auto iter = extensions.find(TypeID::get<Ty>());
522  if (iter == extensions.end())
523  return nullptr;
524  return static_cast<Ty *>(iter->second.get());
525  }
526 
527  /// Removes the extension of the specified type.
528  template <typename Ty>
530  static_assert(
532  "only an class derived from TransformState::Extension is allowed here");
533  extensions.erase(TypeID::get<Ty>());
534  }
535 
536 private:
537  /// Identifier for storing top-level value in the `operations` mapping.
538  static constexpr Value kTopLevelValue = Value();
539 
540  /// Creates a state for transform ops living in the given region. The second
541  /// argument points to the root operation in the payload IR being transformed,
542  /// which may or may not contain the region with transform ops. Additional
543  /// options can be provided through the trailing configuration object.
544  TransformState(Region *region, Operation *payloadRoot,
546 
547  /// Returns the mappings frame for the reigon in which the value is defined.
548  const Mappings &getMapping(Value value) const {
549  return const_cast<TransformState *>(this)->getMapping(value);
550  }
551  Mappings &getMapping(Value value) {
552  auto it = mappings.find(value.getParentRegion());
553  assert(it != mappings.end() &&
554  "trying to find a mapping for a value from an unmapped region");
555  return it->second;
556  }
557 
558  /// Returns the mappings frame for the region in which the operation resides.
559  const Mappings &getMapping(Operation *operation) const {
560  return const_cast<TransformState *>(this)->getMapping(operation);
561  }
562  Mappings &getMapping(Operation *operation) {
563  auto it = mappings.find(operation->getParentRegion());
564  assert(it != mappings.end() &&
565  "trying to find a mapping for an operation from an unmapped region");
566  return it->second;
567  }
568 
569  /// Removes the mapping between the given payload IR operation and the given
570  /// transform IR value.
571  void dropReverseMapping(Mappings &mappings, Operation *op, Value value);
572 
573  /// Sets the payload IR ops associated with the given transform IR value
574  /// (handle). A payload op may be associated multiple handles as long as
575  /// at most one of them gets consumed by further transformations.
576  /// For example, a hypothetical "find function by name" may be called twice in
577  /// a row to produce two handles pointing to the same function:
578  ///
579  /// %0 = transform.find_func_by_name { name = "myfunc" }
580  /// %1 = transform.find_func_by_name { name = "myfunc" }
581  ///
582  /// which is valid by itself. However, calling a hypothetical "rewrite and
583  /// rename function" transform on both handles:
584  ///
585  /// transform.rewrite_and_rename %0 { new_name = "func" }
586  /// transform.rewrite_and_rename %1 { new_name = "func" }
587  ///
588  /// is invalid given the transformation "consumes" the handle as expressed
589  /// by side effects. Practically, a transformation consuming a handle means
590  /// that the associated payload operation may no longer exist.
591  ///
592  /// Returns failure if the payload does not satisfy the conditions associated
593  /// with the type of the handle value.
594  LogicalResult setPayloadOps(Value value, ArrayRef<Operation *> targets);
595 
596  /// Forgets the payload IR ops associated with the given transform IR value.
597  void removePayloadOps(Value value);
598 
599  /// Updates the payload IR ops associated with the given transform IR value.
600  /// The callback function is called once per associated operation and is
601  /// expected to return the modified operation or nullptr. In the latter case,
602  /// the corresponding operation is no longer associated with the transform IR
603  /// value.
604  ///
605  /// Returns failure if the payload does not satisfy the conditions associated
606  /// with the type of the handle value.
607  LogicalResult
608  updatePayloadOps(Value value,
609  function_ref<Operation *(Operation *)> callback);
610 
611  /// If the operand is a handle consumed by the operation, i.e. has the "free"
612  /// memory effect associated with it, identifies other handles that are
613  /// pointing to payload IR operations nested in the operations pointed to by
614  /// the consumed handle. Marks all such handles as invalidated to trigger
615  /// errors if they are used.
616  void recordHandleInvalidation(OpOperand &handle);
617  void recordHandleInvalidationOne(OpOperand &handle, Operation *payloadOp,
618  Value otherHandle);
619 
620  /// Checks that the operation does not use invalidated handles as operands.
621  /// Reports errors and returns failure if it does. Otherwise, invalidates the
622  /// handles consumed by the operation as well as any handles pointing to
623  /// payload IR operations nested in the operations associated with the
624  /// consumed handles.
625  LogicalResult
626  checkAndRecordHandleInvalidation(TransformOpInterface transform);
627 
628  /// The mappings between transform IR values and payload IR ops, aggregated by
629  /// the region in which the transform IR values are defined.
630  llvm::SmallDenseMap<Region *, Mappings> mappings;
631 
632  /// Extensions attached to the TransformState, identified by the TypeID of
633  /// their type. Only one extension of any given type is allowed.
634  DenseMap<TypeID, std::unique_ptr<Extension>> extensions;
635 
636  /// The top-level operation that contains all payload IR, typically a module.
637  Operation *topLevel;
638 
639  /// Additional options controlling the transformation state behavior.
640  TransformOptions options;
641 
642  /// The mapping from invalidated handles to the error-reporting functions that
643  /// describe when the handles were invalidated. Calling such a function emits
644  /// a user-visible diagnostic with an additional note pointing to the given
645  /// location.
646  DenseMap<Value, std::function<void(Location)>> invalidatedHandles;
647 
648 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
649  /// A stack of nested regions that are being processed in the transform IR.
650  /// Each region must be an ancestor of the following regions in this list.
651  /// These are also the keys for "mappings".
652  SmallVector<Region *> regionStack;
653 #endif // LLVM_ENABLE_ABI_BREAKING_CHECKS
654 };
655 
656 /// Local mapping between values defined by a specific op implementing the
657 /// TransformOpInterface and the payload IR ops they correspond to.
659  friend class TransformState;
660 
661 public:
662  /// Indicates that the result of the transform IR op at the given position
663  /// corresponds to the given list of payload IR ops. Each result must be set
664  /// by the transformation exactly once.
666 
667 private:
668  /// Creates an instance of TransformResults that expects mappings for
669  /// `numSegments` values.
670  explicit TransformResults(unsigned numSegments);
671 
672  /// Gets the list of operations associated with the result identified by its
673  /// number in the list of operation results.
674  ArrayRef<Operation *> get(unsigned resultNumber) const;
675 
676  /// Storage for pointers to payload IR ops that are associated with results of
677  /// a transform IR op. `segments` contains as many entries as the transform IR
678  /// op has results. Each entry is a reference to a contiguous segment in
679  /// the `operations` list that contains the pointers to operations. This
680  /// allows for operations to be stored contiguously without nested vectors and
681  /// for different segments to be set in any order.
683  SmallVector<Operation *> operations;
684 };
685 
687  return RegionScope(*this, region);
688 }
689 
690 namespace detail {
691 /// Maps the only block argument of the op with PossibleTopLevelTransformOpTrait
692 /// to either the list of operations associated with its operand or the root of
693 /// the payload IR, depending on what is available in the context.
696  Operation *op, Region &region);
697 
698 /// Verification hook for PossibleTopLevelTransformOpTrait.
700 } // namespace detail
701 
702 /// This trait is supposed to be attached to Transform dialect operations that
703 /// can be standalone top-level transforms. Such operations typically contain
704 /// other Transform dialect operations that can be executed following some
705 /// control flow logic specific to the current operation. The operations with
706 /// this trait are expected to have at least one single-block region with one
707 /// argument of PDL Operation type. The operations are also expected to be valid
708 /// without operands, in which case they are considered top-level, and with one
709 /// or more arguments, in which case they are considered nested. Top-level
710 /// operations have the block argument of the entry block in the Transform IR
711 /// correspond to the root operation of Payload IR. Nested operations have the
712 /// block argument of the entry block in the Transform IR correspond to a list
713 /// of Payload IR operations mapped to the first operand of the Transform IR
714 /// operation. The operation must implement TransformOpInterface.
715 template <typename OpTy>
717  : public OpTrait::TraitBase<OpTy, PossibleTopLevelTransformOpTrait> {
718 public:
719  /// Verifies that `op` satisfies the invariants of this trait. Not expected to
720  /// be called directly.
723  }
724 
725  /// Returns the single block of the given region.
726  Block *getBodyBlock(unsigned region = 0) {
727  return &this->getOperation()->getRegion(region).front();
728  }
729 
730  /// Sets up the mapping between the entry block of the given region of this op
731  /// and the relevant list of Payload IR operations in the given state. The
732  /// state is expected to be already scoped at the region of this operation.
734  assert(region.getParentOp() == this->getOperation() &&
735  "op comes from the wrong region");
737  state, this->getOperation(), region);
738  }
740  assert(
741  this->getOperation()->getNumRegions() == 1 &&
742  "must indicate the region to map if the operation has more than one");
743  return mapBlockArguments(state, this->getOperation()->getRegion(0));
744  }
745 };
746 
747 /// Trait implementing the TransformOpInterface for operations applying a
748 /// transformation to a single operation handle and producing zero, one or
749 /// multiple operation handles.
750 /// The op must implement a method with the following signature:
751 /// - DiagnosedSilenceableFailure applyToOne(OpTy,
752 /// SmallVector<Operation*> &results, state)
753 /// to perform a transformation that is applied in turn to all payload IR
754 /// operations that correspond to the handle of the transform IR operation.
755 /// In `applyToOne`, OpTy is either Operation* or a concrete payload IR Op class
756 /// that the transformation is applied to (and NOT the class of the transform IR
757 /// op).
758 /// The `applyToOne` method takes an empty `results` vector that it fills with
759 /// zero, one or multiple operations depending on the number of resultd expected
760 /// by the transform op.
761 /// The number of results must match the number of results of the transform op.
762 /// `applyToOne` is allowed to fill the `results` with all null elements to
763 /// signify that the transformation did not apply to the payload IR operations.
764 /// Such null elements are filtered out from results before return.
765 ///
766 /// The transform op having this trait is expected to have a single operand.
767 template <typename OpTy>
769  : public OpTrait::TraitBase<OpTy, TransformEachOpTrait> {
770 public:
771  /// Calls `applyToOne` for every payload operation associated with the operand
772  /// of this transform IR op, the following case disjunction happens:
773  /// 1. If not target payload ops are associated to the operand then fill the
774  /// results vector with the expected number of null elements and return
775  /// success. This is the corner case handling that allows propagating
776  /// the "no-op" case gracefully to improve usability.
777  /// 2. If any `applyToOne` returns definiteFailure, the transformation is
778  /// immediately considered definitely failed and we return.
779  /// 3. All applications of `applyToOne` are checked to return a number of
780  /// results expected by the transform IR op. If not, this is a definite
781  /// failure and we return early.
782  /// 4. If `applyToOne` produces ops, associate them with the result of this
783  /// transform op.
784  /// 5. If any `applyToOne` return silenceableFailure, the transformation is
785  /// considered silenceable.
786  /// 6. Otherwise the transformation is considered successful.
788  TransformState &state);
789 
790  /// Checks that the op matches the expectations of this trait.
791  static LogicalResult verifyTrait(Operation *op);
792 };
793 
794 /// Side effect resource corresponding to the mapping between Transform IR
795 /// values and Payload IR operations. An Allocate effect from this resource
796 /// means creating a new mapping entry, it is always accompanied by a Write
797 /// effet. A Read effect from this resource means accessing the mapping. A Free
798 /// effect on this resource indicates the removal of the mapping entry,
799 /// typically after a transformation that modifies the Payload IR operations
800 /// associated with one of the Transform IR operation's operands. It is always
801 /// accompanied by a Read effect. Read-after-Free and double-Free are not
802 /// allowed (they would be problematic with "regular" memory effects too) as
803 /// they indicate an attempt to access Payload IR operations that have been
804 /// modified, potentially erased, by the previous tranfsormations.
805 // TODO: consider custom effects if these are not enabling generic passes such
806 // as CSE/DCE to work.
808  : public SideEffects::Resource::Base<TransformMappingResource> {
809  StringRef getName() override { return "transform.mapping"; }
810 };
811 
812 /// Side effect resource corresponding to the Payload IR itself. Only Read and
813 /// Write effects are expected on this resource, with Write always accompanied
814 /// by a Read (short of fully replacing the top-level Payload IR operation, one
815 /// cannot modify the Payload IR without reading it first). This is intended
816 /// to disallow reordering of Transform IR operations that mutate the Payload IR
817 /// while still allowing the reordering of those that only access it.
819  : public SideEffects::Resource::Base<PayloadIRResource> {
820  StringRef getName() override { return "transform.payload_ir"; }
821 };
822 
823 /// Populates `effects` with the memory effects indicating the operation on the
824 /// given handle value:
825 /// - consumes = Read + Free,
826 /// - produces = Allocate + Write,
827 /// - onlyReads = Read.
828 void consumesHandle(ValueRange handles,
830 void producesHandle(ValueRange handles,
832 void onlyReadsHandle(ValueRange handles,
834 
835 /// Checks whether the transform op consumes the given handle.
836 bool isHandleConsumed(Value handle, transform::TransformOpInterface transform);
837 
838 /// Populates `effects` with the memory effects indicating the access to payload
839 /// IR resource.
842 
843 /// Trait implementing the MemoryEffectOpInterface for operations that "consume"
844 /// their operands and produce new results.
845 template <typename OpTy>
847  : public OpTrait::TraitBase<OpTy, FunctionalStyleTransformOpTrait> {
848 public:
849  /// This op "consumes" the operands by reading and freeing then, "produces"
850  /// the results by allocating and writing it and reads/writes the payload IR
851  /// in the process.
853  consumesHandle(this->getOperation()->getOperands(), effects);
854  producesHandle(this->getOperation()->getResults(), effects);
855  modifiesPayload(effects);
856  }
857 
858  /// Checks that the op matches the expectations of this trait.
860  if (!op->getName().getInterface<MemoryEffectOpInterface>()) {
861  op->emitError()
862  << "FunctionalStyleTransformOpTrait should only be attached to ops "
863  "that implement MemoryEffectOpInterface";
864  }
865  return success();
866  }
867 };
868 
869 /// Trait implementing the MemoryEffectOpInterface for single-operand
870 /// single-result operations that use their operand without consuming and
871 /// without modifying the Payload IR to produce a new handle.
872 template <typename OpTy>
874  : public OpTrait::TraitBase<OpTy, NavigationTransformOpTrait> {
875 public:
876  /// This op produces handles to the Payload IR without consuming the original
877  /// handles and without modifying the IR itself.
879  onlyReadsHandle(this->getOperation()->getOperands(), effects);
880  producesHandle(this->getOperation()->getResults(), effects);
881  onlyReadsPayload(effects);
882  }
883 
884  /// Checks that the op matches the expectation of this trait.
886  static_assert(OpTy::template hasTrait<OpTrait::OneOperand>(),
887  "expected single-operand op");
888  static_assert(OpTy::template hasTrait<OpTrait::OneResult>(),
889  "expected single-result op");
890  if (!op->getName().getInterface<MemoryEffectOpInterface>()) {
891  op->emitError() << "NavigationTransformOpTrait should only be attached "
892  "to ops that implement MemoryEffectOpInterface";
893  }
894  return success();
895  }
896 };
897 
898 } // namespace transform
899 } // namespace mlir
900 
901 #include "mlir/Dialect/Transform/IR/TransformInterfaces.h.inc"
902 
903 namespace mlir {
904 namespace transform {
905 namespace detail {
906 /// Applies a one-to-one or a one-to-many transform to each of the given
907 /// targets. Puts the results of transforms, if any, in `results` in the same
908 /// order. Fails if any of the application fails. Individual transforms must be
909 /// callable with the following signature:
910 /// - DiagnosedSilenceableFailure(OpTy,
911 /// SmallVector<Operation*> &results, state)
912 /// where OpTy is either
913 /// - Operation *, in which case the transform is always applied;
914 /// - a concrete Op class, in which case a check is performed whether
915 /// `targets` contains operations of the same class and a silenceable failure
916 /// is reported if it does not.
917 template <typename FnTy>
919  Location loc, int expectedNumResults, ArrayRef<Operation *> targets,
920  SmallVectorImpl<SmallVector<Operation *>> &results, FnTy transform) {
921  SmallVector<Diagnostic> silenceableStack;
922  using OpTy = typename llvm::function_traits<FnTy>::template arg_t<0>;
924  "expected transform function to take an operation");
925  for (Operation *target : targets) {
926  // Emplace back a placeholder for the returned new ops.
927  // This is filled with `expectedNumResults` if the op fails to apply.
928  results.push_back(SmallVector<Operation *>());
929 
930  auto specificOp = dyn_cast<OpTy>(target);
931  if (!specificOp) {
933  diag << "transform applied to the wrong op kind";
934  diag.attachNote(target->getLoc()) << "when applied to this op";
935  // Producing `expectedNumResults` nullptr is a silenceableFailure mode.
936  // TODO: encode this implicit `expectedNumResults` nullptr ==
937  // silenceableFailure with a proper trait.
938  results.back().assign(expectedNumResults, nullptr);
939  silenceableStack.push_back(std::move(diag));
940  continue;
941  }
942 
943  DiagnosedSilenceableFailure result = transform(specificOp, results.back());
944  if (result.isDefiniteFailure())
945  return result;
946  if (result.isSilenceableFailure())
947  result.takeDiagnostics(silenceableStack);
948  }
949  if (!silenceableStack.empty()) {
951  std::move(silenceableStack));
952  }
954 }
955 
956 /// Helper function: transpose MxN into NxM; assumes that the input is a valid.
960  if (m.empty())
961  return res;
962  int64_t rows = m.size(), cols = m[0].size();
963  for (int64_t j = 0; j < cols; ++j)
964  res.push_back(SmallVector<Operation *, 1>(rows, nullptr));
965  for (int64_t i = 0; i < rows; ++i) {
966  assert(static_cast<int64_t>(m[i].size()) == cols);
967  for (int64_t j = 0; j < cols; ++j) {
968  res[j][i] = m[i][j];
969  }
970  }
971  return res;
972 }
973 } // namespace detail
974 } // namespace transform
975 } // namespace mlir
976 
977 template <typename OpTy>
980  TransformResults &transformResults, TransformState &state) {
981  using TransformOpType = typename llvm::function_traits<
982  decltype(&OpTy::applyToOne)>::template arg_t<0>;
983  ArrayRef<Operation *> targets =
984  state.getPayloadOps(this->getOperation()->getOperand(0));
985 
986  // Step 1. Handle the corner case where no target is specified.
987  // This is typically the case when the matcher fails to apply and we need to
988  // propagate gracefully.
989  // In this case, we fill all results with an empty vector.
990  if (targets.empty()) {
992  for (auto r : this->getOperation()->getResults())
993  transformResults.set(r.template cast<OpResult>(), empty);
995  }
996 
997  // Step 2. Call applyToOne on each target and record newly produced ops in its
998  // corresponding results entry.
999  int expectedNumResults = this->getOperation()->getNumResults();
1002  this->getOperation()->getLoc(), expectedNumResults, targets, results,
1003  [&](TransformOpType specificOp, SmallVector<Operation *> &partialResult) {
1004  auto res = static_cast<OpTy *>(this)->applyToOne(specificOp,
1005  partialResult, state);
1006  if (res.isDefiniteFailure())
1007  return res;
1008 
1009  // TODO: encode this implicit must always produce `expectedNumResults`
1010  // and nullptr is fine with a proper trait.
1011  if (static_cast<int>(partialResult.size()) != expectedNumResults) {
1012  auto loc = this->getOperation()->getLoc();
1013  auto diag = mlir::emitError(loc, "applications of ")
1014  << OpTy::getOperationName() << " expected to produce "
1015  << expectedNumResults << " results (actually produced "
1016  << partialResult.size() << ").";
1017  diag.attachNote(loc)
1018  << "If you need variadic results, consider a generic `apply` "
1019  << "instead of the specialized `applyToOne`.";
1020  diag.attachNote(loc)
1021  << "Producing " << expectedNumResults << " null results is "
1022  << "allowed if the use case warrants it.";
1023  diag.attachNote(specificOp->getLoc()) << "when applied to this op";
1024  return DiagnosedSilenceableFailure::definiteFailure();
1025  }
1026  // Check that all is null or none is null
1027  // TODO: relax this behavior and encode with a proper trait.
1028  if (llvm::any_of(partialResult, [](Operation *op) { return op; }) &&
1029  llvm::any_of(partialResult, [](Operation *op) { return !op; })) {
1030  auto loc = this->getOperation()->getLoc();
1031  auto diag = mlir::emitError(loc, "unexpected application of ")
1032  << OpTy::getOperationName()
1033  << " produces both null and non null results.";
1034  diag.attachNote(specificOp->getLoc()) << "when applied to this op";
1035  return DiagnosedSilenceableFailure::definiteFailure();
1036  }
1037  return res;
1038  });
1039 
1040  // Step 3. Propagate the definite failure if any and bail out.
1041  if (result.isDefiniteFailure())
1042  return result;
1043 
1044  // Step 4. If there are no results, return early.
1045  if (OpTy::template hasTrait<OpTrait::ZeroResults>())
1046  return result;
1047 
1048  // Step 5. Perform transposition of M applications producing N results each
1049  // into N results for each of the M applications.
1050  SmallVector<SmallVector<Operation *, 1>> transposedResults =
1051  detail::transposeResults(results);
1052 
1053  // Step 6. Single result applies to M ops produces one single M-result.
1054  if (OpTy::template hasTrait<OpTrait::OneResult>()) {
1055  assert(transposedResults.size() == 1 && "Expected single result");
1056  transformResults.set(
1057  this->getOperation()->getResult(0).template cast<OpResult>(),
1058  transposedResults[0]);
1059  // ApplyToOne may have returned silenceableFailure, propagate it.
1060  return result;
1061  }
1062 
1063  // Step 7. Filter out empty results and set the transformResults.
1064  for (const auto &it :
1065  llvm::zip(this->getOperation()->getResults(), transposedResults)) {
1066  SmallVector<Operation *, 1> filtered;
1067  llvm::copy_if(std::get<1>(it), std::back_inserter(filtered),
1068  [](Operation *op) { return op; });
1069  transformResults.set(std::get<0>(it).template cast<OpResult>(), filtered);
1070  }
1071 
1072  // Step 8. ApplyToOne may have returned silenceableFailure, propagate it.
1073  return result;
1074 }
1075 
1076 template <typename OpTy>
1079  static_assert(OpTy::template hasTrait<OpTrait::OneOperand>(),
1080  "expected single-operand op");
1081  if (!op->getName().getInterface<TransformOpInterface>()) {
1082  return op->emitError() << "TransformEachOpTrait should only be attached to "
1083  "ops that implement TransformOpInterface";
1084  }
1085 
1086  return success();
1087 }
1088 
1089 #endif // DIALECT_TRANSFORM_IR_TRANSFORMINTERFACES_H
static std::string diag(llvm::Value &value)
static constexpr const bool value
static llvm::ManagedStatic< PassManagerOptions > options
This class represents an argument of a Block.
Definition: Value.h:296
Block represents an ordered list of Operations.
Definition: Block.h:30
A compatibility class connecting InFlightDiagnostic to DiagnosedSilenceableFailure while providing an...
Diagnostic & attachNote(Optional< Location > loc=llvm::None)
Attaches a note to the error.
friend DiagnosedDefiniteFailure emitDefiniteFailure(Location loc, const Twine &message)
Emits a definite failure with the given message.
DiagnosedDefiniteFailure & operator<<(T &&value) &
Forward the message to the diagnostic.
DiagnosedDefiniteFailure && operator<<(T &&value) &&
DiagnosedDefiniteFailure(DiagnosedDefiniteFailure &&)=default
Only move-constructible because it carries an in-flight diagnostic.
The result of a transform IR operation application.
LogicalResult silence()
Converts silenceable failure into LogicalResult success without reporting the diagnostic,...
static DiagnosedSilenceableFailure success()
Constructs a DiagnosedSilenceableFailure in the success state.
std::string getStatusString() const
Returns a string representation of the failure mode (for error reporting).
DiagnosedSilenceableFailure & operator=(DiagnosedSilenceableFailure &&)=default
std::string getMessage() const
Returns the diagnostic message without emitting it.
DiagnosedSilenceableFailure(DiagnosedSilenceableFailure &&)=default
bool isDefiniteFailure() const
Returns true if this is a definite failure.
static DiagnosedSilenceableFailure silenceableFailure(SmallVector< Diagnostic > &&diag)
LogicalResult checkAndReport()
Converts all kinds of failure into a LogicalResult failure, emitting the diagnostic if necessary.
DiagnosedSilenceableFailure && operator<<(T &&value) &&
DiagnosedSilenceableFailure(const DiagnosedSilenceableFailure &)=delete
static DiagnosedSilenceableFailure silenceableFailure(Diagnostic &&diag)
Constructs a DiagnosedSilenceableFailure in the silenceable failure state, ready to emit the given di...
DiagnosedSilenceableFailure & operator<<(T &&value) &
Streams the given values into the last diagnostic.
void takeDiagnostics(SmallVectorImpl< Diagnostic > &diags)
Take the diagnostics and silence.
bool succeeded() const
Returns true if this is a success.
Diagnostic & attachNote(Optional< Location > loc=llvm::None)
Attaches a note to the last diagnostic.
static DiagnosedSilenceableFailure definiteFailure()
Constructs a DiagnosedSilenceableFailure in the failure state.
DiagnosedSilenceableFailure & operator=(const DiagnosedSilenceableFailure &)=delete
DiagnosedSilenceableFailure(LogicalResult result)
bool isSilenceableFailure() const
Returns true if this is a silenceable failure.
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine.
Definition: Diagnostics.h:155
void report()
Reports the diagnostic to the engine.
Diagnostic & attachNote(Optional< Location > noteLoc=llvm::None)
Attaches a note to this diagnostic.
Definition: Diagnostics.h:345
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:64
This is a value defined by a result of an operation.
Definition: Value.h:442
Helper class for implementing traits.
Definition: OpDefinition.h:310
Operation * getOperation()
Return the ultimate Operation being worked on.
Definition: OpDefinition.h:313
T::Concept * getInterface() const
Returns an instance of the concept object for the given interface if it was registered to this operat...
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:31
Location getLoc()
The source location the operation was defined or derived from.
Definition: Operation.h:154
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:225
Region & getRegion(unsigned index)
Returns the region held by this operation at position 'index'.
Definition: Operation.h:486
OperationName getName()
The name of an operation is the key identifier for it.
Definition: Operation.h:50
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
Operation * getParentOp()
Return the parent operation this region is attached to.
Definition: Region.h:200
Block & back()
Definition: Region.h:64
Block & front()
Definition: Region.h:65
This base class is used for derived effects that are non-parametric.
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:349
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:85
Region * getParentRegion()
Return the Region in which this Value is defined.
Definition: Value.cpp:41
Trait implementing the MemoryEffectOpInterface for operations that "consume" their operands and produ...
void getEffects(SmallVectorImpl< MemoryEffects::EffectInstance > &effects)
This op "consumes" the operands by reading and freeing then, "produces" the results by allocating and...
static LogicalResult verifyTrait(Operation *op)
Checks that the op matches the expectations of this trait.
Trait implementing the MemoryEffectOpInterface for single-operand single-result operations that use t...
void getEffects(SmallVectorImpl< MemoryEffects::EffectInstance > &effects)
This op produces handles to the Payload IR without consuming the original handles and without modifyi...
static LogicalResult verifyTrait(Operation *op)
Checks that the op matches the expectation of this trait.
This trait is supposed to be attached to Transform dialect operations that can be standalone top-leve...
LogicalResult mapBlockArguments(TransformState &state)
static LogicalResult verifyTrait(Operation *op)
Verifies that op satisfies the invariants of this trait.
LogicalResult mapBlockArguments(TransformState &state, Region &region)
Sets up the mapping between the entry block of the given region of this op and the relevant list of P...
Block * getBodyBlock(unsigned region=0)
Returns the single block of the given region.
Trait implementing the TransformOpInterface for operations applying a transformation to a single oper...
static LogicalResult verifyTrait(Operation *op)
Checks that the op matches the expectations of this trait.
DiagnosedSilenceableFailure apply(TransformResults &transformResults, TransformState &state)
Calls applyToOne for every payload operation associated with the operand of this transform IR op,...
Options controlling the application of transform operations by the TransformState.
TransformOptions & enableExpensiveChecks(bool enable=true)
Requests computationally expensive checks of the transform and payload IR well-formedness to be perfo...
bool getExpensiveChecksEnabled() const
Returns true if the expensive checks are requested.
Local mapping between values defined by a specific op implementing the TransformOpInterface and the p...
void set(OpResult value, ArrayRef< Operation * > ops)
Indicates that the result of the transform IR op at the given position corresponds to the given list ...
Base class for TransformState extensions that allow TransformState to contain user-specified informat...
Extension(TransformState &state)
Constructs an extension of the given TransformState object.
const TransformState & getTransformState() const
Provides read-only access to the parent TransformState object.
LogicalResult replacePayloadOp(Operation *op, Operation *replacement)
Replaces the given payload op with another op.
virtual ~Extension()
Base virtual destructor.
A RAII object maintaining a "stack frame" for a transform IR region.
~RegionScope()
Forgets the mapping from or to values defined in the associated transform IR region.
The state maintained across applications of various ops implementing the TransformOpInterface.
LogicalResult getHandlesForPayloadOp(Operation *op, SmallVectorImpl< Value > &handles) const
Populates handles with all handles pointing to the given Payload IR op.
LogicalResult mapBlockArguments(BlockArgument argument, ArrayRef< Operation * > operations)
Records the mapping between a block argument in the transform IR and a list of operations in the payl...
DiagnosedSilenceableFailure applyTransform(TransformOpInterface transform)
Applies the transformation specified by the given transform op and updates the state accordingly.
RegionScope make_region_scope(Region &region)
Creates a new region scope for the given region.
ArrayRef< Operation * > getPayloadOps(Value value) const
Returns the list of ops that the given transform IR value corresponds to.
friend LogicalResult applyTransforms(Operation *payloadRoot, TransformOpInterface transform, const TransformOptions &options)
Entry point to the Transform dialect infrastructure.
Ty & addExtension(Args &&...args)
Adds a new Extension of the type specified as template parameter, constructing it with the arguments ...
Ty * getExtension()
Returns the extension of the specified type.
Operation * getTopLevel() const
Returns the op at which the transformation state is rooted.
void removeExtension()
Removes the extension of the specified type.
DiagnosedSilenceableFailure applyTransformToEach(Location loc, int expectedNumResults, ArrayRef< Operation * > targets, SmallVectorImpl< SmallVector< Operation * >> &results, FnTy transform)
Applies a one-to-one or a one-to-many transform to each of the given targets.
LogicalResult mapPossibleTopLevelTransformOpBlockArguments(TransformState &state, Operation *op, Region &region)
Maps the only block argument of the op with PossibleTopLevelTransformOpTrait to either the list of op...
static SmallVector< SmallVector< Operation *, 1 > > transposeResults(const SmallVector< SmallVector< Operation * >, 1 > &m)
Helper function: transpose MxN into NxM; assumes that the input is a valid.
LogicalResult verifyPossibleTopLevelTransformOpTrait(Operation *op)
Verification hook for PossibleTopLevelTransformOpTrait.
void onlyReadsPayload(SmallVectorImpl< MemoryEffects::EffectInstance > &effects)
bool isHandleConsumed(Value handle, transform::TransformOpInterface transform)
Checks whether the transform op consumes the given handle.
void onlyReadsHandle(ValueRange handles, SmallVectorImpl< MemoryEffects::EffectInstance > &effects)
void consumesHandle(ValueRange handles, SmallVectorImpl< MemoryEffects::EffectInstance > &effects)
Populates effects with the memory effects indicating the operation on the given handle value:
LogicalResult applyTransforms(Operation *payloadRoot, TransformOpInterface transform, const TransformOptions &options=TransformOptions())
Entry point to the Transform dialect infrastructure.
void producesHandle(ValueRange handles, SmallVectorImpl< MemoryEffects::EffectInstance > &effects)
void modifiesPayload(SmallVectorImpl< MemoryEffects::EffectInstance > &effects)
Populates effects with the memory effects indicating the access to payload IR resource.
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
llvm::function_ref< Fn > function_ref
Definition: LLVM.h:150
DiagnosedSilenceableFailure emitSilenceableFailure(Location loc, const Twine &message={})
Emits a silenceable failure with the given message.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value.
Definition: LogicalResult.h:68
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
DiagnosedDefiniteFailure emitDefiniteFailure(Location loc, const Twine &message={})
Emits a definite failure with the given message.
llvm::DenseMap< KeyT, ValueT, KeyInfoT, BucketT > DenseMap
Definition: LLVM.h:123
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value.
Definition: LogicalResult.h:72
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
Side effect resource corresponding to the Payload IR itself.
StringRef getName() override
Return a string name of the resource.
Side effect resource corresponding to the mapping between Transform IR values and Payload IR operatio...
StringRef getName() override
Return a string name of the resource.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.