CIRCT  20.0.0git
SupportModule.cpp
Go to the documentation of this file.
1 //===- SupportModule.cpp - Support API pybind module ----------------------===//
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 #include "CIRCTModules.h"
10 
11 #include "mlir/Bindings/Python/PybindAdaptors.h"
12 
13 #include "PybindUtils.h"
14 #include "mlir-c/Support.h"
15 #include <pybind11/pybind11.h>
16 #include <pybind11/pytypes.h>
17 #include <pybind11/stl.h>
18 
19 namespace py = pybind11;
20 
21 using namespace circt;
22 using namespace mlir::python::adaptors;
23 
24 /// Populate the support python module.
25 void circt::python::populateSupportSubmodule(py::module &m) {
26  m.doc() = "CIRCT Python utils";
27  // Walk with filter.
28  m.def(
29  "_walk_with_filter",
30  [](MlirOperation operation, const std::vector<std::string> &opNames,
31  std::function<py::object(MlirOperation)> callback,
32  py::object walkOrderRaw) {
33  struct UserData {
34  std::function<py::object(MlirOperation)> callback;
35  bool gotException;
36  std::string exceptionWhat;
37  py::object exceptionType;
38  std::vector<MlirIdentifier> opNames;
39  };
40 
41  // As we transition from pybind11 to nanobind, the WalkOrder enum and
42  // automatic casting will be defined as a nanobind enum upstream. Do a
43  // manual conversion that works with either pybind11 or nanobind for
44  // now. When we're on nanobind in CIRCT, we can go back to automatic
45  // casting.
46  MlirWalkOrder walkOrder;
47  auto walkOrderRawValue = py::cast<int>(walkOrderRaw.attr("value"));
48  switch (walkOrderRawValue) {
49  case 0:
50  walkOrder = MlirWalkOrder::MlirWalkPreOrder;
51  break;
52  case 1:
53  walkOrder = MlirWalkOrder::MlirWalkPostOrder;
54  break;
55  }
56 
57  std::vector<MlirIdentifier> opNamesIdentifiers;
58  opNamesIdentifiers.reserve(opNames.size());
59 
60  // Construct MlirIdentifier from string to perform pointer comparison.
61  for (auto &opName : opNames)
62  opNamesIdentifiers.push_back(mlirIdentifierGet(
63  mlirOperationGetContext(operation),
64  mlirStringRefCreateFromCString(opName.c_str())));
65 
66  UserData userData{
67  std::move(callback), false, {}, {}, opNamesIdentifiers};
68  MlirOperationWalkCallback walkCallback = [](MlirOperation op,
69  void *userData) {
70  UserData *calleeUserData = static_cast<UserData *>(userData);
71  auto opName = mlirOperationGetName(op);
72 
73  // Check if the operation name is in the filter.
74  bool inFilter = false;
75  for (auto &opNamesIdentifier : calleeUserData->opNames) {
76  if (mlirIdentifierEqual(opName, opNamesIdentifier)) {
77  inFilter = true;
78  break;
79  }
80  }
81 
82  // If the operation name is not in the filter, skip it.
83  if (!inFilter)
84  return MlirWalkResult::MlirWalkResultAdvance;
85 
86  try {
87  // As we transition from pybind11 to nanobind, the WalkResult enum
88  // and automatic casting will be defined as a nanobind enum
89  // upstream. Do a manual conversion that works with either pybind11
90  // or nanobind for now. When we're on nanobind in CIRCT, we can go
91  // back to automatic casting.
92  MlirWalkResult walkResult;
93  auto walkResultRaw = (calleeUserData->callback)(op);
94  auto walkResultRawValue =
95  py::cast<int>(walkResultRaw.attr("value"));
96  switch (walkResultRawValue) {
97  case 0:
98  walkResult = MlirWalkResult::MlirWalkResultAdvance;
99  break;
100  case 1:
101  walkResult = MlirWalkResult::MlirWalkResultInterrupt;
102  break;
103  case 2:
104  walkResult = MlirWalkResult::MlirWalkResultSkip;
105  break;
106  }
107  return walkResult;
108  } catch (py::error_already_set &e) {
109  calleeUserData->gotException = true;
110  calleeUserData->exceptionWhat = e.what();
111  calleeUserData->exceptionType = e.type();
112  return MlirWalkResult::MlirWalkResultInterrupt;
113  }
114  };
115  mlirOperationWalk(operation, walkCallback, &userData, walkOrder);
116  if (userData.gotException) {
117  std::string message("Exception raised in callback: ");
118  message.append(userData.exceptionWhat);
119  throw std::runtime_error(message);
120  }
121  },
122  py::arg("op"), py::arg("op_names"), py::arg("callback"),
123  py::arg("walk_order"));
124 }
void populateSupportSubmodule(pybind11::module &m)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21