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,111 @@ class PyOpAttributeMap {
2789
2786
PyOperationRef operation;
2790
2787
};
2791
2788
2789
+ // copied/borrow from
2790
+ // https://github.com/python/pythoncapi-compat/blob/b541b98df1e3e5aabb5def27422a75c876f5a88a/pythoncapi_compat.h#L222
2791
+ // bpo-40421 added PyFrame_GetLasti() to Python 3.11.0b1
2792
+ #if PY_VERSION_HEX < 0x030b00b1 && !defined(PYPY_VERSION)
2793
+ int PyFrame_GetLasti (PyFrameObject *frame) {
2794
+ #if PY_VERSION_HEX >= 0x030a00a7
2795
+ // bpo-27129: Since Python 3.10.0a7, f_lasti is an instruction offset,
2796
+ // not a bytes offset anymore. Python uses 16-bit "wordcode" (2 bytes)
2797
+ // instructions.
2798
+ if (frame->f_lasti < 0 ) {
2799
+ return -1 ;
2800
+ }
2801
+ return frame->f_lasti * 2 ;
2802
+ #else
2803
+ return frame->f_lasti ;
2804
+ #endif
2805
+ }
2806
+ #endif
2807
+
2808
+ constexpr size_t kMaxFrames = 512 ;
2809
+
2810
+ MlirLocation tracebackToLocation (MlirContext ctx) {
2811
+ size_t framesLimit =
2812
+ PyGlobals::get ().getTracebackLoc ().locTracebackFramesLimit ();
2813
+ // We use a thread_local here mostly to avoid requiring a large amount of
2814
+ // space.
2815
+ thread_local std::array<MlirLocation, kMaxFrames > frames;
2816
+ size_t count = 0 ;
2817
+
2818
+ assert (PyGILState_Check ());
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 ().getTracebackLoc ().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
+
2874
+ PyLocation
2875
+ maybeGetTracebackLocation (const std::optional<PyLocation> &___location) {
2876
+ MlirLocation mlirLoc;
2877
+ MlirContext mlirCtx;
2878
+ if (!___location.has_value () &&
2879
+ PyGlobals::get ().getTracebackLoc ().locTracebacksEnabled ()) {
2880
+ mlirCtx = DefaultingPyMlirContext::resolve ().get ();
2881
+ mlirLoc = tracebackToLocation (mlirCtx);
2882
+ } else if (!___location.has_value ()) {
2883
+ mlirLoc = DefaultingPyLocation::resolve ();
2884
+ mlirCtx = mlirLocationGetContext (mlirLoc);
2885
+ } else {
2886
+ mlirLoc = *___location;
2887
+ mlirCtx = mlirLocationGetContext (mlirLoc);
2888
+ }
2889
+ assert (!mlirLocationIsNull (mlirLoc) && " expected non-null mlirLoc" );
2890
+ PyMlirContextRef ctx = PyMlirContext::forContext (mlirCtx);
2891
+ return {ctx, mlirLoc};
2892
+ }
2893
+
2792
2894
} // namespace
2793
2895
2794
2896
// ------------------------------------------------------------------------------
@@ -3240,8 +3342,9 @@ void mlir::python::populateIRCore(nb::module_ &m) {
3240
3342
kModuleParseDocstring )
3241
3343
.def_static (
3242
3344
" create" ,
3243
- [](DefaultingPyLocation loc) {
3244
- MlirModule module = mlirModuleCreateEmpty (loc);
3345
+ [](std::optional<PyLocation> loc) {
3346
+ PyLocation pyLoc = maybeGetTracebackLocation (loc);
3347
+ MlirModule module = mlirModuleCreateEmpty (pyLoc.get ());
3245
3348
return PyModule::forModule (module ).releaseObject ();
3246
3349
},
3247
3350
nb::arg (" loc" ).none () = nb::none (), " Creates an empty module" )
@@ -3454,7 +3557,7 @@ void mlir::python::populateIRCore(nb::module_ &m) {
3454
3557
std::optional<std::vector<PyValue *>> operands,
3455
3558
std::optional<nb::dict> attributes,
3456
3559
std::optional<std::vector<PyBlock *>> successors, int regions,
3457
- DefaultingPyLocation ___location, const nb::object &maybeIp,
3560
+ std::optional<PyLocation> ___location, const nb::object &maybeIp,
3458
3561
bool inferType) {
3459
3562
// Unpack/validate operands.
3460
3563
llvm::SmallVector<MlirValue, 4 > mlirOperands;
@@ -3467,8 +3570,9 @@ void mlir::python::populateIRCore(nb::module_ &m) {
3467
3570
}
3468
3571
}
3469
3572
3573
+ PyLocation pyLoc = maybeGetTracebackLocation (___location);
3470
3574
return PyOperation::create (name, results, mlirOperands, attributes,
3471
- successors, regions, ___location , maybeIp,
3575
+ successors, regions, pyLoc , maybeIp,
3472
3576
inferType);
3473
3577
},
3474
3578
nb::arg (" name" ), nb::arg (" results" ).none () = nb::none (),
@@ -3512,12 +3616,13 @@ void mlir::python::populateIRCore(nb::module_ &m) {
3512
3616
std::optional<nb::list> resultTypeList, nb::list operandList,
3513
3617
std::optional<nb::dict> attributes,
3514
3618
std::optional<std::vector<PyBlock *>> successors,
3515
- std::optional<int > regions, DefaultingPyLocation ___location,
3619
+ std::optional<int > regions, std::optional<PyLocation> ___location,
3516
3620
const nb::object &maybeIp) {
3621
+ PyLocation pyLoc = maybeGetTracebackLocation (___location);
3517
3622
new (self) PyOpView (PyOpView::buildGeneric (
3518
3623
name, opRegionSpec, operandSegmentSpecObj,
3519
3624
resultSegmentSpecObj, resultTypeList, operandList,
3520
- attributes, successors, regions, ___location , maybeIp));
3625
+ attributes, successors, regions, pyLoc , maybeIp));
3521
3626
},
3522
3627
nb::arg (" name" ), nb::arg (" opRegionSpec" ),
3523
3628
nb::arg (" operandSegmentSpecObj" ).none () = nb::none (),
@@ -3551,17 +3656,18 @@ void mlir::python::populateIRCore(nb::module_ &m) {
3551
3656
[](nb::handle cls, std::optional<nb::list> resultTypeList,
3552
3657
nb::list operandList, std::optional<nb::dict> attributes,
3553
3658
std::optional<std::vector<PyBlock *>> successors,
3554
- std::optional<int > regions, DefaultingPyLocation ___location,
3659
+ std::optional<int > regions, std::optional<PyLocation> ___location,
3555
3660
const nb::object &maybeIp) {
3556
3661
std::string name = nb::cast<std::string>(cls.attr (" OPERATION_NAME" ));
3557
3662
std::tuple<int , bool > opRegionSpec =
3558
3663
nb::cast<std::tuple<int , bool >>(cls.attr (" _ODS_REGIONS" ));
3559
3664
nb::object operandSegmentSpec = cls.attr (" _ODS_OPERAND_SEGMENTS" );
3560
3665
nb::object resultSegmentSpec = cls.attr (" _ODS_RESULT_SEGMENTS" );
3666
+ PyLocation pyLoc = maybeGetTracebackLocation (___location);
3561
3667
return PyOpView::buildGeneric (name, opRegionSpec, operandSegmentSpec,
3562
3668
resultSegmentSpec, resultTypeList,
3563
3669
operandList, attributes, successors,
3564
- regions, ___location , maybeIp);
3670
+ regions, pyLoc , maybeIp);
3565
3671
},
3566
3672
nb::arg (" cls" ), nb::arg (" results" ).none () = nb::none (),
3567
3673
nb::arg (" operands" ).none () = nb::none (),
0 commit comments