|
20 | 20 | #include "nanobind/nanobind.h"
|
21 | 21 | #include "llvm/ADT/ArrayRef.h"
|
22 | 22 | #include "llvm/ADT/SmallVector.h"
|
23 |
| -#include "llvm/Support/raw_ostream.h" |
24 | 23 |
|
25 | 24 | #include <optional>
|
26 |
| -#include <system_error> |
27 |
| -#include <utility> |
28 | 25 |
|
29 | 26 | namespace nb = nanobind;
|
30 | 27 | using namespace nb::literals;
|
@@ -1523,7 +1520,7 @@ nb::object PyOperation::create(std::string_view name,
|
1523 | 1520 | llvm::ArrayRef<MlirValue> operands,
|
1524 | 1521 | std::optional<nb::dict> attributes,
|
1525 | 1522 | std::optional<std::vector<PyBlock *>> successors,
|
1526 |
| - int regions, DefaultingPyLocation ___location, |
| 1523 | + int regions, PyLocation ___location, |
1527 | 1524 | const nb::object &maybeIp, bool inferType) {
|
1528 | 1525 | llvm::SmallVector<MlirType, 4> mlirResults;
|
1529 | 1526 | llvm::SmallVector<MlirBlock, 4> mlirSuccessors;
|
@@ -1627,7 +1624,7 @@ nb::object PyOperation::create(std::string_view name,
|
1627 | 1624 | if (!operation.ptr)
|
1628 | 1625 | throw nb::value_error("Operation creation failed");
|
1629 | 1626 | PyOperationRef created =
|
1630 |
| - PyOperation::createDetached(___location->getContext(), operation); |
| 1627 | + PyOperation::createDetached(___location.getContext(), operation); |
1631 | 1628 | maybeInsertOperation(created, maybeIp);
|
1632 | 1629 |
|
1633 | 1630 | return created.getObject();
|
@@ -1937,9 +1934,9 @@ nb::object PyOpView::buildGeneric(
|
1937 | 1934 | std::optional<nb::list> resultTypeList, nb::list operandList,
|
1938 | 1935 | std::optional<nb::dict> attributes,
|
1939 | 1936 | std::optional<std::vector<PyBlock *>> successors,
|
1940 |
| - std::optional<int> regions, DefaultingPyLocation ___location, |
| 1937 | + std::optional<int> regions, PyLocation ___location, |
1941 | 1938 | const nb::object &maybeIp) {
|
1942 |
| - PyMlirContextRef context = ___location->getContext(); |
| 1939 | + PyMlirContextRef context = ___location.getContext(); |
1943 | 1940 |
|
1944 | 1941 | // Class level operation construction metadata.
|
1945 | 1942 | // Operand and result segment specs are either none, which does no
|
@@ -2789,6 +2786,91 @@ class PyOpAttributeMap {
|
2789 | 2786 | PyOperationRef operation;
|
2790 | 2787 | };
|
2791 | 2788 |
|
| 2789 | +// bpo-40421 added PyFrame_GetLasti() to Python 3.11.0b1 |
| 2790 | +#if PY_VERSION_HEX < 0x030b00b1 && !defined(PYPY_VERSION) |
| 2791 | +int PyFrame_GetLasti(PyFrameObject *frame) { |
| 2792 | +#if PY_VERSION_HEX >= 0x030a00a7 |
| 2793 | + // bpo-27129: Since Python 3.10.0a7, f_lasti is an instruction offset, |
| 2794 | + // not a bytes offset anymore. Python uses 16-bit "wordcode" (2 bytes) |
| 2795 | + // instructions. |
| 2796 | + if (frame->f_lasti < 0) { |
| 2797 | + return -1; |
| 2798 | + } |
| 2799 | + return frame->f_lasti * 2; |
| 2800 | +#else |
| 2801 | + return frame->f_lasti; |
| 2802 | +#endif |
| 2803 | +} |
| 2804 | +#endif |
| 2805 | + |
| 2806 | +constexpr size_t kMaxFrames = 512; |
| 2807 | + |
| 2808 | +std::optional<MlirLocation> tracebackToLocation(MlirContext ctx) { |
| 2809 | + size_t framesLimit = PyGlobals::get().locTracebackFramesLimit(); |
| 2810 | + // We use a thread_local here mostly to avoid requiring a large amount of |
| 2811 | + // space. |
| 2812 | + thread_local std::array<MlirLocation, kMaxFrames> frames; |
| 2813 | + size_t count = 0; |
| 2814 | + |
| 2815 | + assert(PyGILState_Check()); |
| 2816 | + |
| 2817 | + if (!PyGlobals::get().locTracebacksEnabled()) |
| 2818 | + return std::nullopt; |
| 2819 | + |
| 2820 | + PyThreadState *tstate = PyThreadState_GET(); |
| 2821 | + |
| 2822 | + PyFrameObject *next; |
| 2823 | + for (PyFrameObject *pyFrame = PyThreadState_GetFrame(tstate); |
| 2824 | + pyFrame != nullptr && count < framesLimit; |
| 2825 | + next = PyFrame_GetBack(pyFrame), Py_XDECREF(pyFrame), pyFrame = next) { |
| 2826 | + PyCodeObject *code = PyFrame_GetCode(pyFrame); |
| 2827 | + auto fileNameStr = |
| 2828 | + nb::cast<std::string>(nb::borrow<nb::str>(code->co_filename)); |
| 2829 | + llvm::StringRef fileName(fileNameStr); |
| 2830 | + if (!PyGlobals::get().isUserTracebackFilename(fileName)) |
| 2831 | + continue; |
| 2832 | + |
| 2833 | +#if PY_VERSION_HEX < 0x030b00f0 |
| 2834 | + std::string name = |
| 2835 | + nb::cast<std::string>(nb::borrow<nb::str>(code->co_name)); |
| 2836 | + llvm::StringRef funcName(name); |
| 2837 | + int startLine = PyFrame_GetLineNumber(pyFrame); |
| 2838 | + MlirLocation loc = |
| 2839 | + mlirLocationFileLineColGet(ctx, wrap(fileName), startLine, 0); |
| 2840 | +#else |
| 2841 | + // co_qualname added in py3.11 |
| 2842 | + std::string name = |
| 2843 | + nb::cast<std::string>(nb::borrow<nb::str>(code->co_qualname)); |
| 2844 | + llvm::StringRef funcName(name); |
| 2845 | + int startLine, startCol, endLine, endCol; |
| 2846 | + int lasti = PyFrame_GetLasti(pyFrame); |
| 2847 | + if (!PyCode_Addr2Location(code, lasti, &startLine, &startCol, &endLine, |
| 2848 | + &endCol)) { |
| 2849 | + throw nb::python_error(); |
| 2850 | + } |
| 2851 | + MlirLocation loc = mlirLocationFileLineColRangeGet( |
| 2852 | + ctx, wrap(fileName), startLine, startCol, endLine, endCol); |
| 2853 | +#endif |
| 2854 | + |
| 2855 | + frames[count] = mlirLocationNameGet(ctx, wrap(funcName), loc); |
| 2856 | + ++count; |
| 2857 | + if (count > framesLimit) |
| 2858 | + break; |
| 2859 | + } |
| 2860 | + |
| 2861 | + if (count == 0) |
| 2862 | + return mlirLocationUnknownGet(ctx); |
| 2863 | + if (count == 1) |
| 2864 | + return frames.front(); |
| 2865 | + |
| 2866 | + MlirLocation callee = frames[0]; |
| 2867 | + MlirLocation caller = frames[count - 1]; |
| 2868 | + for (int i = count - 2; i >= 1; i--) |
| 2869 | + caller = mlirLocationCallSiteGet(frames[i], caller); |
| 2870 | + |
| 2871 | + return mlirLocationCallSiteGet(callee, caller); |
| 2872 | +} |
| 2873 | + |
2792 | 2874 | } // namespace
|
2793 | 2875 |
|
2794 | 2876 | //------------------------------------------------------------------------------
|
@@ -3241,7 +3323,11 @@ void mlir::python::populateIRCore(nb::module_ &m) {
|
3241 | 3323 | .def_static(
|
3242 | 3324 | "create",
|
3243 | 3325 | [](DefaultingPyLocation loc) {
|
3244 |
| - MlirModule module = mlirModuleCreateEmpty(loc); |
| 3326 | + PyMlirContextRef ctx = loc->getContext(); |
| 3327 | + MlirLocation mlirLoc = loc; |
| 3328 | + if (auto tloc = tracebackToLocation(ctx->get())) |
| 3329 | + mlirLoc = *tloc; |
| 3330 | + MlirModule module = mlirModuleCreateEmpty(mlirLoc); |
3245 | 3331 | return PyModule::forModule(module).releaseObject();
|
3246 | 3332 | },
|
3247 | 3333 | nb::arg("loc").none() = nb::none(), "Creates an empty module")
|
@@ -3467,9 +3553,15 @@ void mlir::python::populateIRCore(nb::module_ &m) {
|
3467 | 3553 | }
|
3468 | 3554 | }
|
3469 | 3555 |
|
| 3556 | + PyMlirContextRef ctx = ___location->getContext(); |
| 3557 | + if (auto loc = tracebackToLocation(ctx->get())) { |
| 3558 | + return PyOperation::create(name, results, mlirOperands, |
| 3559 | + attributes, successors, regions, |
| 3560 | + {ctx, *loc}, maybeIp, inferType); |
| 3561 | + } |
3470 | 3562 | return PyOperation::create(name, results, mlirOperands, attributes,
|
3471 |
| - successors, regions, ___location, maybeIp, |
3472 |
| - inferType); |
| 3563 | + successors, regions, *___location.get(), |
| 3564 | + maybeIp, inferType); |
3473 | 3565 | },
|
3474 | 3566 | nb::arg("name"), nb::arg("results").none() = nb::none(),
|
3475 | 3567 | nb::arg("operands").none() = nb::none(),
|
@@ -3514,10 +3606,19 @@ void mlir::python::populateIRCore(nb::module_ &m) {
|
3514 | 3606 | std::optional<std::vector<PyBlock *>> successors,
|
3515 | 3607 | std::optional<int> regions, DefaultingPyLocation ___location,
|
3516 | 3608 | const nb::object &maybeIp) {
|
3517 |
| - new (self) PyOpView(PyOpView::buildGeneric( |
3518 |
| - name, opRegionSpec, operandSegmentSpecObj, |
3519 |
| - resultSegmentSpecObj, resultTypeList, operandList, |
3520 |
| - attributes, successors, regions, ___location, maybeIp)); |
| 3609 | + PyMlirContextRef ctx = ___location->getContext(); |
| 3610 | + if (auto loc = tracebackToLocation(ctx->get())) { |
| 3611 | + new (self) PyOpView(PyOpView::buildGeneric( |
| 3612 | + name, opRegionSpec, operandSegmentSpecObj, |
| 3613 | + resultSegmentSpecObj, resultTypeList, operandList, |
| 3614 | + attributes, successors, regions, {ctx, *loc}, maybeIp)); |
| 3615 | + } else { |
| 3616 | + new (self) PyOpView(PyOpView::buildGeneric( |
| 3617 | + name, opRegionSpec, operandSegmentSpecObj, |
| 3618 | + resultSegmentSpecObj, resultTypeList, operandList, |
| 3619 | + attributes, successors, regions, *___location.get(), |
| 3620 | + maybeIp)); |
| 3621 | + } |
3521 | 3622 | },
|
3522 | 3623 | nb::arg("name"), nb::arg("opRegionSpec"),
|
3523 | 3624 | nb::arg("operandSegmentSpecObj").none() = nb::none(),
|
@@ -3558,10 +3659,18 @@ void mlir::python::populateIRCore(nb::module_ &m) {
|
3558 | 3659 | nb::cast<std::tuple<int, bool>>(cls.attr("_ODS_REGIONS"));
|
3559 | 3660 | nb::object operandSegmentSpec = cls.attr("_ODS_OPERAND_SEGMENTS");
|
3560 | 3661 | nb::object resultSegmentSpec = cls.attr("_ODS_RESULT_SEGMENTS");
|
| 3662 | + |
| 3663 | + PyMlirContextRef ctx = ___location->getContext(); |
| 3664 | + if (auto loc = tracebackToLocation(ctx->get())) { |
| 3665 | + return PyOpView::buildGeneric(name, opRegionSpec, operandSegmentSpec, |
| 3666 | + resultSegmentSpec, resultTypeList, |
| 3667 | + operandList, attributes, successors, |
| 3668 | + regions, {ctx, *loc}, maybeIp); |
| 3669 | + } |
3561 | 3670 | return PyOpView::buildGeneric(name, opRegionSpec, operandSegmentSpec,
|
3562 | 3671 | resultSegmentSpec, resultTypeList,
|
3563 | 3672 | operandList, attributes, successors,
|
3564 |
| - regions, ___location, maybeIp); |
| 3673 | + regions, *___location.get(), maybeIp); |
3565 | 3674 | },
|
3566 | 3675 | nb::arg("cls"), nb::arg("results").none() = nb::none(),
|
3567 | 3676 | nb::arg("operands").none() = nb::none(),
|
|
0 commit comments