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