/home/arjun/llvm-project/mlir/include/mlir/IR/Visitors.h
Line | Count | Source (jump to first uncovered line) |
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" |
17 | | #include "mlir/Support/LogicalResult.h" |
18 | | #include "llvm/ADT/STLExtras.h" |
19 | | |
20 | | namespace mlir { |
21 | | class Diagnostic; |
22 | | class InFlightDiagnostic; |
23 | | class Operation; |
24 | | |
25 | | /// A utility result that is used to signal if a walk method should be |
26 | | /// interrupted or advance. |
27 | | class WalkResult { |
28 | | enum ResultEnum { Interrupt, Advance } result; |
29 | | |
30 | | public: |
31 | 0 | WalkResult(ResultEnum result) : result(result) {} |
32 | | |
33 | | /// Allow LogicalResult to interrupt the walk on failure. |
34 | | WalkResult(LogicalResult result) |
35 | 0 | : result(failed(result) ? Interrupt : Advance) {} |
36 | | |
37 | | /// Allow diagnostics to interrupt the walk. |
38 | 0 | WalkResult(Diagnostic &&) : result(Interrupt) {} |
39 | 0 | WalkResult(InFlightDiagnostic &&) : result(Interrupt) {} |
40 | | |
41 | 0 | bool operator==(const WalkResult &rhs) const { return result == rhs.result; } |
42 | | |
43 | 0 | static WalkResult interrupt() { return {Interrupt}; } |
44 | 0 | static WalkResult advance() { return {Advance}; } |
45 | | |
46 | | /// Returns if the walk was interrupted. |
47 | 0 | bool wasInterrupted() const { return result == Interrupt; } |
48 | | }; |
49 | | |
50 | | namespace detail { |
51 | | /// Helper templates to deduce the first argument of a callback parameter. |
52 | | template <typename Ret, typename Arg> Arg first_argument_type(Ret (*)(Arg)); |
53 | | template <typename Ret, typename F, typename Arg> |
54 | | Arg first_argument_type(Ret (F::*)(Arg)); |
55 | | template <typename Ret, typename F, typename Arg> |
56 | | Arg first_argument_type(Ret (F::*)(Arg) const); |
57 | | template <typename F> |
58 | | decltype(first_argument_type(&F::operator())) first_argument_type(F); |
59 | | |
60 | | /// Type definition of the first argument to the given callable 'T'. |
61 | | template <typename T> |
62 | | using first_argument = decltype(first_argument_type(std::declval<T>())); |
63 | | |
64 | | /// Walk all of the operations nested under and including the given operation. |
65 | | void walkOperations(Operation *op, function_ref<void(Operation *op)> callback); |
66 | | |
67 | | /// Walk all of the operations nested under and including the given operation. |
68 | | /// This methods walks operations until an interrupt result is returned by the |
69 | | /// callback. |
70 | | WalkResult walkOperations(Operation *op, |
71 | | function_ref<WalkResult(Operation *op)> callback); |
72 | | |
73 | | // Below are a set of functions to walk nested operations. Users should favor |
74 | | // the direct `walk` methods on the IR classes(Operation/Block/etc) over these |
75 | | // methods. They are also templated to allow for statically dispatching based |
76 | | // upon the type of the callback function. |
77 | | |
78 | | /// Walk all of the operations nested under and including the given operation. |
79 | | /// This method is selected for callbacks that operation on Operation*. |
80 | | /// |
81 | | /// Example: |
82 | | /// op->walk([](Operation *op) { ... }); |
83 | | template < |
84 | | typename FuncTy, typename ArgT = detail::first_argument<FuncTy>, |
85 | | typename RetT = decltype(std::declval<FuncTy>()(std::declval<ArgT>()))> |
86 | | typename std::enable_if<std::is_same<ArgT, Operation *>::value, RetT>::type |
87 | 0 | walkOperations(Operation *op, FuncTy &&callback) { |
88 | 0 | return detail::walkOperations(op, function_ref<RetT(ArgT)>(callback)); |
89 | 0 | } Unexecuted instantiation: Ops.cpp:_ZN4mlir6detail14walkOperationsIRZL6verifyNS_18GenericAtomicRMWOpEE4$_24PNS_9OperationENS_10WalkResultEEENSt9enable_ifIXsr3std7is_sameIT0_S6_EE5valueET1_E4typeES6_OT_ Unexecuted instantiation: AsmPrinter.cpp:_ZN4mlir6detail14walkOperationsIZN12_GLOBAL__N_110AliasState10initializeEPNS_9OperationERNS_26DialectInterfaceCollectionINS_21OpAsmDialectInterfaceEEEE3$_2S5_vEENSt9enable_ifIXsr3std7is_sameIT0_S5_EE5valueET1_E4typeES5_OT_ Unexecuted instantiation: Region.cpp:_ZN4mlir6detail14walkOperationsIRZNS_6Region9cloneIntoEPS2_N4llvm14ilist_iteratorINS4_12ilist_detail12node_optionsINS_5BlockELb1ELb0EvEELb0ELb0EEERNS_20BlockAndValueMappingEE3$_0PNS_9OperationEvEENSt9enable_ifIXsr3std7is_sameIT0_SG_EE5valueET1_E4typeESG_OT_ |
90 | | |
91 | | /// Walk all of the operations of type 'ArgT' nested under and including the |
92 | | /// given operation. This method is selected for void returning callbacks that |
93 | | /// operate on a specific derived operation type. |
94 | | /// |
95 | | /// Example: |
96 | | /// op->walk([](ReturnOp op) { ... }); |
97 | | template < |
98 | | typename FuncTy, typename ArgT = detail::first_argument<FuncTy>, |
99 | | typename RetT = decltype(std::declval<FuncTy>()(std::declval<ArgT>()))> |
100 | | typename std::enable_if<!std::is_same<ArgT, Operation *>::value && |
101 | | std::is_same<RetT, void>::value, |
102 | | RetT>::type |
103 | | walkOperations(Operation *op, FuncTy &&callback) { |
104 | | auto wrapperFn = [&](Operation *op) { |
105 | | if (auto derivedOp = dyn_cast<ArgT>(op)) |
106 | | callback(derivedOp); |
107 | | }; |
108 | | return detail::walkOperations(op, function_ref<RetT(Operation *)>(wrapperFn)); |
109 | | } |
110 | | |
111 | | /// Walk all of the operations of type 'ArgT' nested under and including the |
112 | | /// given operation. This method is selected for WalkReturn returning |
113 | | /// interruptible callbacks that operate on a specific derived operation type. |
114 | | /// |
115 | | /// Example: |
116 | | /// op->walk([](ReturnOp op) { |
117 | | /// if (some_invariant) |
118 | | /// return WalkResult::interrupt(); |
119 | | /// return WalkResult::advance(); |
120 | | /// }); |
121 | | template < |
122 | | typename FuncTy, typename ArgT = detail::first_argument<FuncTy>, |
123 | | typename RetT = decltype(std::declval<FuncTy>()(std::declval<ArgT>()))> |
124 | | typename std::enable_if<!std::is_same<ArgT, Operation *>::value && |
125 | | std::is_same<RetT, WalkResult>::value, |
126 | | RetT>::type |
127 | | walkOperations(Operation *op, FuncTy &&callback) { |
128 | | auto wrapperFn = [&](Operation *op) { |
129 | | if (auto derivedOp = dyn_cast<ArgT>(op)) |
130 | | return callback(derivedOp); |
131 | | return WalkResult::advance(); |
132 | | }; |
133 | | return detail::walkOperations(op, function_ref<RetT(Operation *)>(wrapperFn)); |
134 | | } |
135 | | |
136 | | /// Utility to provide the return type of a templated walk method. |
137 | | template <typename FnT> |
138 | | using walkResultType = decltype(walkOperations(nullptr, std::declval<FnT>())); |
139 | | } // end namespace detail |
140 | | |
141 | | } // namespace mlir |
142 | | |
143 | | #endif |