MLIR  16.0.0git
DebugAction.h
Go to the documentation of this file.
1 //===- DebugAction.h - Debug Action Support ---------------------*- 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 contains definitions for the debug action framework. This framework
10 // allows for external entities to control certain actions taken by the compiler
11 // by registering handler functions. A debug action handler provides the
12 // internal implementation for the various queries on a debug action, such as
13 // whether it should execute or not.
14 //
15 //===----------------------------------------------------------------------===//
16 
17 #ifndef MLIR_SUPPORT_DEBUGACTION_H
18 #define MLIR_SUPPORT_DEBUGACTION_H
19 
21 #include "mlir/Support/TypeID.h"
22 #include "llvm/ADT/ArrayRef.h"
23 #include "llvm/ADT/Sequence.h"
24 #include "llvm/ADT/StringMap.h"
25 #include "llvm/Support/TypeName.h"
26 #include "llvm/Support/raw_ostream.h"
27 #include <functional>
28 
29 namespace mlir {
30 
31 //===----------------------------------------------------------------------===//
32 // DebugActionManager
33 //===----------------------------------------------------------------------===//
34 
35 /// This class represents manages debug actions, and orchestrates the
36 /// communication between action queries and action handlers. An action handler
37 /// is either an action specific handler, i.e. a derived class of
38 /// `MyActionType::Handler`, or a generic handler, i.e. a derived class of
39 /// `DebugActionManager::GenericHandler`. For more details on action specific
40 /// handlers, see the definition of `DebugAction::Handler` below. For more
41 /// details on generic handlers, see `DebugActionManager::GenericHandler` below.
43 public:
44  //===--------------------------------------------------------------------===//
45  // Handlers
46  //===--------------------------------------------------------------------===//
47 
48  /// This class represents the base class of a debug action handler.
49  class HandlerBase {
50  public:
51  virtual ~HandlerBase() = default;
52 
53  /// Return the unique handler id of this handler, use for casting
54  /// functionality.
55  TypeID getHandlerID() const { return handlerID; }
56 
57  protected:
58  HandlerBase(TypeID handlerID) : handlerID(handlerID) {}
59 
60  /// The type of the derived handler class. This allows for detecting if a
61  /// handler can handle a given action type.
63  };
64 
65  /// This class represents a generic action handler. A generic handler allows
66  /// for handling any action type. Handlers of this type are useful for
67  /// implementing general functionality that doesn't necessarily need to
68  /// interpret the exact action parameters, or can rely on an external
69  /// interpreter (such as the user). Given that these handlers are generic,
70  /// they take a set of opaque parameters that try to map the context of the
71  /// action type in a generic way.
72  class GenericHandler : public HandlerBase {
73  public:
75 
76  /// This hook allows for controlling whether an action should execute or
77  /// not. It should return failure if the handler could not process the
78  /// action, passing it to the next registered handler.
79  virtual FailureOr<bool> shouldExecute(StringRef actionTag,
80  StringRef description) {
81  return failure();
82  }
83 
84  /// Provide classof to allow casting between handler types.
85  static bool classof(const DebugActionManager::HandlerBase *handler) {
86  return handler->getHandlerID() == TypeID::get<GenericHandler>();
87  }
88  };
89 
90  /// Register the given action handler with the manager.
91  void registerActionHandler(std::unique_ptr<HandlerBase> handler) {
92  // The manager is always disabled if built without debug.
93 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
94  actionHandlers.emplace_back(std::move(handler));
95 #endif
96  }
97  template <typename T>
99  registerActionHandler(std::make_unique<T>());
100  }
101 
102  //===--------------------------------------------------------------------===//
103  // Action Queries
104  //===--------------------------------------------------------------------===//
105 
106  /// Returns true if the given action type should be executed, false otherwise.
107  /// `Args` are a set of parameters used by handlers of `ActionType` to
108  /// determine if the action should be executed.
109  template <typename ActionType, typename... Args>
110  bool shouldExecute(Args &&...args) {
111  // The manager is always disabled if built without debug.
112 #if !LLVM_ENABLE_ABI_BREAKING_CHECKS
113  return true;
114 #else
115  // Invoke the `shouldExecute` method on the provided handler.
116  auto shouldExecuteFn = [&](auto *handler, auto &&...handlerParams) {
117  return handler->shouldExecute(
118  std::forward<decltype(handlerParams)>(handlerParams)...);
119  };
120  FailureOr<bool> result = dispatchToHandler<ActionType, bool>(
121  shouldExecuteFn, std::forward<Args>(args)...);
122 
123  // If the action wasn't handled, execute the action by default.
124  return succeeded(result) ? *result : true;
125 #endif
126  }
127 
128 private:
129 // The manager is always disabled if built without debug.
130 #if LLVM_ENABLE_ABI_BREAKING_CHECKS
131  //===--------------------------------------------------------------------===//
132  // Query to Handler Dispatch
133  //===--------------------------------------------------------------------===//
134 
135  /// Dispath a given callback on any handlers that are able to process queries
136  /// on the given action type. This method returns failure if no handlers could
137  /// process the action, or success(with a result) if a handler processed the
138  /// action.
139  template <typename ActionType, typename ResultT, typename HandlerCallbackT,
140  typename... Args>
141  FailureOr<ResultT> dispatchToHandler(HandlerCallbackT &&handlerCallback,
142  Args &&...args) {
143  static_assert(ActionType::template canHandleWith<Args...>(),
144  "cannot execute action with the given set of parameters");
145 
146  // Process any generic or action specific handlers.
147  // TODO: We currently just pick the first handler that gives us a result,
148  // but in the future we may want to employ a reduction over all of the
149  // values returned.
150  for (std::unique_ptr<HandlerBase> &it : llvm::reverse(actionHandlers)) {
151  FailureOr<ResultT> result = failure();
152  if (auto *handler = dyn_cast<typename ActionType::Handler>(&*it)) {
153  result = handlerCallback(handler, std::forward<Args>(args)...);
154  } else if (auto *genericHandler = dyn_cast<GenericHandler>(&*it)) {
155  result = handlerCallback(genericHandler, ActionType::getTag(),
156  ActionType::getDescription());
157  }
158 
159  // If the handler succeeded, return the result. Otherwise, try a new
160  // handler.
161  if (succeeded(result))
162  return result;
163  }
164  return failure();
165  }
166 
167  /// The set of action handlers that have been registered with the manager.
169 #endif
170 };
171 
172 //===----------------------------------------------------------------------===//
173 // DebugAction
174 //===----------------------------------------------------------------------===//
175 
176 /// A debug action is a specific action that is to be taken by the compiler,
177 /// that can be toggled and controlled by an external user. There are no
178 /// constraints on the granularity of an action, it could be as simple as
179 /// "perform this fold" and as complex as "run this pass pipeline". Via template
180 /// parameters `ParameterTs`, a user may provide the set of argument types that
181 /// are provided when handling a query on this action. Derived classes are
182 /// expected to provide the following:
183 /// * static llvm::StringRef getTag()
184 /// - This method returns a unique string identifier, similar to a command
185 /// line flag or DEBUG_TYPE.
186 /// * static llvm::StringRef getDescription()
187 /// - This method returns a short description of what the action represents.
188 ///
189 /// This class provides a handler class that can be derived from to handle
190 /// instances of this action. The parameters to its query methods map 1-1 to the
191 /// types on the action type.
192 template <typename... ParameterTs>
193 class DebugAction {
194 public:
196  public:
198  : HandlerBase(
199  TypeID::get<typename DebugAction<ParameterTs...>::Handler>()) {}
200 
201  /// This hook allows for controlling whether an action should execute or
202  /// not. `parameters` correspond to the set of values provided by the
203  /// action as context. It should return failure if the handler could not
204  /// process the action, passing it to the next registered handler.
205  virtual FailureOr<bool> shouldExecute(ParameterTs... parameters) {
206  return failure();
207  }
208 
209  /// Provide classof to allow casting between handler types.
210  static bool classof(const DebugActionManager::HandlerBase *handler) {
211  return handler->getHandlerID() ==
212  TypeID::get<typename DebugAction<ParameterTs...>::Handler>();
213  }
214  };
215 
216 private:
217  /// Returns true if the action can be handled within the given set of
218  /// parameter types.
219  template <typename... CallerParameterTs>
220  static constexpr bool canHandleWith() {
221  return llvm::is_invocable<function_ref<void(ParameterTs...)>,
222  CallerParameterTs...>::value;
223  }
224 
225  /// Allow access to `canHandleWith`.
226  friend class DebugActionManager;
227 };
228 
229 } // namespace mlir
230 
231 #endif // MLIR_SUPPORT_DEBUGACTION_H
Include the generated interface declarations.
static bool classof(const DebugActionManager::HandlerBase *handler)
Provide classof to allow casting between handler types.
Definition: DebugAction.h:85
static TypeID get()
Construct a type info object for the given type T.
Definition: TypeID.h:232
bool succeeded(LogicalResult result)
Utility function that returns true if the provided LogicalResult corresponds to a success value...
Definition: LogicalResult.h:68
bool shouldExecute(Args &&...args)
Returns true if the given action type should be executed, false otherwise.
Definition: DebugAction.h:110
TypeID handlerID
The type of the derived handler class.
Definition: DebugAction.h:62
static constexpr const bool value
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:104
A debug action is a specific action that is to be taken by the compiler, that can be toggled and cont...
Definition: DebugAction.h:193
This class represents the base class of a debug action handler.
Definition: DebugAction.h:49
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
This class provides support for representing a failure result, or a valid value of type T...
Definition: LogicalResult.h:78
TypeID getHandlerID() const
Return the unique handler id of this handler, use for casting functionality.
Definition: DebugAction.h:55
virtual FailureOr< bool > shouldExecute(ParameterTs... parameters)
This hook allows for controlling whether an action should execute or not.
Definition: DebugAction.h:205
This class represents a generic action handler.
Definition: DebugAction.h:72
This class represents manages debug actions, and orchestrates the communication between action querie...
Definition: DebugAction.h:42
static bool classof(const DebugActionManager::HandlerBase *handler)
Provide classof to allow casting between handler types.
Definition: DebugAction.h:210
virtual FailureOr< bool > shouldExecute(StringRef actionTag, StringRef description)
This hook allows for controlling whether an action should execute or not.
Definition: DebugAction.h:79
void registerActionHandler(std::unique_ptr< HandlerBase > handler)
Register the given action handler with the manager.
Definition: DebugAction.h:91