19
19
#ifndef MLIR_BINDINGS_PYTHON_NANOBINDADAPTORS_H
20
20
#define MLIR_BINDINGS_PYTHON_NANOBINDADAPTORS_H
21
21
22
+ #include < atomic>
22
23
#include < cstdint>
24
+ #include < memory>
23
25
#include < optional>
24
26
25
27
#include " mlir-c/Diagnostics.h"
30
32
// clang-format on
31
33
#include " llvm/ADT/Twine.h"
32
34
35
+ namespace mlir {
36
+ namespace python {
37
+ namespace {
38
+
39
+ // Safely calls Python initialization code on first use, avoiding deadlocks.
40
+ template <typename T>
41
+ class SafeInit {
42
+ public:
43
+ typedef std::unique_ptr<T> (*F)();
44
+
45
+ explicit SafeInit (F init_fn) : initFn(init_fn) {}
46
+
47
+ T &get () {
48
+ if (T *result = output.load ()) {
49
+ return *result;
50
+ }
51
+
52
+ // Note: init_fn() may be called multiple times if, for example, the GIL is
53
+ // released during its execution. The intended use case is for module
54
+ // imports which are safe to perform multiple times. We are careful not to
55
+ // hold a lock across init_fn() to avoid lock ordering problems.
56
+ std::unique_ptr<T> m = initFn ();
57
+ {
58
+ nanobind::ft_lock_guard lock (mu);
59
+ if (T *result = output.load ()) {
60
+ return *result;
61
+ }
62
+ T *p = m.release ();
63
+ output.store (p);
64
+ return *p;
65
+ }
66
+ }
67
+
68
+ private:
69
+ nanobind::ft_mutex mu;
70
+ std::atomic<T *> output{nullptr };
71
+ F initFn;
72
+ };
73
+
74
+ nanobind::module_ &irModule () {
75
+ static SafeInit<nanobind::module_> init ([]() {
76
+ return std::make_unique<nanobind::module_>(
77
+ nanobind::module_::import_ (MAKE_MLIR_PYTHON_QUALNAME (" ir" )));
78
+ });
79
+ return init.get ();
80
+ }
81
+
82
+ } // namespace
83
+ } // namespace python
84
+ } // namespace mlir
85
+
33
86
// Raw CAPI type casters need to be declared before use, so always include them
34
87
// first.
35
88
namespace nanobind {
@@ -75,7 +128,7 @@ struct type_caster<MlirAffineMap> {
75
128
cleanup_list *cleanup) noexcept {
76
129
nanobind::object capsule =
77
130
nanobind::steal<nanobind::object>(mlirPythonAffineMapToCapsule (v));
78
- return nanobind::module_::import_ ( MAKE_MLIR_PYTHON_QUALNAME ( " ir " ) )
131
+ return mlir::python::irModule ( )
79
132
.attr (" AffineMap" )
80
133
.attr (MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
81
134
.release ();
@@ -97,7 +150,7 @@ struct type_caster<MlirAttribute> {
97
150
cleanup_list *cleanup) noexcept {
98
151
nanobind::object capsule =
99
152
nanobind::steal<nanobind::object>(mlirPythonAttributeToCapsule (v));
100
- return nanobind::module_::import_ ( MAKE_MLIR_PYTHON_QUALNAME ( " ir " ) )
153
+ return mlir::python::irModule ( )
101
154
.attr (" Attribute" )
102
155
.attr (MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
103
156
.attr (MLIR_PYTHON_MAYBE_DOWNCAST_ATTR)()
@@ -128,9 +181,7 @@ struct type_caster<MlirContext> {
128
181
// TODO: This raises an error of "No current context" currently.
129
182
// Update the implementation to pretty-print the helpful error that the
130
183
// core implementations print in this case.
131
- src = nanobind::module_::import_ (MAKE_MLIR_PYTHON_QUALNAME (" ir" ))
132
- .attr (" Context" )
133
- .attr (" current" );
184
+ src = mlir::python::irModule ().attr (" Context" ).attr (" current" );
134
185
}
135
186
std::optional<nanobind::object> capsule = mlirApiObjectToCapsule (src);
136
187
value = mlirPythonCapsuleToContext (capsule->ptr ());
@@ -153,7 +204,7 @@ struct type_caster<MlirDialectRegistry> {
153
204
cleanup_list *cleanup) noexcept {
154
205
nanobind::object capsule = nanobind::steal<nanobind::object>(
155
206
mlirPythonDialectRegistryToCapsule (v));
156
- return nanobind::module_::import_ ( MAKE_MLIR_PYTHON_QUALNAME ( " ir " ) )
207
+ return mlir::python::irModule ( )
157
208
.attr (" DialectRegistry" )
158
209
.attr (MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
159
210
.release ();
@@ -167,9 +218,7 @@ struct type_caster<MlirLocation> {
167
218
bool from_python (handle src, uint8_t flags, cleanup_list *cleanup) noexcept {
168
219
if (src.is_none ()) {
169
220
// Gets the current thread-bound context.
170
- src = nanobind::module_::import_ (MAKE_MLIR_PYTHON_QUALNAME (" ir" ))
171
- .attr (" Location" )
172
- .attr (" current" );
221
+ src = mlir::python::irModule ().attr (" Location" ).attr (" current" );
173
222
}
174
223
if (auto capsule = mlirApiObjectToCapsule (src)) {
175
224
value = mlirPythonCapsuleToLocation (capsule->ptr ());
@@ -181,7 +230,7 @@ struct type_caster<MlirLocation> {
181
230
cleanup_list *cleanup) noexcept {
182
231
nanobind::object capsule =
183
232
nanobind::steal<nanobind::object>(mlirPythonLocationToCapsule (v));
184
- return nanobind::module_::import_ ( MAKE_MLIR_PYTHON_QUALNAME ( " ir " ) )
233
+ return mlir::python::irModule ( )
185
234
.attr (" Location" )
186
235
.attr (MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
187
236
.release ();
@@ -203,7 +252,7 @@ struct type_caster<MlirModule> {
203
252
cleanup_list *cleanup) noexcept {
204
253
nanobind::object capsule =
205
254
nanobind::steal<nanobind::object>(mlirPythonModuleToCapsule (v));
206
- return nanobind::module_::import_ ( MAKE_MLIR_PYTHON_QUALNAME ( " ir " ) )
255
+ return mlir::python::irModule ( )
207
256
.attr (" Module" )
208
257
.attr (MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
209
258
.release ();
@@ -250,7 +299,7 @@ struct type_caster<MlirOperation> {
250
299
return nanobind::none ();
251
300
nanobind::object capsule =
252
301
nanobind::steal<nanobind::object>(mlirPythonOperationToCapsule (v));
253
- return nanobind::module_::import_ ( MAKE_MLIR_PYTHON_QUALNAME ( " ir " ) )
302
+ return mlir::python::irModule ( )
254
303
.attr (" Operation" )
255
304
.attr (MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
256
305
.release ();
@@ -274,7 +323,7 @@ struct type_caster<MlirValue> {
274
323
return nanobind::none ();
275
324
nanobind::object capsule =
276
325
nanobind::steal<nanobind::object>(mlirPythonValueToCapsule (v));
277
- return nanobind::module_::import_ ( MAKE_MLIR_PYTHON_QUALNAME ( " ir " ) )
326
+ return mlir::python::irModule ( )
278
327
.attr (" Value" )
279
328
.attr (MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
280
329
.attr (MLIR_PYTHON_MAYBE_DOWNCAST_ATTR)()
@@ -312,7 +361,7 @@ struct type_caster<MlirTypeID> {
312
361
return nanobind::none ();
313
362
nanobind::object capsule =
314
363
nanobind::steal<nanobind::object>(mlirPythonTypeIDToCapsule (v));
315
- return nanobind::module_::import_ ( MAKE_MLIR_PYTHON_QUALNAME ( " ir " ) )
364
+ return mlir::python::irModule ( )
316
365
.attr (" TypeID" )
317
366
.attr (MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
318
367
.release ();
@@ -334,7 +383,7 @@ struct type_caster<MlirType> {
334
383
cleanup_list *cleanup) noexcept {
335
384
nanobind::object capsule =
336
385
nanobind::steal<nanobind::object>(mlirPythonTypeToCapsule (t));
337
- return nanobind::module_::import_ ( MAKE_MLIR_PYTHON_QUALNAME ( " ir " ) )
386
+ return mlir::python::irModule ( )
338
387
.attr (" Type" )
339
388
.attr (MLIR_PYTHON_CAPI_FACTORY_ATTR)(capsule)
340
389
.attr (MLIR_PYTHON_MAYBE_DOWNCAST_ATTR)()
@@ -453,11 +502,9 @@ class mlir_attribute_subclass : public pure_subclass {
453
502
mlir_attribute_subclass (nanobind::handle scope, const char *attrClassName,
454
503
IsAFunctionTy isaFunction,
455
504
GetTypeIDFunctionTy getTypeIDFunction = nullptr )
456
- : mlir_attribute_subclass(
457
- scope, attrClassName, isaFunction,
458
- nanobind::module_::import_ (MAKE_MLIR_PYTHON_QUALNAME(" ir" ))
459
- .attr(" Attribute" ),
460
- getTypeIDFunction) {}
505
+ : mlir_attribute_subclass(scope, attrClassName, isaFunction,
506
+ irModule ().attr(" Attribute" ),
507
+ getTypeIDFunction) {}
461
508
462
509
// / Subclasses with a provided mlir.ir.Attribute super-class. This must
463
510
// / be used if the subclass is being defined in the same extension module
@@ -540,11 +587,8 @@ class mlir_type_subclass : public pure_subclass {
540
587
mlir_type_subclass (nanobind::handle scope, const char *typeClassName,
541
588
IsAFunctionTy isaFunction,
542
589
GetTypeIDFunctionTy getTypeIDFunction = nullptr )
543
- : mlir_type_subclass(
544
- scope, typeClassName, isaFunction,
545
- nanobind::module_::import_ (MAKE_MLIR_PYTHON_QUALNAME(" ir" ))
546
- .attr(" Type" ),
547
- getTypeIDFunction) {}
590
+ : mlir_type_subclass(scope, typeClassName, isaFunction,
591
+ irModule ().attr(" Type" ), getTypeIDFunction) {}
548
592
549
593
// / Subclasses with a provided mlir.ir.Type super-class. This must
550
594
// / be used if the subclass is being defined in the same extension module
@@ -631,10 +675,8 @@ class mlir_value_subclass : public pure_subclass {
631
675
// / Subclasses by looking up the super-class dynamically.
632
676
mlir_value_subclass (nanobind::handle scope, const char *valueClassName,
633
677
IsAFunctionTy isaFunction)
634
- : mlir_value_subclass(
635
- scope, valueClassName, isaFunction,
636
- nanobind::module_::import_ (MAKE_MLIR_PYTHON_QUALNAME(" ir" ))
637
- .attr(" Value" )) {}
678
+ : mlir_value_subclass(scope, valueClassName, isaFunction,
679
+ irModule ().attr(" Value" )) {}
638
680
639
681
// / Subclasses with a provided mlir.ir.Value super-class. This must
640
682
// / be used if the subclass is being defined in the same extension module
0 commit comments