MLIR  14.0.0git
Visitors.h
Go to the documentation of this file.
1 //===- Visitors.h - Utilities for visiting operations -----------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines utilities for walking and visiting operations.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef MLIR_IR_VISITORS_H
14 #define MLIR_IR_VISITORS_H
15 
16 #include "mlir/Support/LLVM.h"
18 #include "llvm/ADT/STLExtras.h"
19 
20 namespace mlir {
21 class Diagnostic;
22 class InFlightDiagnostic;
23 class Operation;
24 class Block;
25 class Region;
26 
27 /// A utility result that is used to signal how to proceed with an ongoing walk:
28 /// * Interrupt: the walk will be interrupted and no more operations, regions
29 /// or blocks will be visited.
30 /// * Advance: the walk will continue.
31 /// * Skip: the walk of the current operation, region or block and their
32 /// nested elements that haven't been visited already will be skipped and will
33 /// continue with the next operation, region or block.
34 class WalkResult {
35  enum ResultEnum { Interrupt, Advance, Skip } result;
36 
37 public:
38  WalkResult(ResultEnum result) : result(result) {}
39 
40  /// Allow LogicalResult to interrupt the walk on failure.
42  : result(failed(result) ? Interrupt : Advance) {}
43 
44  /// Allow diagnostics to interrupt the walk.
45  WalkResult(Diagnostic &&) : result(Interrupt) {}
46  WalkResult(InFlightDiagnostic &&) : result(Interrupt) {}
47 
48  bool operator==(const WalkResult &rhs) const { return result == rhs.result; }
49 
50  static WalkResult interrupt() { return {Interrupt}; }
51  static WalkResult advance() { return {Advance}; }
52  static WalkResult skip() { return {Skip}; }
53 
54  /// Returns true if the walk was interrupted.
55  bool wasInterrupted() const { return result == Interrupt; }
56 
57  /// Returns true if the walk was skipped.
58  bool wasSkipped() const { return result == Skip; }
59 };
60 
61 /// Traversal order for region, block and operation walk utilities.
62 enum class WalkOrder { PreOrder, PostOrder };
63 
64 namespace detail {
65 /// Helper templates to deduce the first argument of a callback parameter.
66 template <typename Ret, typename Arg> Arg first_argument_type(Ret (*)(Arg));
67 template <typename Ret, typename F, typename Arg>
68 Arg first_argument_type(Ret (F::*)(Arg));
69 template <typename Ret, typename F, typename Arg>
70 Arg first_argument_type(Ret (F::*)(Arg) const);
71 template <typename F>
72 decltype(first_argument_type(&F::operator())) first_argument_type(F);
73 
74 /// Type definition of the first argument to the given callable 'T'.
75 template <typename T>
76 using first_argument = decltype(first_argument_type(std::declval<T>()));
77 
78 /// Walk all of the regions, blocks, or operations nested under (and including)
79 /// the given operation. Regions, blocks and operations at the same nesting
80 /// level are visited in lexicographical order. The walk order for enclosing
81 /// regions, blocks and operations with respect to their nested ones is
82 /// specified by 'order'. These methods are invoked for void-returning
83 /// callbacks. A callback on a block or operation is allowed to erase that block
84 /// or operation only if the walk is in post-order. See non-void method for
85 /// pre-order erasure.
86 void walk(Operation *op, function_ref<void(Region *)> callback,
87  WalkOrder order);
88 void walk(Operation *op, function_ref<void(Block *)> callback, WalkOrder order);
89 void walk(Operation *op, function_ref<void(Operation *)> callback,
90  WalkOrder order);
91 /// Walk all of the regions, blocks, or operations nested under (and including)
92 /// the given operation. Regions, blocks and operations at the same nesting
93 /// level are visited in lexicographical order. The walk order for enclosing
94 /// regions, blocks and operations with respect to their nested ones is
95 /// specified by 'order'. This method is invoked for skippable or interruptible
96 /// callbacks. A callback on a block or operation is allowed to erase that block
97 /// or operation if either:
98 /// * the walk is in post-order, or
99 /// * the walk is in pre-order and the walk is skipped after the erasure.
101  WalkOrder order);
103  WalkOrder order);
105  WalkOrder order);
106 
107 // Below are a set of functions to walk nested operations. Users should favor
108 // the direct `walk` methods on the IR classes(Operation/Block/etc) over these
109 // methods. They are also templated to allow for statically dispatching based
110 // upon the type of the callback function.
111 
112 /// Walk all of the regions, blocks, or operations nested under (and including)
113 /// the given operation. Regions, blocks and operations at the same nesting
114 /// level are visited in lexicographical order. The walk order for enclosing
115 /// regions, blocks and operations with respect to their nested ones is
116 /// specified by 'Order' (post-order by default). A callback on a block or
117 /// operation is allowed to erase that block or operation if either:
118 /// * the walk is in post-order, or
119 /// * the walk is in pre-order and the walk is skipped after the erasure.
120 /// This method is selected for callbacks that operate on Region*, Block*, and
121 /// Operation*.
122 ///
123 /// Example:
124 /// op->walk([](Region *r) { ... });
125 /// op->walk([](Block *b) { ... });
126 /// op->walk([](Operation *op) { ... });
127 template <
128  WalkOrder Order = WalkOrder::PostOrder, typename FuncTy,
129  typename ArgT = detail::first_argument<FuncTy>,
130  typename RetT = decltype(std::declval<FuncTy>()(std::declval<ArgT>()))>
131 typename std::enable_if<
132  llvm::is_one_of<ArgT, Operation *, Region *, Block *>::value, RetT>::type
133 walk(Operation *op, FuncTy &&callback) {
134  return detail::walk(op, function_ref<RetT(ArgT)>(callback), Order);
135 }
136 
137 /// Walk all of the operations of type 'ArgT' nested under and including the
138 /// given operation. Regions, blocks and operations at the same nesting
139 /// level are visited in lexicographical order. The walk order for enclosing
140 /// regions, blocks and operations with respect to their nested ones is
141 /// specified by 'order' (post-order by default). This method is selected for
142 /// void-returning callbacks that operate on a specific derived operation type.
143 /// A callback on an operation is allowed to erase that operation only if the
144 /// walk is in post-order. See non-void method for pre-order erasure.
145 ///
146 /// Example:
147 /// op->walk([](ReturnOp op) { ... });
148 template <
149  WalkOrder Order = WalkOrder::PostOrder, typename FuncTy,
150  typename ArgT = detail::first_argument<FuncTy>,
151  typename RetT = decltype(std::declval<FuncTy>()(std::declval<ArgT>()))>
152 typename std::enable_if<
155  RetT>::type
156 walk(Operation *op, FuncTy &&callback) {
157  auto wrapperFn = [&](Operation *op) {
158  if (auto derivedOp = dyn_cast<ArgT>(op))
159  callback(derivedOp);
160  };
161  return detail::walk(op, function_ref<RetT(Operation *)>(wrapperFn), Order);
162 }
163 
164 /// Walk all of the operations of type 'ArgT' nested under and including the
165 /// given operation. Regions, blocks and operations at the same nesting level
166 /// are visited in lexicographical order. The walk order for enclosing regions,
167 /// blocks and operations with respect to their nested ones is specified by
168 /// 'Order' (post-order by default). This method is selected for WalkReturn
169 /// returning skippable or interruptible callbacks that operate on a specific
170 /// derived operation type. A callback on an operation is allowed to erase that
171 /// operation if either:
172 /// * the walk is in post-order, or
173 /// * the walk is in pre-order and the walk is skipped after the erasure.
174 ///
175 /// Example:
176 /// op->walk([](ReturnOp op) {
177 /// if (some_invariant)
178 /// return WalkResult::skip();
179 /// if (another_invariant)
180 /// return WalkResult::interrupt();
181 /// return WalkResult::advance();
182 /// });
183 template <
184  WalkOrder Order = WalkOrder::PostOrder, typename FuncTy,
185  typename ArgT = detail::first_argument<FuncTy>,
186  typename RetT = decltype(std::declval<FuncTy>()(std::declval<ArgT>()))>
187 typename std::enable_if<
190  RetT>::type
191 walk(Operation *op, FuncTy &&callback) {
192  auto wrapperFn = [&](Operation *op) {
193  if (auto derivedOp = dyn_cast<ArgT>(op))
194  return callback(derivedOp);
195  return WalkResult::advance();
196  };
197  return detail::walk(op, function_ref<RetT(Operation *)>(wrapperFn), Order);
198 }
199 
200 /// Utility to provide the return type of a templated walk method.
201 template <typename FnT>
202 using walkResultType = decltype(walk(nullptr, std::declval<FnT>()));
203 } // end namespace detail
204 
205 } // namespace mlir
206 
207 #endif
Include the generated interface declarations.
This class contains a list of basic blocks and a link to the parent operation it is attached to...
Definition: Region.h:26
WalkResult(InFlightDiagnostic &&)
Definition: Visitors.h:46
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:28
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:299
Block represents an ordered list of Operations.
Definition: Block.h:29
bool wasInterrupted() const
Returns true if the walk was interrupted.
Definition: Visitors.h:55
bool failed(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a failure value...
Definition: LogicalResult.h:72
static constexpr const bool value
decltype(walk(nullptr, std::declval< FnT >())) walkResultType
Utility to provide the return type of a templated walk method.
Definition: Visitors.h:202
This class contains all of the information necessary to report a diagnostic to the DiagnosticEngine...
Definition: Diagnostics.h:155
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
WalkResult(LogicalResult result)
Allow LogicalResult to interrupt the walk on failure.
Definition: Visitors.h:41
static WalkResult advance()
Definition: Visitors.h:51
static WalkResult interrupt()
Definition: Visitors.h:50
A utility result that is used to signal how to proceed with an ongoing walk:
Definition: Visitors.h:34
std::enable_if< !llvm::is_one_of< ArgT, Operation *, Region *, Block * >::value &&std::is_same< RetT, WalkResult >::value, RetT >::type walk(Operation *op, FuncTy &&callback)
Walk all of the operations of type &#39;ArgT&#39; nested under and including the given operation.
Definition: Visitors.h:191
decltype(first_argument_type(std::declval< T >())) first_argument
Type definition of the first argument to the given callable &#39;T&#39;.
Definition: Visitors.h:76
static WalkResult skip()
Definition: Visitors.h:52
void walk(Operation *op, function_ref< void(Region *)> callback, WalkOrder order)
Walk all of the regions, blocks, or operations nested under (and including) the given operation...
Definition: Visitors.cpp:21
bool wasSkipped() const
Returns true if the walk was skipped.
Definition: Visitors.h:58
bool operator==(const WalkResult &rhs) const
Definition: Visitors.h:48
Arg first_argument_type(Ret(F::*)(Arg))
WalkResult(ResultEnum result)
Definition: Visitors.h:38
WalkOrder
Traversal order for region, block and operation walk utilities.
Definition: Visitors.h:62
WalkResult(Diagnostic &&)
Allow diagnostics to interrupt the walk.
Definition: Visitors.h:45