MLIR  22.0.0git
IRAttributes.cpp
Go to the documentation of this file.
1 //===- IRAttributes.cpp - Exports builtin and standard attributes ---------===//
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 <cstdint>
10 #include <optional>
11 #include <string>
12 #include <string_view>
13 #include <utility>
14 
15 #include "IRModule.h"
16 #include "NanobindUtils.h"
18 #include "mlir-c/BuiltinTypes.h"
21 #include "llvm/ADT/ScopeExit.h"
22 #include "llvm/Support/raw_ostream.h"
23 
24 namespace nb = nanobind;
25 using namespace nanobind::literals;
26 using namespace mlir;
27 using namespace mlir::python;
28 
29 using llvm::SmallVector;
30 
31 //------------------------------------------------------------------------------
32 // Docstrings (trivial, non-duplicated docstrings are included inline).
33 //------------------------------------------------------------------------------
34 
35 static const char kDenseElementsAttrGetDocstring[] =
36  R"(Gets a DenseElementsAttr from a Python buffer or array.
37 
38 When `type` is not provided, then some limited type inferencing is done based
39 on the buffer format. Support presently exists for 8/16/32/64 signed and
40 unsigned integers and float16/float32/float64. DenseElementsAttrs of these
41 types can also be converted back to a corresponding buffer.
42 
43 For conversions outside of these types, a `type=` must be explicitly provided
44 and the buffer contents must be bit-castable to the MLIR internal
45 representation:
46 
47  * Integer types (except for i1): the buffer must be byte aligned to the
48  next byte boundary.
49  * Floating point types: Must be bit-castable to the given floating point
50  size.
51  * i1 (bool): Bit packed into 8bit words where the bit pattern matches a
52  row major ordering. An arbitrary Numpy `bool_` array can be bit packed to
53  this specification with: `np.packbits(ary, axis=None, bitorder='little')`.
54 
55 If a single element buffer is passed (or for i1, a single byte with value 0
56 or 255), then a splat will be created.
57 
58 Args:
59  array: The array or buffer to convert.
60  signless: If inferring an appropriate MLIR type, use signless types for
61  integers (defaults True).
62  type: Skips inference of the MLIR element type and uses this instead. The
63  storage size must be consistent with the actual contents of the buffer.
64  shape: Overrides the shape of the buffer when constructing the MLIR
65  shaped type. This is needed when the physical and logical shape differ (as
66  for i1).
67  context: Explicit context, if not from context manager.
68 
69 Returns:
70  DenseElementsAttr on success.
71 
72 Raises:
73  ValueError: If the type of the buffer or array cannot be matched to an MLIR
74  type or if the buffer does not meet expectations.
75 )";
76 
78  R"(Gets a DenseElementsAttr from a Python list of attributes.
79 
80 Note that it can be expensive to construct attributes individually.
81 For a large number of elements, consider using a Python buffer or array instead.
82 
83 Args:
84  attrs: A list of attributes.
85  type: The desired shape and type of the resulting DenseElementsAttr.
86  If not provided, the element type is determined based on the type
87  of the 0th attribute and the shape is `[len(attrs)]`.
88  context: Explicit context, if not from context manager.
89 
90 Returns:
91  DenseElementsAttr on success.
92 
93 Raises:
94  ValueError: If the type of the attributes does not match the type
95  specified by `shaped_type`.
96 )";
97 
99  R"(Gets a DenseResourceElementsAttr from a Python buffer or array.
100 
101 This function does minimal validation or massaging of the data, and it is
102 up to the caller to ensure that the buffer meets the characteristics
103 implied by the shape.
104 
105 The backing buffer and any user objects will be retained for the lifetime
106 of the resource blob. This is typically bounded to the context but the
107 resource can have a shorter lifespan depending on how it is used in
108 subsequent processing.
109 
110 Args:
111  buffer: The array or buffer to convert.
112  name: Name to provide to the resource (may be changed upon collision).
113  type: The explicit ShapedType to construct the attribute with.
114  context: Explicit context, if not from context manager.
115 
116 Returns:
117  DenseResourceElementsAttr on success.
118 
119 Raises:
120  ValueError: If the type of the buffer or array cannot be matched to an MLIR
121  type or if the buffer does not meet expectations.
122 )";
123 
124 namespace {
125 
126 struct nb_buffer_info {
127  void *ptr = nullptr;
128  ssize_t itemsize = 0;
129  ssize_t size = 0;
130  const char *format = nullptr;
131  ssize_t ndim = 0;
133  SmallVector<ssize_t, 4> strides;
134  bool readonly = false;
135 
136  nb_buffer_info(
137  void *ptr, ssize_t itemsize, const char *format, ssize_t ndim,
139  bool readonly = false,
140  std::unique_ptr<Py_buffer, void (*)(Py_buffer *)> owned_view_in =
141  std::unique_ptr<Py_buffer, void (*)(Py_buffer *)>(nullptr, nullptr))
142  : ptr(ptr), itemsize(itemsize), format(format), ndim(ndim),
143  shape(std::move(shape_in)), strides(std::move(strides_in)),
144  readonly(readonly), owned_view(std::move(owned_view_in)) {
145  size = 1;
146  for (ssize_t i = 0; i < ndim; ++i) {
147  size *= shape[i];
148  }
149  }
150 
151  explicit nb_buffer_info(Py_buffer *view)
152  : nb_buffer_info(view->buf, view->itemsize, view->format, view->ndim,
153  {view->shape, view->shape + view->ndim},
154  // TODO(phawkins): check for null strides
155  {view->strides, view->strides + view->ndim},
156  view->readonly != 0,
157  std::unique_ptr<Py_buffer, void (*)(Py_buffer *)>(
158  view, PyBuffer_Release)) {}
159 
160  nb_buffer_info(const nb_buffer_info &) = delete;
161  nb_buffer_info(nb_buffer_info &&) = default;
162  nb_buffer_info &operator=(const nb_buffer_info &) = delete;
163  nb_buffer_info &operator=(nb_buffer_info &&) = default;
164 
165 private:
166  std::unique_ptr<Py_buffer, void (*)(Py_buffer *)> owned_view;
167 };
168 
169 class nb_buffer : public nb::object {
170  NB_OBJECT_DEFAULT(nb_buffer, object, "Buffer", PyObject_CheckBuffer);
171 
172  nb_buffer_info request() const {
173  int flags = PyBUF_STRIDES | PyBUF_FORMAT;
174  auto *view = new Py_buffer();
175  if (PyObject_GetBuffer(ptr(), view, flags) != 0) {
176  delete view;
177  throw nb::python_error();
178  }
179  return nb_buffer_info(view);
180  }
181 };
182 
183 template <typename T>
184 struct nb_format_descriptor {};
185 
186 template <>
187 struct nb_format_descriptor<bool> {
188  static const char *format() { return "?"; }
189 };
190 template <>
191 struct nb_format_descriptor<int8_t> {
192  static const char *format() { return "b"; }
193 };
194 template <>
195 struct nb_format_descriptor<uint8_t> {
196  static const char *format() { return "B"; }
197 };
198 template <>
199 struct nb_format_descriptor<int16_t> {
200  static const char *format() { return "h"; }
201 };
202 template <>
203 struct nb_format_descriptor<uint16_t> {
204  static const char *format() { return "H"; }
205 };
206 template <>
207 struct nb_format_descriptor<int32_t> {
208  static const char *format() { return "i"; }
209 };
210 template <>
211 struct nb_format_descriptor<uint32_t> {
212  static const char *format() { return "I"; }
213 };
214 template <>
215 struct nb_format_descriptor<int64_t> {
216  static const char *format() { return "q"; }
217 };
218 template <>
219 struct nb_format_descriptor<uint64_t> {
220  static const char *format() { return "Q"; }
221 };
222 template <>
223 struct nb_format_descriptor<float> {
224  static const char *format() { return "f"; }
225 };
226 template <>
227 struct nb_format_descriptor<double> {
228  static const char *format() { return "d"; }
229 };
230 
231 static MlirStringRef toMlirStringRef(const std::string &s) {
232  return mlirStringRefCreate(s.data(), s.size());
233 }
234 
235 static MlirStringRef toMlirStringRef(const nb::bytes &s) {
236  return mlirStringRefCreate(static_cast<const char *>(s.data()), s.size());
237 }
238 
239 class PyAffineMapAttribute : public PyConcreteAttribute<PyAffineMapAttribute> {
240 public:
241  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsAAffineMap;
242  static constexpr const char *pyClassName = "AffineMapAttr";
243  using PyConcreteAttribute::PyConcreteAttribute;
244  static constexpr GetTypeIDFunctionTy getTypeIdFunction =
246 
247  static void bindDerived(ClassTy &c) {
248  c.def_static(
249  "get",
250  [](PyAffineMap &affineMap) {
251  MlirAttribute attr = mlirAffineMapAttrGet(affineMap.get());
252  return PyAffineMapAttribute(affineMap.getContext(), attr);
253  },
254  nb::arg("affine_map"), "Gets an attribute wrapping an AffineMap.");
255  c.def_prop_ro(
256  "value",
257  [](PyAffineMapAttribute &self) {
258  return PyAffineMap(self.getContext(),
260  },
261  "Returns the value of the AffineMap attribute");
262  }
263 };
264 
265 class PyIntegerSetAttribute
266  : public PyConcreteAttribute<PyIntegerSetAttribute> {
267 public:
268  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsAIntegerSet;
269  static constexpr const char *pyClassName = "IntegerSetAttr";
270  using PyConcreteAttribute::PyConcreteAttribute;
271  static constexpr GetTypeIDFunctionTy getTypeIdFunction =
273 
274  static void bindDerived(ClassTy &c) {
275  c.def_static(
276  "get",
277  [](PyIntegerSet &integerSet) {
278  MlirAttribute attr = mlirIntegerSetAttrGet(integerSet.get());
279  return PyIntegerSetAttribute(integerSet.getContext(), attr);
280  },
281  nb::arg("integer_set"), "Gets an attribute wrapping an IntegerSet.");
282  }
283 };
284 
285 template <typename T>
286 static T pyTryCast(nb::handle object) {
287  try {
288  return nb::cast<T>(object);
289  } catch (nb::cast_error &err) {
290  std::string msg = std::string("Invalid attribute when attempting to "
291  "create an ArrayAttribute (") +
292  err.what() + ")";
293  throw std::runtime_error(msg.c_str());
294  } catch (std::runtime_error &err) {
295  std::string msg = std::string("Invalid attribute (None?) when attempting "
296  "to create an ArrayAttribute (") +
297  err.what() + ")";
298  throw std::runtime_error(msg.c_str());
299  }
300 }
301 
302 /// A python-wrapped dense array attribute with an element type and a derived
303 /// implementation class.
304 template <typename EltTy, typename DerivedT>
305 class PyDenseArrayAttribute : public PyConcreteAttribute<DerivedT> {
306 public:
308 
309  /// Iterator over the integer elements of a dense array.
310  class PyDenseArrayIterator {
311  public:
312  PyDenseArrayIterator(PyAttribute attr) : attr(std::move(attr)) {}
313 
314  /// Return a copy of the iterator.
315  PyDenseArrayIterator dunderIter() { return *this; }
316 
317  /// Return the next element.
318  EltTy dunderNext() {
319  // Throw if the index has reached the end.
321  throw nb::stop_iteration();
322  return DerivedT::getElement(attr.get(), nextIndex++);
323  }
324 
325  /// Bind the iterator class.
326  static void bind(nb::module_ &m) {
327  nb::class_<PyDenseArrayIterator>(m, DerivedT::pyIteratorName)
328  .def("__iter__", &PyDenseArrayIterator::dunderIter)
329  .def("__next__", &PyDenseArrayIterator::dunderNext);
330  }
331 
332  private:
333  /// The referenced dense array attribute.
334  PyAttribute attr;
335  /// The next index to read.
336  int nextIndex = 0;
337  };
338 
339  /// Get the element at the given index.
340  EltTy getItem(intptr_t i) { return DerivedT::getElement(*this, i); }
341 
342  /// Bind the attribute class.
343  static void bindDerived(typename PyConcreteAttribute<DerivedT>::ClassTy &c) {
344  // Bind the constructor.
345  if constexpr (std::is_same_v<EltTy, bool>) {
346  c.def_static(
347  "get",
348  [](const nb::sequence &py_values, DefaultingPyMlirContext ctx) {
349  std::vector<bool> values;
350  for (nb::handle py_value : py_values) {
351  int is_true = PyObject_IsTrue(py_value.ptr());
352  if (is_true < 0) {
353  throw nb::python_error();
354  }
355  values.push_back(is_true);
356  }
357  return getAttribute(values, ctx->getRef());
358  },
359  nb::arg("values"), nb::arg("context") = nb::none(),
360  "Gets a uniqued dense array attribute");
361  } else {
362  c.def_static(
363  "get",
364  [](const std::vector<EltTy> &values, DefaultingPyMlirContext ctx) {
365  return getAttribute(values, ctx->getRef());
366  },
367  nb::arg("values"), nb::arg("context") = nb::none(),
368  "Gets a uniqued dense array attribute");
369  }
370  // Bind the array methods.
371  c.def("__getitem__", [](DerivedT &arr, intptr_t i) {
372  if (i >= mlirDenseArrayGetNumElements(arr))
373  throw nb::index_error("DenseArray index out of range");
374  return arr.getItem(i);
375  });
376  c.def("__len__", [](const DerivedT &arr) {
377  return mlirDenseArrayGetNumElements(arr);
378  });
379  c.def("__iter__",
380  [](const DerivedT &arr) { return PyDenseArrayIterator(arr); });
381  c.def("__add__", [](DerivedT &arr, const nb::list &extras) {
382  std::vector<EltTy> values;
383  intptr_t numOldElements = mlirDenseArrayGetNumElements(arr);
384  values.reserve(numOldElements + nb::len(extras));
385  for (intptr_t i = 0; i < numOldElements; ++i)
386  values.push_back(arr.getItem(i));
387  for (nb::handle attr : extras)
388  values.push_back(pyTryCast<EltTy>(attr));
389  return getAttribute(values, arr.getContext());
390  });
391  }
392 
393 private:
394  static DerivedT getAttribute(const std::vector<EltTy> &values,
395  PyMlirContextRef ctx) {
396  if constexpr (std::is_same_v<EltTy, bool>) {
397  std::vector<int> intValues(values.begin(), values.end());
398  MlirAttribute attr = DerivedT::getAttribute(ctx->get(), intValues.size(),
399  intValues.data());
400  return DerivedT(ctx, attr);
401  } else {
402  MlirAttribute attr =
403  DerivedT::getAttribute(ctx->get(), values.size(), values.data());
404  return DerivedT(ctx, attr);
405  }
406  }
407 };
408 
409 /// Instantiate the python dense array classes.
410 struct PyDenseBoolArrayAttribute
411  : public PyDenseArrayAttribute<bool, PyDenseBoolArrayAttribute> {
412  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsADenseBoolArray;
413  static constexpr auto getAttribute = mlirDenseBoolArrayGet;
414  static constexpr auto getElement = mlirDenseBoolArrayGetElement;
415  static constexpr const char *pyClassName = "DenseBoolArrayAttr";
416  static constexpr const char *pyIteratorName = "DenseBoolArrayIterator";
417  using PyDenseArrayAttribute::PyDenseArrayAttribute;
418 };
419 struct PyDenseI8ArrayAttribute
420  : public PyDenseArrayAttribute<int8_t, PyDenseI8ArrayAttribute> {
421  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsADenseI8Array;
422  static constexpr auto getAttribute = mlirDenseI8ArrayGet;
423  static constexpr auto getElement = mlirDenseI8ArrayGetElement;
424  static constexpr const char *pyClassName = "DenseI8ArrayAttr";
425  static constexpr const char *pyIteratorName = "DenseI8ArrayIterator";
426  using PyDenseArrayAttribute::PyDenseArrayAttribute;
427 };
428 struct PyDenseI16ArrayAttribute
429  : public PyDenseArrayAttribute<int16_t, PyDenseI16ArrayAttribute> {
430  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsADenseI16Array;
431  static constexpr auto getAttribute = mlirDenseI16ArrayGet;
432  static constexpr auto getElement = mlirDenseI16ArrayGetElement;
433  static constexpr const char *pyClassName = "DenseI16ArrayAttr";
434  static constexpr const char *pyIteratorName = "DenseI16ArrayIterator";
435  using PyDenseArrayAttribute::PyDenseArrayAttribute;
436 };
437 struct PyDenseI32ArrayAttribute
438  : public PyDenseArrayAttribute<int32_t, PyDenseI32ArrayAttribute> {
439  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsADenseI32Array;
440  static constexpr auto getAttribute = mlirDenseI32ArrayGet;
441  static constexpr auto getElement = mlirDenseI32ArrayGetElement;
442  static constexpr const char *pyClassName = "DenseI32ArrayAttr";
443  static constexpr const char *pyIteratorName = "DenseI32ArrayIterator";
444  using PyDenseArrayAttribute::PyDenseArrayAttribute;
445 };
446 struct PyDenseI64ArrayAttribute
447  : public PyDenseArrayAttribute<int64_t, PyDenseI64ArrayAttribute> {
448  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsADenseI64Array;
449  static constexpr auto getAttribute = mlirDenseI64ArrayGet;
450  static constexpr auto getElement = mlirDenseI64ArrayGetElement;
451  static constexpr const char *pyClassName = "DenseI64ArrayAttr";
452  static constexpr const char *pyIteratorName = "DenseI64ArrayIterator";
453  using PyDenseArrayAttribute::PyDenseArrayAttribute;
454 };
455 struct PyDenseF32ArrayAttribute
456  : public PyDenseArrayAttribute<float, PyDenseF32ArrayAttribute> {
457  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsADenseF32Array;
458  static constexpr auto getAttribute = mlirDenseF32ArrayGet;
459  static constexpr auto getElement = mlirDenseF32ArrayGetElement;
460  static constexpr const char *pyClassName = "DenseF32ArrayAttr";
461  static constexpr const char *pyIteratorName = "DenseF32ArrayIterator";
462  using PyDenseArrayAttribute::PyDenseArrayAttribute;
463 };
464 struct PyDenseF64ArrayAttribute
465  : public PyDenseArrayAttribute<double, PyDenseF64ArrayAttribute> {
466  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsADenseF64Array;
467  static constexpr auto getAttribute = mlirDenseF64ArrayGet;
468  static constexpr auto getElement = mlirDenseF64ArrayGetElement;
469  static constexpr const char *pyClassName = "DenseF64ArrayAttr";
470  static constexpr const char *pyIteratorName = "DenseF64ArrayIterator";
471  using PyDenseArrayAttribute::PyDenseArrayAttribute;
472 };
473 
474 class PyArrayAttribute : public PyConcreteAttribute<PyArrayAttribute> {
475 public:
476  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsAArray;
477  static constexpr const char *pyClassName = "ArrayAttr";
478  using PyConcreteAttribute::PyConcreteAttribute;
479  static constexpr GetTypeIDFunctionTy getTypeIdFunction =
481 
482  class PyArrayAttributeIterator {
483  public:
484  PyArrayAttributeIterator(PyAttribute attr) : attr(std::move(attr)) {}
485 
486  PyArrayAttributeIterator &dunderIter() { return *this; }
487 
488  nb::object dunderNext() {
489  // TODO: Throw is an inefficient way to stop iteration.
491  throw nb::stop_iteration();
492  return PyAttribute(this->attr.getContext(),
494  .maybeDownCast();
495  }
496 
497  static void bind(nb::module_ &m) {
498  nb::class_<PyArrayAttributeIterator>(m, "ArrayAttributeIterator")
499  .def("__iter__", &PyArrayAttributeIterator::dunderIter)
500  .def("__next__", &PyArrayAttributeIterator::dunderNext);
501  }
502 
503  private:
504  PyAttribute attr;
505  int nextIndex = 0;
506  };
507 
508  MlirAttribute getItem(intptr_t i) {
509  return mlirArrayAttrGetElement(*this, i);
510  }
511 
512  static void bindDerived(ClassTy &c) {
513  c.def_static(
514  "get",
515  [](const nb::list &attributes, DefaultingPyMlirContext context) {
516  SmallVector<MlirAttribute> mlirAttributes;
517  mlirAttributes.reserve(nb::len(attributes));
518  for (auto attribute : attributes) {
519  mlirAttributes.push_back(pyTryCast<PyAttribute>(attribute));
520  }
521  MlirAttribute attr = mlirArrayAttrGet(
522  context->get(), mlirAttributes.size(), mlirAttributes.data());
523  return PyArrayAttribute(context->getRef(), attr);
524  },
525  nb::arg("attributes"), nb::arg("context") = nb::none(),
526  "Gets a uniqued Array attribute");
527  c.def(
528  "__getitem__",
529  [](PyArrayAttribute &arr, intptr_t i) {
530  if (i >= mlirArrayAttrGetNumElements(arr))
531  throw nb::index_error("ArrayAttribute index out of range");
532  return PyAttribute(arr.getContext(), arr.getItem(i)).maybeDownCast();
533  })
534  .def("__len__",
535  [](const PyArrayAttribute &arr) {
536  return mlirArrayAttrGetNumElements(arr);
537  })
538  .def("__iter__", [](const PyArrayAttribute &arr) {
539  return PyArrayAttributeIterator(arr);
540  });
541  c.def("__add__", [](PyArrayAttribute arr, const nb::list &extras) {
542  std::vector<MlirAttribute> attributes;
543  intptr_t numOldElements = mlirArrayAttrGetNumElements(arr);
544  attributes.reserve(numOldElements + nb::len(extras));
545  for (intptr_t i = 0; i < numOldElements; ++i)
546  attributes.push_back(arr.getItem(i));
547  for (nb::handle attr : extras)
548  attributes.push_back(pyTryCast<PyAttribute>(attr));
549  MlirAttribute arrayAttr = mlirArrayAttrGet(
550  arr.getContext()->get(), attributes.size(), attributes.data());
551  return PyArrayAttribute(arr.getContext(), arrayAttr);
552  });
553  }
554 };
555 
556 /// Float Point Attribute subclass - FloatAttr.
557 class PyFloatAttribute : public PyConcreteAttribute<PyFloatAttribute> {
558 public:
559  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsAFloat;
560  static constexpr const char *pyClassName = "FloatAttr";
561  using PyConcreteAttribute::PyConcreteAttribute;
562  static constexpr GetTypeIDFunctionTy getTypeIdFunction =
564 
565  static void bindDerived(ClassTy &c) {
566  c.def_static(
567  "get",
568  [](PyType &type, double value, DefaultingPyLocation loc) {
569  PyMlirContext::ErrorCapture errors(loc->getContext());
570  MlirAttribute attr = mlirFloatAttrDoubleGetChecked(loc, type, value);
571  if (mlirAttributeIsNull(attr))
572  throw MLIRError("Invalid attribute", errors.take());
573  return PyFloatAttribute(type.getContext(), attr);
574  },
575  nb::arg("type"), nb::arg("value"), nb::arg("loc") = nb::none(),
576  "Gets an uniqued float point attribute associated to a type");
577  c.def_static(
578  "get_f32",
579  [](double value, DefaultingPyMlirContext context) {
580  MlirAttribute attr = mlirFloatAttrDoubleGet(
581  context->get(), mlirF32TypeGet(context->get()), value);
582  return PyFloatAttribute(context->getRef(), attr);
583  },
584  nb::arg("value"), nb::arg("context") = nb::none(),
585  "Gets an uniqued float point attribute associated to a f32 type");
586  c.def_static(
587  "get_f64",
588  [](double value, DefaultingPyMlirContext context) {
589  MlirAttribute attr = mlirFloatAttrDoubleGet(
590  context->get(), mlirF64TypeGet(context->get()), value);
591  return PyFloatAttribute(context->getRef(), attr);
592  },
593  nb::arg("value"), nb::arg("context") = nb::none(),
594  "Gets an uniqued float point attribute associated to a f64 type");
595  c.def_prop_ro("value", mlirFloatAttrGetValueDouble,
596  "Returns the value of the float attribute");
597  c.def("__float__", mlirFloatAttrGetValueDouble,
598  "Converts the value of the float attribute to a Python float");
599  }
600 };
601 
602 /// Integer Attribute subclass - IntegerAttr.
603 class PyIntegerAttribute : public PyConcreteAttribute<PyIntegerAttribute> {
604 public:
605  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsAInteger;
606  static constexpr const char *pyClassName = "IntegerAttr";
607  using PyConcreteAttribute::PyConcreteAttribute;
608 
609  static void bindDerived(ClassTy &c) {
610  c.def_static(
611  "get",
612  [](PyType &type, int64_t value) {
613  MlirAttribute attr = mlirIntegerAttrGet(type, value);
614  return PyIntegerAttribute(type.getContext(), attr);
615  },
616  nb::arg("type"), nb::arg("value"),
617  "Gets an uniqued integer attribute associated to a type");
618  c.def_prop_ro("value", toPyInt,
619  "Returns the value of the integer attribute");
620  c.def("__int__", toPyInt,
621  "Converts the value of the integer attribute to a Python int");
622  c.def_prop_ro_static(
623  "static_typeid",
624  [](nb::object & /*class*/) {
626  },
627  nanobind::sig("def static_typeid(/) -> TypeID"));
628  }
629 
630 private:
631  static int64_t toPyInt(PyIntegerAttribute &self) {
632  MlirType type = mlirAttributeGetType(self);
633  if (mlirTypeIsAIndex(type) || mlirIntegerTypeIsSignless(type))
634  return mlirIntegerAttrGetValueInt(self);
635  if (mlirIntegerTypeIsSigned(type))
636  return mlirIntegerAttrGetValueSInt(self);
637  return mlirIntegerAttrGetValueUInt(self);
638  }
639 };
640 
641 /// Bool Attribute subclass - BoolAttr.
642 class PyBoolAttribute : public PyConcreteAttribute<PyBoolAttribute> {
643 public:
644  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsABool;
645  static constexpr const char *pyClassName = "BoolAttr";
646  using PyConcreteAttribute::PyConcreteAttribute;
647 
648  static void bindDerived(ClassTy &c) {
649  c.def_static(
650  "get",
651  [](bool value, DefaultingPyMlirContext context) {
652  MlirAttribute attr = mlirBoolAttrGet(context->get(), value);
653  return PyBoolAttribute(context->getRef(), attr);
654  },
655  nb::arg("value"), nb::arg("context") = nb::none(),
656  "Gets an uniqued bool attribute");
657  c.def_prop_ro("value", mlirBoolAttrGetValue,
658  "Returns the value of the bool attribute");
659  c.def("__bool__", mlirBoolAttrGetValue,
660  "Converts the value of the bool attribute to a Python bool");
661  }
662 };
663 
664 class PySymbolRefAttribute : public PyConcreteAttribute<PySymbolRefAttribute> {
665 public:
666  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsASymbolRef;
667  static constexpr const char *pyClassName = "SymbolRefAttr";
668  using PyConcreteAttribute::PyConcreteAttribute;
669 
670  static PySymbolRefAttribute fromList(const std::vector<std::string> &symbols,
671  PyMlirContext &context) {
672  if (symbols.empty())
673  throw std::runtime_error("SymbolRefAttr must be composed of at least "
674  "one symbol.");
675  MlirStringRef rootSymbol = toMlirStringRef(symbols[0]);
676  SmallVector<MlirAttribute, 3> referenceAttrs;
677  for (size_t i = 1; i < symbols.size(); ++i) {
678  referenceAttrs.push_back(
679  mlirFlatSymbolRefAttrGet(context.get(), toMlirStringRef(symbols[i])));
680  }
681  return PySymbolRefAttribute(context.getRef(),
682  mlirSymbolRefAttrGet(context.get(), rootSymbol,
683  referenceAttrs.size(),
684  referenceAttrs.data()));
685  }
686 
687  static void bindDerived(ClassTy &c) {
688  c.def_static(
689  "get",
690  [](const std::vector<std::string> &symbols,
691  DefaultingPyMlirContext context) {
692  return PySymbolRefAttribute::fromList(symbols, context.resolve());
693  },
694  nb::arg("symbols"), nb::arg("context") = nb::none(),
695  "Gets a uniqued SymbolRef attribute from a list of symbol names");
696  c.def_prop_ro(
697  "value",
698  [](PySymbolRefAttribute &self) {
699  std::vector<std::string> symbols = {
701  for (int i = 0; i < mlirSymbolRefAttrGetNumNestedReferences(self);
702  ++i)
703  symbols.push_back(
706  .str());
707  return symbols;
708  },
709  "Returns the value of the SymbolRef attribute as a list[str]");
710  }
711 };
712 
713 class PyFlatSymbolRefAttribute
714  : public PyConcreteAttribute<PyFlatSymbolRefAttribute> {
715 public:
716  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsAFlatSymbolRef;
717  static constexpr const char *pyClassName = "FlatSymbolRefAttr";
718  using PyConcreteAttribute::PyConcreteAttribute;
719 
720  static void bindDerived(ClassTy &c) {
721  c.def_static(
722  "get",
723  [](const std::string &value, DefaultingPyMlirContext context) {
724  MlirAttribute attr =
725  mlirFlatSymbolRefAttrGet(context->get(), toMlirStringRef(value));
726  return PyFlatSymbolRefAttribute(context->getRef(), attr);
727  },
728  nb::arg("value"), nb::arg("context") = nb::none(),
729  "Gets a uniqued FlatSymbolRef attribute");
730  c.def_prop_ro(
731  "value",
732  [](PyFlatSymbolRefAttribute &self) {
734  return nb::str(stringRef.data, stringRef.length);
735  },
736  "Returns the value of the FlatSymbolRef attribute as a string");
737  }
738 };
739 
740 class PyOpaqueAttribute : public PyConcreteAttribute<PyOpaqueAttribute> {
741 public:
742  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsAOpaque;
743  static constexpr const char *pyClassName = "OpaqueAttr";
744  using PyConcreteAttribute::PyConcreteAttribute;
745  static constexpr GetTypeIDFunctionTy getTypeIdFunction =
747 
748  static void bindDerived(ClassTy &c) {
749  c.def_static(
750  "get",
751  [](const std::string &dialectNamespace, const nb_buffer &buffer,
752  PyType &type, DefaultingPyMlirContext context) {
753  const nb_buffer_info bufferInfo = buffer.request();
754  intptr_t bufferSize = bufferInfo.size;
755  MlirAttribute attr = mlirOpaqueAttrGet(
756  context->get(), toMlirStringRef(dialectNamespace), bufferSize,
757  static_cast<char *>(bufferInfo.ptr), type);
758  return PyOpaqueAttribute(context->getRef(), attr);
759  },
760  nb::arg("dialect_namespace"), nb::arg("buffer"), nb::arg("type"),
761  nb::arg("context") = nb::none(),
762  // clang-format off
763  nb::sig("def get(dialect_namespace: str, buffer: typing_extensions.Buffer, type: Type, context: Context | None = None) -> OpaqueAttr"),
764  // clang-format on
765  "Gets an Opaque attribute.");
766  c.def_prop_ro(
767  "dialect_namespace",
768  [](PyOpaqueAttribute &self) {
770  return nb::str(stringRef.data, stringRef.length);
771  },
772  "Returns the dialect namespace for the Opaque attribute as a string");
773  c.def_prop_ro(
774  "data",
775  [](PyOpaqueAttribute &self) {
776  MlirStringRef stringRef = mlirOpaqueAttrGetData(self);
777  return nb::bytes(stringRef.data, stringRef.length);
778  },
779  "Returns the data for the Opaqued attributes as `bytes`");
780  }
781 };
782 
783 // TODO: Support construction of string elements.
784 class PyDenseElementsAttribute
785  : public PyConcreteAttribute<PyDenseElementsAttribute> {
786 public:
787  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsADenseElements;
788  static constexpr const char *pyClassName = "DenseElementsAttr";
789  using PyConcreteAttribute::PyConcreteAttribute;
790 
791  static PyDenseElementsAttribute
792  getFromList(const nb::list &attributes, std::optional<PyType> explicitType,
793  DefaultingPyMlirContext contextWrapper) {
794  const size_t numAttributes = nb::len(attributes);
795  if (numAttributes == 0)
796  throw nb::value_error("Attributes list must be non-empty.");
797 
798  MlirType shapedType;
799  if (explicitType) {
800  if ((!mlirTypeIsAShaped(*explicitType) ||
801  !mlirShapedTypeHasStaticShape(*explicitType))) {
802 
803  std::string message;
804  llvm::raw_string_ostream os(message);
805  os << "Expected a static ShapedType for the shaped_type parameter: "
806  << nb::cast<std::string>(nb::repr(nb::cast(*explicitType)));
807  throw nb::value_error(message.c_str());
808  }
809  shapedType = *explicitType;
810  } else {
811  SmallVector<int64_t> shape = {static_cast<int64_t>(numAttributes)};
812  shapedType = mlirRankedTensorTypeGet(
813  shape.size(), shape.data(),
814  mlirAttributeGetType(pyTryCast<PyAttribute>(attributes[0])),
816  }
817 
818  SmallVector<MlirAttribute> mlirAttributes;
819  mlirAttributes.reserve(numAttributes);
820  for (const nb::handle &attribute : attributes) {
821  MlirAttribute mlirAttribute = pyTryCast<PyAttribute>(attribute);
822  MlirType attrType = mlirAttributeGetType(mlirAttribute);
823  mlirAttributes.push_back(mlirAttribute);
824 
825  if (!mlirTypeEqual(mlirShapedTypeGetElementType(shapedType), attrType)) {
826  std::string message;
827  llvm::raw_string_ostream os(message);
828  os << "All attributes must be of the same type and match "
829  << "the type parameter: expected="
830  << nb::cast<std::string>(nb::repr(nb::cast(shapedType)))
831  << ", but got="
832  << nb::cast<std::string>(nb::repr(nb::cast(attrType)));
833  throw nb::value_error(message.c_str());
834  }
835  }
836 
837  MlirAttribute elements = mlirDenseElementsAttrGet(
838  shapedType, mlirAttributes.size(), mlirAttributes.data());
839 
840  return PyDenseElementsAttribute(contextWrapper->getRef(), elements);
841  }
842 
843  static PyDenseElementsAttribute
844  getFromBuffer(const nb_buffer &array, bool signless,
845  const std::optional<PyType> &explicitType,
846  std::optional<std::vector<int64_t>> explicitShape,
847  DefaultingPyMlirContext contextWrapper) {
848  // Request a contiguous view. In exotic cases, this will cause a copy.
849  int flags = PyBUF_ND;
850  if (!explicitType) {
851  flags |= PyBUF_FORMAT;
852  }
853  Py_buffer view;
854  if (PyObject_GetBuffer(array.ptr(), &view, flags) != 0) {
855  throw nb::python_error();
856  }
857  auto freeBuffer = llvm::make_scope_exit([&]() { PyBuffer_Release(&view); });
858 
859  MlirContext context = contextWrapper->get();
860  MlirAttribute attr = getAttributeFromBuffer(
861  view, signless, explicitType, std::move(explicitShape), context);
862  if (mlirAttributeIsNull(attr)) {
863  throw std::invalid_argument(
864  "DenseElementsAttr could not be constructed from the given buffer. "
865  "This may mean that the Python buffer layout does not match that "
866  "MLIR expected layout and is a bug.");
867  }
868  return PyDenseElementsAttribute(contextWrapper->getRef(), attr);
869  }
870 
871  static PyDenseElementsAttribute getSplat(const PyType &shapedType,
872  PyAttribute &elementAttr) {
873  auto contextWrapper =
874  PyMlirContext::forContext(mlirTypeGetContext(shapedType));
875  if (!mlirAttributeIsAInteger(elementAttr) &&
876  !mlirAttributeIsAFloat(elementAttr)) {
877  std::string message = "Illegal element type for DenseElementsAttr: ";
878  message.append(nb::cast<std::string>(nb::repr(nb::cast(elementAttr))));
879  throw nb::value_error(message.c_str());
880  }
881  if (!mlirTypeIsAShaped(shapedType) ||
882  !mlirShapedTypeHasStaticShape(shapedType)) {
883  std::string message =
884  "Expected a static ShapedType for the shaped_type parameter: ";
885  message.append(nb::cast<std::string>(nb::repr(nb::cast(shapedType))));
886  throw nb::value_error(message.c_str());
887  }
888  MlirType shapedElementType = mlirShapedTypeGetElementType(shapedType);
889  MlirType attrType = mlirAttributeGetType(elementAttr);
890  if (!mlirTypeEqual(shapedElementType, attrType)) {
891  std::string message =
892  "Shaped element type and attribute type must be equal: shaped=";
893  message.append(nb::cast<std::string>(nb::repr(nb::cast(shapedType))));
894  message.append(", element=");
895  message.append(nb::cast<std::string>(nb::repr(nb::cast(elementAttr))));
896  throw nb::value_error(message.c_str());
897  }
898 
899  MlirAttribute elements =
900  mlirDenseElementsAttrSplatGet(shapedType, elementAttr);
901  return PyDenseElementsAttribute(contextWrapper->getRef(), elements);
902  }
903 
904  intptr_t dunderLen() { return mlirElementsAttrGetNumElements(*this); }
905 
906  std::unique_ptr<nb_buffer_info> accessBuffer() {
907  MlirType shapedType = mlirAttributeGetType(*this);
908  MlirType elementType = mlirShapedTypeGetElementType(shapedType);
909  std::string format;
910 
911  if (mlirTypeIsAF32(elementType)) {
912  // f32
913  return bufferInfo<float>(shapedType);
914  }
915  if (mlirTypeIsAF64(elementType)) {
916  // f64
917  return bufferInfo<double>(shapedType);
918  }
919  if (mlirTypeIsAF16(elementType)) {
920  // f16
921  return bufferInfo<uint16_t>(shapedType, "e");
922  }
923  if (mlirTypeIsAIndex(elementType)) {
924  // Same as IndexType::kInternalStorageBitWidth
925  return bufferInfo<int64_t>(shapedType);
926  }
927  if (mlirTypeIsAInteger(elementType) &&
928  mlirIntegerTypeGetWidth(elementType) == 32) {
929  if (mlirIntegerTypeIsSignless(elementType) ||
930  mlirIntegerTypeIsSigned(elementType)) {
931  // i32
932  return bufferInfo<int32_t>(shapedType);
933  }
934  if (mlirIntegerTypeIsUnsigned(elementType)) {
935  // unsigned i32
936  return bufferInfo<uint32_t>(shapedType);
937  }
938  } else if (mlirTypeIsAInteger(elementType) &&
939  mlirIntegerTypeGetWidth(elementType) == 64) {
940  if (mlirIntegerTypeIsSignless(elementType) ||
941  mlirIntegerTypeIsSigned(elementType)) {
942  // i64
943  return bufferInfo<int64_t>(shapedType);
944  }
945  if (mlirIntegerTypeIsUnsigned(elementType)) {
946  // unsigned i64
947  return bufferInfo<uint64_t>(shapedType);
948  }
949  } else if (mlirTypeIsAInteger(elementType) &&
950  mlirIntegerTypeGetWidth(elementType) == 8) {
951  if (mlirIntegerTypeIsSignless(elementType) ||
952  mlirIntegerTypeIsSigned(elementType)) {
953  // i8
954  return bufferInfo<int8_t>(shapedType);
955  }
956  if (mlirIntegerTypeIsUnsigned(elementType)) {
957  // unsigned i8
958  return bufferInfo<uint8_t>(shapedType);
959  }
960  } else if (mlirTypeIsAInteger(elementType) &&
961  mlirIntegerTypeGetWidth(elementType) == 16) {
962  if (mlirIntegerTypeIsSignless(elementType) ||
963  mlirIntegerTypeIsSigned(elementType)) {
964  // i16
965  return bufferInfo<int16_t>(shapedType);
966  }
967  if (mlirIntegerTypeIsUnsigned(elementType)) {
968  // unsigned i16
969  return bufferInfo<uint16_t>(shapedType);
970  }
971  } else if (mlirTypeIsAInteger(elementType) &&
972  mlirIntegerTypeGetWidth(elementType) == 1) {
973  // i1 / bool
974  // We can not send the buffer directly back to Python, because the i1
975  // values are bitpacked within MLIR. We call numpy's unpackbits function
976  // to convert the bytes.
977  return getBooleanBufferFromBitpackedAttribute();
978  }
979 
980  // TODO: Currently crashes the program.
981  // Reported as https://github.com/pybind/pybind11/issues/3336
982  throw std::invalid_argument(
983  "unsupported data type for conversion to Python buffer");
984  }
985 
986  static void bindDerived(ClassTy &c) {
987 #if PY_VERSION_HEX < 0x03090000
988  PyTypeObject *tp = reinterpret_cast<PyTypeObject *>(c.ptr());
989  tp->tp_as_buffer->bf_getbuffer = PyDenseElementsAttribute::bf_getbuffer;
990  tp->tp_as_buffer->bf_releasebuffer =
991  PyDenseElementsAttribute::bf_releasebuffer;
992 #endif
993  c.def("__len__", &PyDenseElementsAttribute::dunderLen)
994  .def_static(
995  "get", PyDenseElementsAttribute::getFromBuffer, nb::arg("array"),
996  nb::arg("signless") = true, nb::arg("type") = nb::none(),
997  nb::arg("shape") = nb::none(), nb::arg("context") = nb::none(),
998  // clang-format off
999  nb::sig("def get(array: typing_extensions.Buffer, signless: bool = True, type: Type | None = None, shape: Sequence[int] | None = None, context: Context | None = None) -> DenseElementsAttr"),
1000  // clang-format on
1002  .def_static("get", PyDenseElementsAttribute::getFromList,
1003  nb::arg("attrs"), nb::arg("type") = nb::none(),
1004  nb::arg("context") = nb::none(),
1006  .def_static("get_splat", PyDenseElementsAttribute::getSplat,
1007  nb::arg("shaped_type"), nb::arg("element_attr"),
1008  "Gets a DenseElementsAttr where all values are the same")
1009  .def_prop_ro("is_splat",
1010  [](PyDenseElementsAttribute &self) -> bool {
1011  return mlirDenseElementsAttrIsSplat(self);
1012  })
1013  .def("get_splat_value", [](PyDenseElementsAttribute &self) {
1014  if (!mlirDenseElementsAttrIsSplat(self))
1015  throw nb::value_error(
1016  "get_splat_value called on a non-splat attribute");
1017  return PyAttribute(self.getContext(),
1019  .maybeDownCast();
1020  });
1021  }
1022 
1023  static PyType_Slot slots[];
1024 
1025 private:
1026  static int bf_getbuffer(PyObject *exporter, Py_buffer *view, int flags);
1027  static void bf_releasebuffer(PyObject *, Py_buffer *buffer);
1028 
1029  static bool isUnsignedIntegerFormat(std::string_view format) {
1030  if (format.empty())
1031  return false;
1032  char code = format[0];
1033  return code == 'I' || code == 'B' || code == 'H' || code == 'L' ||
1034  code == 'Q';
1035  }
1036 
1037  static bool isSignedIntegerFormat(std::string_view format) {
1038  if (format.empty())
1039  return false;
1040  char code = format[0];
1041  return code == 'i' || code == 'b' || code == 'h' || code == 'l' ||
1042  code == 'q';
1043  }
1044 
1045  static MlirType
1046  getShapedType(std::optional<MlirType> bulkLoadElementType,
1047  std::optional<std::vector<int64_t>> explicitShape,
1048  Py_buffer &view) {
1049  SmallVector<int64_t> shape;
1050  if (explicitShape) {
1051  shape.append(explicitShape->begin(), explicitShape->end());
1052  } else {
1053  shape.append(view.shape, view.shape + view.ndim);
1054  }
1055 
1056  if (mlirTypeIsAShaped(*bulkLoadElementType)) {
1057  if (explicitShape) {
1058  throw std::invalid_argument("Shape can only be specified explicitly "
1059  "when the type is not a shaped type.");
1060  }
1061  return *bulkLoadElementType;
1062  }
1063  MlirAttribute encodingAttr = mlirAttributeGetNull();
1064  return mlirRankedTensorTypeGet(shape.size(), shape.data(),
1065  *bulkLoadElementType, encodingAttr);
1066  }
1067 
1068  static MlirAttribute getAttributeFromBuffer(
1069  Py_buffer &view, bool signless, std::optional<PyType> explicitType,
1070  const std::optional<std::vector<int64_t>> &explicitShape,
1071  MlirContext &context) {
1072  // Detect format codes that are suitable for bulk loading. This includes
1073  // all byte aligned integer and floating point types up to 8 bytes.
1074  // Notably, this excludes exotics types which do not have a direct
1075  // representation in the buffer protocol (i.e. complex, etc).
1076  std::optional<MlirType> bulkLoadElementType;
1077  if (explicitType) {
1078  bulkLoadElementType = *explicitType;
1079  } else {
1080  std::string_view format(view.format);
1081  if (format == "f") {
1082  // f32
1083  assert(view.itemsize == 4 && "mismatched array itemsize");
1084  bulkLoadElementType = mlirF32TypeGet(context);
1085  } else if (format == "d") {
1086  // f64
1087  assert(view.itemsize == 8 && "mismatched array itemsize");
1088  bulkLoadElementType = mlirF64TypeGet(context);
1089  } else if (format == "e") {
1090  // f16
1091  assert(view.itemsize == 2 && "mismatched array itemsize");
1092  bulkLoadElementType = mlirF16TypeGet(context);
1093  } else if (format == "?") {
1094  // i1
1095  // The i1 type needs to be bit-packed, so we will handle it separately
1096  return getBitpackedAttributeFromBooleanBuffer(view, explicitShape,
1097  context);
1098  } else if (isSignedIntegerFormat(format)) {
1099  if (view.itemsize == 4) {
1100  // i32
1101  bulkLoadElementType = signless
1102  ? mlirIntegerTypeGet(context, 32)
1103  : mlirIntegerTypeSignedGet(context, 32);
1104  } else if (view.itemsize == 8) {
1105  // i64
1106  bulkLoadElementType = signless
1107  ? mlirIntegerTypeGet(context, 64)
1108  : mlirIntegerTypeSignedGet(context, 64);
1109  } else if (view.itemsize == 1) {
1110  // i8
1111  bulkLoadElementType = signless ? mlirIntegerTypeGet(context, 8)
1112  : mlirIntegerTypeSignedGet(context, 8);
1113  } else if (view.itemsize == 2) {
1114  // i16
1115  bulkLoadElementType = signless
1116  ? mlirIntegerTypeGet(context, 16)
1117  : mlirIntegerTypeSignedGet(context, 16);
1118  }
1119  } else if (isUnsignedIntegerFormat(format)) {
1120  if (view.itemsize == 4) {
1121  // unsigned i32
1122  bulkLoadElementType = signless
1123  ? mlirIntegerTypeGet(context, 32)
1124  : mlirIntegerTypeUnsignedGet(context, 32);
1125  } else if (view.itemsize == 8) {
1126  // unsigned i64
1127  bulkLoadElementType = signless
1128  ? mlirIntegerTypeGet(context, 64)
1129  : mlirIntegerTypeUnsignedGet(context, 64);
1130  } else if (view.itemsize == 1) {
1131  // i8
1132  bulkLoadElementType = signless
1133  ? mlirIntegerTypeGet(context, 8)
1134  : mlirIntegerTypeUnsignedGet(context, 8);
1135  } else if (view.itemsize == 2) {
1136  // i16
1137  bulkLoadElementType = signless
1138  ? mlirIntegerTypeGet(context, 16)
1139  : mlirIntegerTypeUnsignedGet(context, 16);
1140  }
1141  }
1142  if (!bulkLoadElementType) {
1143  throw std::invalid_argument(
1144  std::string("unimplemented array format conversion from format: ") +
1145  std::string(format));
1146  }
1147  }
1148 
1149  MlirType type = getShapedType(bulkLoadElementType, explicitShape, view);
1150  return mlirDenseElementsAttrRawBufferGet(type, view.len, view.buf);
1151  }
1152 
1153  // There is a complication for boolean numpy arrays, as numpy represents
1154  // them as 8 bits (1 byte) per boolean, whereas MLIR bitpacks them into 8
1155  // booleans per byte.
1156  static MlirAttribute getBitpackedAttributeFromBooleanBuffer(
1157  Py_buffer &view, std::optional<std::vector<int64_t>> explicitShape,
1158  MlirContext &context) {
1159  if (llvm::endianness::native != llvm::endianness::little) {
1160  // Given we have no good way of testing the behavior on big-endian
1161  // systems we will throw
1162  throw nb::type_error("Constructing a bit-packed MLIR attribute is "
1163  "unsupported on big-endian systems");
1164  }
1165  nb::ndarray<uint8_t, nb::numpy, nb::ndim<1>, nb::c_contig> unpackedArray(
1166  /*data=*/static_cast<uint8_t *>(view.buf),
1167  /*shape=*/{static_cast<size_t>(view.len)});
1168 
1169  nb::module_ numpy = nb::module_::import_("numpy");
1170  nb::object packbitsFunc = numpy.attr("packbits");
1171  nb::object packedBooleans =
1172  packbitsFunc(nb::cast(unpackedArray), "bitorder"_a = "little");
1173  nb_buffer_info pythonBuffer = nb::cast<nb_buffer>(packedBooleans).request();
1174 
1175  MlirType bitpackedType = getShapedType(mlirIntegerTypeGet(context, 1),
1176  std::move(explicitShape), view);
1177  assert(pythonBuffer.itemsize == 1 && "Packbits must return uint8");
1178  // Notice that `mlirDenseElementsAttrRawBufferGet` copies the memory of
1179  // packedBooleans, hence the MlirAttribute will remain valid even when
1180  // packedBooleans get reclaimed by the end of the function.
1181  return mlirDenseElementsAttrRawBufferGet(bitpackedType, pythonBuffer.size,
1182  pythonBuffer.ptr);
1183  }
1184 
1185  // This does the opposite transformation of
1186  // `getBitpackedAttributeFromBooleanBuffer`
1187  std::unique_ptr<nb_buffer_info> getBooleanBufferFromBitpackedAttribute() {
1188  if (llvm::endianness::native != llvm::endianness::little) {
1189  // Given we have no good way of testing the behavior on big-endian
1190  // systems we will throw
1191  throw nb::type_error("Constructing a numpy array from a MLIR attribute "
1192  "is unsupported on big-endian systems");
1193  }
1194 
1195  int64_t numBooleans = mlirElementsAttrGetNumElements(*this);
1196  int64_t numBitpackedBytes = llvm::divideCeil(numBooleans, 8);
1197  uint8_t *bitpackedData = static_cast<uint8_t *>(
1198  const_cast<void *>(mlirDenseElementsAttrGetRawData(*this)));
1199  nb::ndarray<uint8_t, nb::numpy, nb::ndim<1>, nb::c_contig> packedArray(
1200  /*data=*/bitpackedData,
1201  /*shape=*/{static_cast<size_t>(numBitpackedBytes)});
1202 
1203  nb::module_ numpy = nb::module_::import_("numpy");
1204  nb::object unpackbitsFunc = numpy.attr("unpackbits");
1205  nb::object equalFunc = numpy.attr("equal");
1206  nb::object reshapeFunc = numpy.attr("reshape");
1207  nb::object unpackedBooleans =
1208  unpackbitsFunc(nb::cast(packedArray), "bitorder"_a = "little");
1209 
1210  // Unpackbits operates on bytes and gives back a flat 0 / 1 integer array.
1211  // We need to:
1212  // 1. Slice away the padded bits
1213  // 2. Make the boolean array have the correct shape
1214  // 3. Convert the array to a boolean array
1215  unpackedBooleans = unpackedBooleans[nb::slice(
1216  nb::int_(0), nb::int_(numBooleans), nb::int_(1))];
1217  unpackedBooleans = equalFunc(unpackedBooleans, 1);
1218 
1219  MlirType shapedType = mlirAttributeGetType(*this);
1220  intptr_t rank = mlirShapedTypeGetRank(shapedType);
1221  std::vector<intptr_t> shape(rank);
1222  for (intptr_t i = 0; i < rank; ++i) {
1223  shape[i] = mlirShapedTypeGetDimSize(shapedType, i);
1224  }
1225  unpackedBooleans = reshapeFunc(unpackedBooleans, shape);
1226 
1227  // Make sure the returned nb::buffer_view claims ownership of the data in
1228  // `pythonBuffer` so it remains valid when Python reads it
1229  nb_buffer pythonBuffer = nb::cast<nb_buffer>(unpackedBooleans);
1230  return std::make_unique<nb_buffer_info>(pythonBuffer.request());
1231  }
1232 
1233  template <typename Type>
1234  std::unique_ptr<nb_buffer_info>
1235  bufferInfo(MlirType shapedType, const char *explicitFormat = nullptr) {
1236  intptr_t rank = mlirShapedTypeGetRank(shapedType);
1237  // Prepare the data for the buffer_info.
1238  // Buffer is configured for read-only access below.
1239  Type *data = static_cast<Type *>(
1240  const_cast<void *>(mlirDenseElementsAttrGetRawData(*this)));
1241  // Prepare the shape for the buffer_info.
1243  for (intptr_t i = 0; i < rank; ++i)
1244  shape.push_back(mlirShapedTypeGetDimSize(shapedType, i));
1245  // Prepare the strides for the buffer_info.
1246  SmallVector<intptr_t, 4> strides;
1247  if (mlirDenseElementsAttrIsSplat(*this)) {
1248  // Splats are special, only the single value is stored.
1249  strides.assign(rank, 0);
1250  } else {
1251  for (intptr_t i = 1; i < rank; ++i) {
1252  intptr_t strideFactor = 1;
1253  for (intptr_t j = i; j < rank; ++j)
1254  strideFactor *= mlirShapedTypeGetDimSize(shapedType, j);
1255  strides.push_back(sizeof(Type) * strideFactor);
1256  }
1257  strides.push_back(sizeof(Type));
1258  }
1259  const char *format;
1260  if (explicitFormat) {
1261  format = explicitFormat;
1262  } else {
1263  format = nb_format_descriptor<Type>::format();
1264  }
1265  return std::make_unique<nb_buffer_info>(
1266  data, sizeof(Type), format, rank, std::move(shape), std::move(strides),
1267  /*readonly=*/true);
1268  }
1269 }; // namespace
1270 
1271 PyType_Slot PyDenseElementsAttribute::slots[] = {
1272 // Python 3.8 doesn't allow setting the buffer protocol slots from a type spec.
1273 #if PY_VERSION_HEX >= 0x03090000
1274  {Py_bf_getbuffer,
1275  reinterpret_cast<void *>(PyDenseElementsAttribute::bf_getbuffer)},
1276  {Py_bf_releasebuffer,
1277  reinterpret_cast<void *>(PyDenseElementsAttribute::bf_releasebuffer)},
1278 #endif
1279  {0, nullptr},
1280 };
1281 
1282 /*static*/ int PyDenseElementsAttribute::bf_getbuffer(PyObject *obj,
1283  Py_buffer *view,
1284  int flags) {
1285  view->obj = nullptr;
1286  std::unique_ptr<nb_buffer_info> info;
1287  try {
1288  auto *attr = nb::cast<PyDenseElementsAttribute *>(nb::handle(obj));
1289  info = attr->accessBuffer();
1290  } catch (nb::python_error &e) {
1291  e.restore();
1292  nb::chain_error(PyExc_BufferError, "Error converting attribute to buffer");
1293  return -1;
1294  }
1295  view->obj = obj;
1296  view->ndim = 1;
1297  view->buf = info->ptr;
1298  view->itemsize = info->itemsize;
1299  view->len = info->itemsize;
1300  for (auto s : info->shape) {
1301  view->len *= s;
1302  }
1303  view->readonly = info->readonly;
1304  if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
1305  view->format = const_cast<char *>(info->format);
1306  }
1307  if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
1308  view->ndim = static_cast<int>(info->ndim);
1309  view->strides = info->strides.data();
1310  view->shape = info->shape.data();
1311  }
1312  view->suboffsets = nullptr;
1313  view->internal = info.release();
1314  Py_INCREF(obj);
1315  return 0;
1316 }
1317 
1318 /*static*/ void PyDenseElementsAttribute::bf_releasebuffer(PyObject *,
1319  Py_buffer *view) {
1320  delete reinterpret_cast<nb_buffer_info *>(view->internal);
1321 }
1322 
1323 /// Refinement of the PyDenseElementsAttribute for attributes containing
1324 /// integer (and boolean) values. Supports element access.
1325 class PyDenseIntElementsAttribute
1326  : public PyConcreteAttribute<PyDenseIntElementsAttribute,
1327  PyDenseElementsAttribute> {
1328 public:
1329  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsADenseIntElements;
1330  static constexpr const char *pyClassName = "DenseIntElementsAttr";
1331  using PyConcreteAttribute::PyConcreteAttribute;
1332 
1333  /// Returns the element at the given linear position. Asserts if the index
1334  /// is out of range.
1335  nb::object dunderGetItem(intptr_t pos) {
1336  if (pos < 0 || pos >= dunderLen()) {
1337  throw nb::index_error("attempt to access out of bounds element");
1338  }
1339 
1340  MlirType type = mlirAttributeGetType(*this);
1341  type = mlirShapedTypeGetElementType(type);
1342  // Index type can also appear as a DenseIntElementsAttr and therefore can be
1343  // casted to integer.
1344  assert(mlirTypeIsAInteger(type) ||
1345  mlirTypeIsAIndex(type) && "expected integer/index element type in "
1346  "dense int elements attribute");
1347  // Dispatch element extraction to an appropriate C function based on the
1348  // elemental type of the attribute. nb::int_ is implicitly constructible
1349  // from any C++ integral type and handles bitwidth correctly.
1350  // TODO: consider caching the type properties in the constructor to avoid
1351  // querying them on each element access.
1352  if (mlirTypeIsAIndex(type)) {
1353  return nb::int_(mlirDenseElementsAttrGetIndexValue(*this, pos));
1354  }
1355  unsigned width = mlirIntegerTypeGetWidth(type);
1356  bool isUnsigned = mlirIntegerTypeIsUnsigned(type);
1357  if (isUnsigned) {
1358  if (width == 1) {
1359  return nb::int_(int(mlirDenseElementsAttrGetBoolValue(*this, pos)));
1360  }
1361  if (width == 8) {
1362  return nb::int_(mlirDenseElementsAttrGetUInt8Value(*this, pos));
1363  }
1364  if (width == 16) {
1365  return nb::int_(mlirDenseElementsAttrGetUInt16Value(*this, pos));
1366  }
1367  if (width == 32) {
1368  return nb::int_(mlirDenseElementsAttrGetUInt32Value(*this, pos));
1369  }
1370  if (width == 64) {
1371  return nb::int_(mlirDenseElementsAttrGetUInt64Value(*this, pos));
1372  }
1373  } else {
1374  if (width == 1) {
1375  return nb::int_(int(mlirDenseElementsAttrGetBoolValue(*this, pos)));
1376  }
1377  if (width == 8) {
1378  return nb::int_(mlirDenseElementsAttrGetInt8Value(*this, pos));
1379  }
1380  if (width == 16) {
1381  return nb::int_(mlirDenseElementsAttrGetInt16Value(*this, pos));
1382  }
1383  if (width == 32) {
1384  return nb::int_(mlirDenseElementsAttrGetInt32Value(*this, pos));
1385  }
1386  if (width == 64) {
1387  return nb::int_(mlirDenseElementsAttrGetInt64Value(*this, pos));
1388  }
1389  }
1390  throw nb::type_error("Unsupported integer type");
1391  }
1392 
1393  static void bindDerived(ClassTy &c) {
1394  c.def("__getitem__", &PyDenseIntElementsAttribute::dunderGetItem);
1395  }
1396 };
1397 
1398 // Check if the python version is less than 3.13. Py_IsFinalizing is a part
1399 // of stable ABI since 3.13 and before it was available as _Py_IsFinalizing.
1400 #if PY_VERSION_HEX < 0x030d0000
1401 #define Py_IsFinalizing _Py_IsFinalizing
1402 #endif
1403 
1404 class PyDenseResourceElementsAttribute
1405  : public PyConcreteAttribute<PyDenseResourceElementsAttribute> {
1406 public:
1407  static constexpr IsAFunctionTy isaFunction =
1409  static constexpr const char *pyClassName = "DenseResourceElementsAttr";
1410  using PyConcreteAttribute::PyConcreteAttribute;
1411 
1412  static PyDenseResourceElementsAttribute
1413  getFromBuffer(const nb_buffer &buffer, const std::string &name,
1414  const PyType &type, std::optional<size_t> alignment,
1415  bool isMutable, DefaultingPyMlirContext contextWrapper) {
1416  if (!mlirTypeIsAShaped(type)) {
1417  throw std::invalid_argument(
1418  "Constructing a DenseResourceElementsAttr requires a ShapedType.");
1419  }
1420 
1421  // Do not request any conversions as we must ensure to use caller
1422  // managed memory.
1423  int flags = PyBUF_STRIDES;
1424  std::unique_ptr<Py_buffer> view = std::make_unique<Py_buffer>();
1425  if (PyObject_GetBuffer(buffer.ptr(), view.get(), flags) != 0) {
1426  throw nb::python_error();
1427  }
1428 
1429  // This scope releaser will only release if we haven't yet transferred
1430  // ownership.
1431  auto freeBuffer = llvm::make_scope_exit([&]() {
1432  if (view)
1433  PyBuffer_Release(view.get());
1434  });
1435 
1436  if (!PyBuffer_IsContiguous(view.get(), 'A')) {
1437  throw std::invalid_argument("Contiguous buffer is required.");
1438  }
1439 
1440  // Infer alignment to be the stride of one element if not explicit.
1441  size_t inferredAlignment;
1442  if (alignment)
1443  inferredAlignment = *alignment;
1444  else
1445  inferredAlignment = view->strides[view->ndim - 1];
1446 
1447  // The userData is a Py_buffer* that the deleter owns.
1448  auto deleter = [](void *userData, const void *data, size_t size,
1449  size_t align) {
1450  if (Py_IsFinalizing())
1451  return;
1452  assert(Py_IsInitialized() && "expected interpreter to be initialized");
1453  Py_buffer *ownedView = static_cast<Py_buffer *>(userData);
1454  nb::gil_scoped_acquire gil;
1455  PyBuffer_Release(ownedView);
1456  delete ownedView;
1457  };
1458 
1459  size_t rawBufferSize = view->len;
1460  MlirAttribute attr = mlirUnmanagedDenseResourceElementsAttrGet(
1461  type, toMlirStringRef(name), view->buf, rawBufferSize,
1462  inferredAlignment, isMutable, deleter, static_cast<void *>(view.get()));
1463  if (mlirAttributeIsNull(attr)) {
1464  throw std::invalid_argument(
1465  "DenseResourceElementsAttr could not be constructed from the given "
1466  "buffer. "
1467  "This may mean that the Python buffer layout does not match that "
1468  "MLIR expected layout and is a bug.");
1469  }
1470  view.release();
1471  return PyDenseResourceElementsAttribute(contextWrapper->getRef(), attr);
1472  }
1473 
1474  static void bindDerived(ClassTy &c) {
1475  c.def_static("get_from_buffer",
1476  PyDenseResourceElementsAttribute::getFromBuffer,
1477  nb::arg("array"), nb::arg("name"), nb::arg("type"),
1478  nb::arg("alignment") = nb::none(),
1479  nb::arg("is_mutable") = false, nb::arg("context") = nb::none(),
1480  // clang-format off
1481  nb::sig("def get_from_buffer(array: typing_extensions.Buffer, name: str, type: Type, alignment: int | None = None, is_mutable: bool = False, context: Context | None = None) -> DenseResourceElementsAttr"),
1482  // clang-format on
1484  }
1485 };
1486 
1487 class PyDictAttribute : public PyConcreteAttribute<PyDictAttribute> {
1488 public:
1489  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsADictionary;
1490  static constexpr const char *pyClassName = "DictAttr";
1491  using PyConcreteAttribute::PyConcreteAttribute;
1492  static constexpr GetTypeIDFunctionTy getTypeIdFunction =
1494 
1495  intptr_t dunderLen() { return mlirDictionaryAttrGetNumElements(*this); }
1496 
1497  bool dunderContains(const std::string &name) {
1498  return !mlirAttributeIsNull(
1500  }
1501 
1502  static void bindDerived(ClassTy &c) {
1503  c.def("__contains__", &PyDictAttribute::dunderContains);
1504  c.def("__len__", &PyDictAttribute::dunderLen);
1505  c.def_static(
1506  "get",
1507  [](const nb::dict &attributes, DefaultingPyMlirContext context) {
1508  SmallVector<MlirNamedAttribute> mlirNamedAttributes;
1509  mlirNamedAttributes.reserve(attributes.size());
1510  for (std::pair<nb::handle, nb::handle> it : attributes) {
1511  auto &mlirAttr = nb::cast<PyAttribute &>(it.second);
1512  auto name = nb::cast<std::string>(it.first);
1513  mlirNamedAttributes.push_back(mlirNamedAttributeGet(
1515  toMlirStringRef(name)),
1516  mlirAttr));
1517  }
1518  MlirAttribute attr =
1519  mlirDictionaryAttrGet(context->get(), mlirNamedAttributes.size(),
1520  mlirNamedAttributes.data());
1521  return PyDictAttribute(context->getRef(), attr);
1522  },
1523  nb::arg("value") = nb::dict(), nb::arg("context") = nb::none(),
1524  "Gets an uniqued dict attribute");
1525  c.def("__getitem__", [](PyDictAttribute &self, const std::string &name) {
1526  MlirAttribute attr =
1528  if (mlirAttributeIsNull(attr))
1529  throw nb::key_error("attempt to access a non-existent attribute");
1530  return PyAttribute(self.getContext(), attr).maybeDownCast();
1531  });
1532  c.def("__getitem__", [](PyDictAttribute &self, intptr_t index) {
1533  if (index < 0 || index >= self.dunderLen()) {
1534  throw nb::index_error("attempt to access out of bounds attribute");
1535  }
1536  MlirNamedAttribute namedAttr = mlirDictionaryAttrGetElement(self, index);
1537  return PyNamedAttribute(
1538  namedAttr.attribute,
1539  std::string(mlirIdentifierStr(namedAttr.name).data));
1540  });
1541  }
1542 };
1543 
1544 /// Refinement of PyDenseElementsAttribute for attributes containing
1545 /// floating-point values. Supports element access.
1546 class PyDenseFPElementsAttribute
1547  : public PyConcreteAttribute<PyDenseFPElementsAttribute,
1548  PyDenseElementsAttribute> {
1549 public:
1550  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsADenseFPElements;
1551  static constexpr const char *pyClassName = "DenseFPElementsAttr";
1552  using PyConcreteAttribute::PyConcreteAttribute;
1553 
1554  nb::float_ dunderGetItem(intptr_t pos) {
1555  if (pos < 0 || pos >= dunderLen()) {
1556  throw nb::index_error("attempt to access out of bounds element");
1557  }
1558 
1559  MlirType type = mlirAttributeGetType(*this);
1560  type = mlirShapedTypeGetElementType(type);
1561  // Dispatch element extraction to an appropriate C function based on the
1562  // elemental type of the attribute. nb::float_ is implicitly constructible
1563  // from float and double.
1564  // TODO: consider caching the type properties in the constructor to avoid
1565  // querying them on each element access.
1566  if (mlirTypeIsAF32(type)) {
1567  return nb::float_(mlirDenseElementsAttrGetFloatValue(*this, pos));
1568  }
1569  if (mlirTypeIsAF64(type)) {
1570  return nb::float_(mlirDenseElementsAttrGetDoubleValue(*this, pos));
1571  }
1572  throw nb::type_error("Unsupported floating-point type");
1573  }
1574 
1575  static void bindDerived(ClassTy &c) {
1576  c.def("__getitem__", &PyDenseFPElementsAttribute::dunderGetItem);
1577  }
1578 };
1579 
1580 class PyTypeAttribute : public PyConcreteAttribute<PyTypeAttribute> {
1581 public:
1582  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsAType;
1583  static constexpr const char *pyClassName = "TypeAttr";
1584  using PyConcreteAttribute::PyConcreteAttribute;
1585  static constexpr GetTypeIDFunctionTy getTypeIdFunction =
1587 
1588  static void bindDerived(ClassTy &c) {
1589  c.def_static(
1590  "get",
1591  [](const PyType &value, DefaultingPyMlirContext context) {
1592  MlirAttribute attr = mlirTypeAttrGet(value.get());
1593  return PyTypeAttribute(context->getRef(), attr);
1594  },
1595  nb::arg("value"), nb::arg("context") = nb::none(),
1596  "Gets a uniqued Type attribute");
1597  c.def_prop_ro("value", [](PyTypeAttribute &self) {
1598  return PyType(self.getContext(), mlirTypeAttrGetValue(self.get()))
1599  .maybeDownCast();
1600  });
1601  }
1602 };
1603 
1604 /// Unit Attribute subclass. Unit attributes don't have values.
1605 class PyUnitAttribute : public PyConcreteAttribute<PyUnitAttribute> {
1606 public:
1607  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsAUnit;
1608  static constexpr const char *pyClassName = "UnitAttr";
1609  using PyConcreteAttribute::PyConcreteAttribute;
1610  static constexpr GetTypeIDFunctionTy getTypeIdFunction =
1612 
1613  static void bindDerived(ClassTy &c) {
1614  c.def_static(
1615  "get",
1616  [](DefaultingPyMlirContext context) {
1617  return PyUnitAttribute(context->getRef(),
1618  mlirUnitAttrGet(context->get()));
1619  },
1620  nb::arg("context") = nb::none(), "Create a Unit attribute.");
1621  }
1622 };
1623 
1624 /// Strided layout attribute subclass.
1625 class PyStridedLayoutAttribute
1626  : public PyConcreteAttribute<PyStridedLayoutAttribute> {
1627 public:
1628  static constexpr IsAFunctionTy isaFunction = mlirAttributeIsAStridedLayout;
1629  static constexpr const char *pyClassName = "StridedLayoutAttr";
1630  using PyConcreteAttribute::PyConcreteAttribute;
1631  static constexpr GetTypeIDFunctionTy getTypeIdFunction =
1633 
1634  static void bindDerived(ClassTy &c) {
1635  c.def_static(
1636  "get",
1637  [](int64_t offset, const std::vector<int64_t> &strides,
1639  MlirAttribute attr = mlirStridedLayoutAttrGet(
1640  ctx->get(), offset, strides.size(), strides.data());
1641  return PyStridedLayoutAttribute(ctx->getRef(), attr);
1642  },
1643  nb::arg("offset"), nb::arg("strides"), nb::arg("context") = nb::none(),
1644  "Gets a strided layout attribute.");
1645  c.def_static(
1646  "get_fully_dynamic",
1647  [](int64_t rank, DefaultingPyMlirContext ctx) {
1648  auto dynamic = mlirShapedTypeGetDynamicStrideOrOffset();
1649  std::vector<int64_t> strides(rank);
1650  llvm::fill(strides, dynamic);
1651  MlirAttribute attr = mlirStridedLayoutAttrGet(
1652  ctx->get(), dynamic, strides.size(), strides.data());
1653  return PyStridedLayoutAttribute(ctx->getRef(), attr);
1654  },
1655  nb::arg("rank"), nb::arg("context") = nb::none(),
1656  "Gets a strided layout attribute with dynamic offset and strides of "
1657  "a "
1658  "given rank.");
1659  c.def_prop_ro(
1660  "offset",
1661  [](PyStridedLayoutAttribute &self) {
1662  return mlirStridedLayoutAttrGetOffset(self);
1663  },
1664  "Returns the value of the float point attribute");
1665  c.def_prop_ro(
1666  "strides",
1667  [](PyStridedLayoutAttribute &self) {
1668  intptr_t size = mlirStridedLayoutAttrGetNumStrides(self);
1669  std::vector<int64_t> strides(size);
1670  for (intptr_t i = 0; i < size; i++) {
1671  strides[i] = mlirStridedLayoutAttrGetStride(self, i);
1672  }
1673  return strides;
1674  },
1675  "Returns the value of the float point attribute");
1676  }
1677 };
1678 
1679 nb::object denseArrayAttributeCaster(PyAttribute &pyAttribute) {
1680  if (PyDenseBoolArrayAttribute::isaFunction(pyAttribute))
1681  return nb::cast(PyDenseBoolArrayAttribute(pyAttribute));
1682  if (PyDenseI8ArrayAttribute::isaFunction(pyAttribute))
1683  return nb::cast(PyDenseI8ArrayAttribute(pyAttribute));
1684  if (PyDenseI16ArrayAttribute::isaFunction(pyAttribute))
1685  return nb::cast(PyDenseI16ArrayAttribute(pyAttribute));
1686  if (PyDenseI32ArrayAttribute::isaFunction(pyAttribute))
1687  return nb::cast(PyDenseI32ArrayAttribute(pyAttribute));
1688  if (PyDenseI64ArrayAttribute::isaFunction(pyAttribute))
1689  return nb::cast(PyDenseI64ArrayAttribute(pyAttribute));
1690  if (PyDenseF32ArrayAttribute::isaFunction(pyAttribute))
1691  return nb::cast(PyDenseF32ArrayAttribute(pyAttribute));
1692  if (PyDenseF64ArrayAttribute::isaFunction(pyAttribute))
1693  return nb::cast(PyDenseF64ArrayAttribute(pyAttribute));
1694  std::string msg =
1695  std::string("Can't cast unknown element type DenseArrayAttr (") +
1696  nb::cast<std::string>(nb::repr(nb::cast(pyAttribute))) + ")";
1697  throw nb::type_error(msg.c_str());
1698 }
1699 
1700 nb::object denseIntOrFPElementsAttributeCaster(PyAttribute &pyAttribute) {
1701  if (PyDenseFPElementsAttribute::isaFunction(pyAttribute))
1702  return nb::cast(PyDenseFPElementsAttribute(pyAttribute));
1703  if (PyDenseIntElementsAttribute::isaFunction(pyAttribute))
1704  return nb::cast(PyDenseIntElementsAttribute(pyAttribute));
1705  std::string msg =
1706  std::string(
1707  "Can't cast unknown element type DenseIntOrFPElementsAttr (") +
1708  nb::cast<std::string>(nb::repr(nb::cast(pyAttribute))) + ")";
1709  throw nb::type_error(msg.c_str());
1710 }
1711 
1712 nb::object integerOrBoolAttributeCaster(PyAttribute &pyAttribute) {
1713  if (PyBoolAttribute::isaFunction(pyAttribute))
1714  return nb::cast(PyBoolAttribute(pyAttribute));
1715  if (PyIntegerAttribute::isaFunction(pyAttribute))
1716  return nb::cast(PyIntegerAttribute(pyAttribute));
1717  std::string msg = std::string("Can't cast unknown attribute type Attr (") +
1718  nb::cast<std::string>(nb::repr(nb::cast(pyAttribute))) +
1719  ")";
1720  throw nb::type_error(msg.c_str());
1721 }
1722 
1723 nb::object symbolRefOrFlatSymbolRefAttributeCaster(PyAttribute &pyAttribute) {
1724  if (PyFlatSymbolRefAttribute::isaFunction(pyAttribute))
1725  return nb::cast(PyFlatSymbolRefAttribute(pyAttribute));
1726  if (PySymbolRefAttribute::isaFunction(pyAttribute))
1727  return nb::cast(PySymbolRefAttribute(pyAttribute));
1728  std::string msg = std::string("Can't cast unknown SymbolRef attribute (") +
1729  nb::cast<std::string>(nb::repr(nb::cast(pyAttribute))) +
1730  ")";
1731  throw nb::type_error(msg.c_str());
1732 }
1733 
1734 } // namespace
1735 
1736 void PyStringAttribute::bindDerived(ClassTy &c) {
1737  c.def_static(
1738  "get",
1739  [](const std::string &value, DefaultingPyMlirContext context) {
1740  MlirAttribute attr =
1741  mlirStringAttrGet(context->get(), toMlirStringRef(value));
1742  return PyStringAttribute(context->getRef(), attr);
1743  },
1744  nb::arg("value"), nb::arg("context") = nb::none(),
1745  "Gets a uniqued string attribute");
1746  c.def_static(
1747  "get",
1748  [](const nb::bytes &value, DefaultingPyMlirContext context) {
1749  MlirAttribute attr =
1750  mlirStringAttrGet(context->get(), toMlirStringRef(value));
1751  return PyStringAttribute(context->getRef(), attr);
1752  },
1753  nb::arg("value"), nb::arg("context") = nb::none(),
1754  "Gets a uniqued string attribute");
1755  c.def_static(
1756  "get_typed",
1757  [](PyType &type, const std::string &value) {
1758  MlirAttribute attr =
1760  return PyStringAttribute(type.getContext(), attr);
1761  },
1762  nb::arg("type"), nb::arg("value"),
1763  "Gets a uniqued string attribute associated to a type");
1764  c.def_prop_ro(
1765  "value",
1766  [](PyStringAttribute &self) {
1767  MlirStringRef stringRef = mlirStringAttrGetValue(self);
1768  return nb::str(stringRef.data, stringRef.length);
1769  },
1770  "Returns the value of the string attribute");
1771  c.def_prop_ro(
1772  "value_bytes",
1773  [](PyStringAttribute &self) {
1774  MlirStringRef stringRef = mlirStringAttrGetValue(self);
1775  return nb::bytes(stringRef.data, stringRef.length);
1776  },
1777  "Returns the value of the string attribute as `bytes`");
1778 }
1779 
1780 void mlir::python::populateIRAttributes(nb::module_ &m) {
1781  PyAffineMapAttribute::bind(m);
1782  PyDenseBoolArrayAttribute::bind(m);
1783  PyDenseBoolArrayAttribute::PyDenseArrayIterator::bind(m);
1784  PyDenseI8ArrayAttribute::bind(m);
1785  PyDenseI8ArrayAttribute::PyDenseArrayIterator::bind(m);
1786  PyDenseI16ArrayAttribute::bind(m);
1787  PyDenseI16ArrayAttribute::PyDenseArrayIterator::bind(m);
1788  PyDenseI32ArrayAttribute::bind(m);
1789  PyDenseI32ArrayAttribute::PyDenseArrayIterator::bind(m);
1790  PyDenseI64ArrayAttribute::bind(m);
1791  PyDenseI64ArrayAttribute::PyDenseArrayIterator::bind(m);
1792  PyDenseF32ArrayAttribute::bind(m);
1793  PyDenseF32ArrayAttribute::PyDenseArrayIterator::bind(m);
1794  PyDenseF64ArrayAttribute::bind(m);
1795  PyDenseF64ArrayAttribute::PyDenseArrayIterator::bind(m);
1796  PyGlobals::get().registerTypeCaster(
1798  nb::cast<nb::callable>(nb::cpp_function(denseArrayAttributeCaster)));
1799 
1800  PyArrayAttribute::bind(m);
1801  PyArrayAttribute::PyArrayAttributeIterator::bind(m);
1802  PyBoolAttribute::bind(m);
1803  PyDenseElementsAttribute::bind(m, PyDenseElementsAttribute::slots);
1804  PyDenseFPElementsAttribute::bind(m);
1805  PyDenseIntElementsAttribute::bind(m);
1806  PyGlobals::get().registerTypeCaster(
1808  nb::cast<nb::callable>(
1809  nb::cpp_function(denseIntOrFPElementsAttributeCaster)));
1810  PyDenseResourceElementsAttribute::bind(m);
1811 
1812  PyDictAttribute::bind(m);
1813  PySymbolRefAttribute::bind(m);
1814  PyGlobals::get().registerTypeCaster(
1816  nb::cast<nb::callable>(
1817  nb::cpp_function(symbolRefOrFlatSymbolRefAttributeCaster)));
1818 
1819  PyFlatSymbolRefAttribute::bind(m);
1820  PyOpaqueAttribute::bind(m);
1821  PyFloatAttribute::bind(m);
1822  PyIntegerAttribute::bind(m);
1823  PyIntegerSetAttribute::bind(m);
1824  PyStringAttribute::bind(m);
1825  PyTypeAttribute::bind(m);
1826  PyGlobals::get().registerTypeCaster(
1828  nb::cast<nb::callable>(nb::cpp_function(integerOrBoolAttributeCaster)));
1829  PyUnitAttribute::bind(m);
1830 
1831  PyStridedLayoutAttribute::bind(m);
1832 }
#define Py_IsFinalizing
static const char kDenseElementsAttrGetDocstring[]
static const char kDenseResourceElementsAttrGetFromBufferDocstring[]
static const char kDenseElementsAttrGetFromListDocstring[]
static MlirStringRef toMlirStringRef(const std::string &s)
Definition: IRCore.cpp:223
static MLIRContext * getContext(OpFoldResult val)
static LogicalResult nextIndex(ArrayRef< int64_t > shape, MutableArrayRef< int64_t > index)
Walks over the indices of the elements of a tensor of a given shape by updating index in place to the...
std::string str() const
Converts the diagnostic to a string.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
PyMlirContextRef & getContext()
Accesses the context reference.
Definition: IRModule.h:293
Used in function arguments when None should resolve to the current context manager set instance.
Definition: IRModule.h:500
Used in function arguments when None should resolve to the current context manager set instance.
Definition: IRModule.h:273
static PyMlirContext & resolve()
Definition: IRCore.cpp:785
ReferrentTy * get() const
Definition: NanobindUtils.h:60
MlirAffineMap get() const
Definition: IRModule.h:1228
Wrapper around the generic MlirAttribute.
Definition: IRModule.h:1008
nanobind::object maybeDownCast()
Definition: IRCore.cpp:2136
MlirAttribute get() const
Definition: IRModule.h:1014
CRTP base classes for Python attributes that subclass Attribute and should be castable from it (i....
Definition: IRModule.h:1060
nanobind::class_< DerivedTy, BaseTy > ClassTy
Definition: IRModule.h:1065
MlirIntegerSet get() const
Definition: IRModule.h:1249
MlirContext get()
Accesses the underlying MlirContext.
Definition: IRModule.h:204
PyMlirContextRef getRef()
Gets a strong reference to this context, which will ensure it is kept alive for the life of the refer...
Definition: IRModule.h:208
Represents a Python MlirNamedAttr, carrying an optional owned name.
Definition: IRModule.h:1034
A TypeID provides an efficient and unique identifier for a specific C++ type.
Definition: IRModule.h:904
Wrapper around the generic MlirType.
Definition: IRModule.h:878
MlirType get() const
Definition: IRModule.h:884
nanobind::object maybeDownCast()
Definition: IRCore.cpp:2182
mlir::Diagnostic & unwrap(MlirDiagnostic diagnostic)
Definition: Diagnostics.h:19
MLIR_CAPI_EXPORTED MlirAttribute mlirAffineMapAttrGet(MlirAffineMap map)
Creates an affine map attribute wrapping the given map.
MLIR_CAPI_EXPORTED bool mlirAttributeIsADenseFPElements(MlirAttribute attr)
MLIR_CAPI_EXPORTED MlirAttribute mlirOpaqueAttrGet(MlirContext ctx, MlirStringRef dialectNamespace, intptr_t dataLength, const char *data, MlirType type)
Creates an opaque attribute in the given context associated with the dialect identified by its namesp...
MLIR_CAPI_EXPORTED MlirAttribute mlirFloatAttrDoubleGetChecked(MlirLocation loc, MlirType type, double value)
Same as "mlirFloatAttrDoubleGet", but if the type is not valid for a construction of a FloatAttr,...
MLIR_CAPI_EXPORTED int16_t mlirDenseI16ArrayGetElement(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED bool mlirAttributeIsAStridedLayout(MlirAttribute attr)
MLIR_CAPI_EXPORTED uint8_t mlirDenseElementsAttrGetUInt8Value(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED int64_t mlirStridedLayoutAttrGetOffset(MlirAttribute attr)
MLIR_CAPI_EXPORTED bool mlirAttributeIsADenseI64Array(MlirAttribute attr)
MLIR_CAPI_EXPORTED MlirAffineMap mlirAffineMapAttrGetValue(MlirAttribute attr)
Returns the affine map wrapped in the given affine map attribute.
MLIR_CAPI_EXPORTED int64_t mlirStridedLayoutAttrGetStride(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED int8_t mlirDenseElementsAttrGetInt8Value(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED MlirAttribute mlirStridedLayoutAttrGet(MlirContext ctx, int64_t offset, intptr_t numStrides, const int64_t *strides)
MLIR_CAPI_EXPORTED bool mlirAttributeIsAUnit(MlirAttribute attr)
Checks whether the given attribute is a unit attribute.
MLIR_CAPI_EXPORTED bool mlirAttributeIsADenseElements(MlirAttribute attr)
Checks whether the given attribute is a dense elements attribute.
MLIR_CAPI_EXPORTED bool mlirAttributeIsAIntegerSet(MlirAttribute attr)
Checks whether the given attribute is an integer set attribute.
MLIR_CAPI_EXPORTED bool mlirAttributeIsAAffineMap(MlirAttribute attr)
Checks whether the given attribute is an affine map attribute.
MLIR_CAPI_EXPORTED int32_t mlirDenseI32ArrayGetElement(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED double mlirDenseF64ArrayGetElement(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED MlirAttribute mlirFlatSymbolRefAttrGet(MlirContext ctx, MlirStringRef symbol)
Creates a flat symbol reference attribute in the given context referencing a symbol identified by the...
MLIR_CAPI_EXPORTED MlirTypeID mlirStridedLayoutAttrGetTypeID(void)
Returns the typeID of a StridedLayout attribute.
MLIR_CAPI_EXPORTED uint64_t mlirDenseElementsAttrGetIndexValue(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED MlirTypeID mlirIntegerAttrGetTypeID(void)
Returns the typeID of an Integer attribute.
MLIR_CAPI_EXPORTED bool mlirAttributeIsADenseResourceElements(MlirAttribute attr)
MLIR_CAPI_EXPORTED int16_t mlirDenseElementsAttrGetInt16Value(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED MlirStringRef mlirSymbolRefAttrGetRootReference(MlirAttribute attr)
Returns the string reference to the root referenced symbol.
MLIR_CAPI_EXPORTED bool mlirAttributeIsAType(MlirAttribute attr)
Checks whether the given attribute is a type attribute.
MLIR_CAPI_EXPORTED MlirTypeID mlirDenseIntOrFPElementsAttrGetTypeID(void)
Returns the typeID of an DenseIntOrFPElements attribute.
MLIR_CAPI_EXPORTED bool mlirAttributeIsADenseIntElements(MlirAttribute attr)
MLIR_CAPI_EXPORTED bool mlirAttributeIsAArray(MlirAttribute attr)
Checks whether the given attribute is an array attribute.
MLIR_CAPI_EXPORTED bool mlirAttributeIsAInteger(MlirAttribute attr)
Checks whether the given attribute is an integer attribute.
MLIR_CAPI_EXPORTED intptr_t mlirDictionaryAttrGetNumElements(MlirAttribute attr)
Returns the number of attributes contained in a dictionary attribute.
MLIR_CAPI_EXPORTED MlirAttribute mlirIntegerSetAttrGet(MlirIntegerSet set)
Creates an integer set attribute wrapping the given set.
MLIR_CAPI_EXPORTED uint16_t mlirDenseElementsAttrGetUInt16Value(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED uint64_t mlirDenseElementsAttrGetUInt64Value(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED bool mlirBoolAttrGetValue(MlirAttribute attr)
Returns the value stored in the given bool attribute.
MLIR_CAPI_EXPORTED int64_t mlirDenseI64ArrayGetElement(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED MlirAttribute mlirIntegerAttrGet(MlirType type, int64_t value)
Creates an integer attribute of the given type with the given integer value.
MLIR_CAPI_EXPORTED MlirTypeID mlirIntegerSetAttrGetTypeID(void)
Returns the typeID of an IntegerSet attribute.
MLIR_CAPI_EXPORTED bool mlirDenseElementsAttrGetBoolValue(MlirAttribute attr, intptr_t pos)
Returns the pos-th value (flat contiguous indexing) of a specific type contained by the given dense e...
MLIR_CAPI_EXPORTED MlirAttribute mlirDictionaryAttrGet(MlirContext ctx, intptr_t numElements, MlirNamedAttribute const *elements)
Creates a dictionary attribute containing the given list of elements in the provided context.
MLIR_CAPI_EXPORTED MlirAttribute mlirUnmanagedDenseResourceElementsAttrGet(MlirType shapedType, MlirStringRef name, void *data, size_t dataLength, size_t dataAlignment, bool dataIsMutable, void(*deleter)(void *userData, const void *data, size_t size, size_t align), void *userData)
Unlike the typed accessors below, constructs the attribute with a raw data buffer and no type/alignme...
MLIR_CAPI_EXPORTED bool mlirAttributeIsABool(MlirAttribute attr)
Checks whether the given attribute is a bool attribute.
MLIR_CAPI_EXPORTED bool mlirDenseBoolArrayGetElement(MlirAttribute attr, intptr_t pos)
Get an element of a dense array.
MLIR_CAPI_EXPORTED MlirAttribute mlirDenseI64ArrayGet(MlirContext ctx, intptr_t size, int64_t const *values)
MLIR_CAPI_EXPORTED MlirTypeID mlirAffineMapAttrGetTypeID(void)
Returns the typeID of an AffineMap attribute.
MLIR_CAPI_EXPORTED MlirAttribute mlirSymbolRefAttrGetNestedReference(MlirAttribute attr, intptr_t pos)
Returns pos-th reference nested in the given symbol reference attribute.
MLIR_CAPI_EXPORTED MlirTypeID mlirArrayAttrGetTypeID(void)
Returns the typeID of an Array attribute.
MLIR_CAPI_EXPORTED float mlirDenseF32ArrayGetElement(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED MlirAttribute mlirDenseF64ArrayGet(MlirContext ctx, intptr_t size, double const *values)
MLIR_CAPI_EXPORTED int64_t mlirIntegerAttrGetValueInt(MlirAttribute attr)
Returns the value stored in the given integer attribute, assuming the value is of signless type and f...
MLIR_CAPI_EXPORTED intptr_t mlirSymbolRefAttrGetNumNestedReferences(MlirAttribute attr)
Returns the number of references nested in the given symbol reference attribute.
MLIR_CAPI_EXPORTED MlirType mlirTypeAttrGetValue(MlirAttribute attr)
Returns the type stored in the given type attribute.
MLIR_CAPI_EXPORTED bool mlirDenseElementsAttrIsSplat(MlirAttribute attr)
Checks whether the given dense elements attribute contains a single replicated value (splat).
MLIR_CAPI_EXPORTED MlirAttribute mlirDenseElementsAttrGet(MlirType shapedType, intptr_t numElements, MlirAttribute const *elements)
Creates a dense elements attribute with the given Shaped type and elements in the same context as the...
MLIR_CAPI_EXPORTED bool mlirAttributeIsADenseBoolArray(MlirAttribute attr)
Checks whether the given attribute is a dense array attribute.
MLIR_CAPI_EXPORTED MlirStringRef mlirOpaqueAttrGetData(MlirAttribute attr)
Returns the raw data as a string reference.
MLIR_CAPI_EXPORTED MlirAttribute mlirAttributeGetNull(void)
Returns an empty attribute.
MLIR_CAPI_EXPORTED MlirAttribute mlirBoolAttrGet(MlirContext ctx, int value)
Creates a bool attribute in the given context with the given value.
MLIR_CAPI_EXPORTED MlirTypeID mlirFloatAttrGetTypeID(void)
Returns the typeID of a Float attribute.
MLIR_CAPI_EXPORTED int64_t mlirIntegerAttrGetValueSInt(MlirAttribute attr)
Returns the value stored in the given integer attribute, assuming the value is of signed type and fit...
MLIR_CAPI_EXPORTED int8_t mlirDenseI8ArrayGetElement(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED MlirAttribute mlirDenseI32ArrayGet(MlirContext ctx, intptr_t size, int32_t const *values)
MLIR_CAPI_EXPORTED int64_t mlirDenseElementsAttrGetInt64Value(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED MlirNamedAttribute mlirDictionaryAttrGetElement(MlirAttribute attr, intptr_t pos)
Returns pos-th element of the given dictionary attribute.
MLIR_CAPI_EXPORTED MlirTypeID mlirUnitAttrGetTypeID(void)
Returns the typeID of a Unit attribute.
MLIR_CAPI_EXPORTED MlirAttribute mlirDenseF32ArrayGet(MlirContext ctx, intptr_t size, float const *values)
MLIR_CAPI_EXPORTED MlirAttribute mlirDenseBoolArrayGet(MlirContext ctx, intptr_t size, int const *values)
Create a dense array attribute with the given elements.
MLIR_CAPI_EXPORTED bool mlirAttributeIsAOpaque(MlirAttribute attr)
Checks whether the given attribute is an opaque attribute.
MLIR_CAPI_EXPORTED MlirAttribute mlirArrayAttrGetElement(MlirAttribute attr, intptr_t pos)
Returns pos-th element stored in the given array attribute.
MLIR_CAPI_EXPORTED MlirAttribute mlirDictionaryAttrGetElementByName(MlirAttribute attr, MlirStringRef name)
Returns the dictionary attribute element with the given name or NULL if the given name does not exist...
MLIR_CAPI_EXPORTED bool mlirAttributeIsADenseF32Array(MlirAttribute attr)
MLIR_CAPI_EXPORTED MlirTypeID mlirSymbolRefAttrGetTypeID(void)
Returns the typeID of an SymbolRef attribute.
MLIR_CAPI_EXPORTED MlirTypeID mlirDenseArrayAttrGetTypeID(void)
MLIR_CAPI_EXPORTED MlirAttribute mlirDenseElementsAttrGetSplatValue(MlirAttribute attr)
Returns the single replicated value (splat) of a specific type contained by the given dense elements ...
MLIR_CAPI_EXPORTED bool mlirAttributeIsASymbolRef(MlirAttribute attr)
Checks whether the given attribute is a symbol reference attribute.
MLIR_CAPI_EXPORTED float mlirDenseElementsAttrGetFloatValue(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED int64_t mlirElementsAttrGetNumElements(MlirAttribute attr)
Gets the total number of elements in the given elements attribute.
MLIR_CAPI_EXPORTED MlirStringRef mlirOpaqueAttrGetDialectNamespace(MlirAttribute attr)
Returns the namespace of the dialect with which the given opaque attribute is associated.
MLIR_CAPI_EXPORTED bool mlirAttributeIsADictionary(MlirAttribute attr)
Checks whether the given attribute is a dictionary attribute.
MLIR_CAPI_EXPORTED int32_t mlirDenseElementsAttrGetInt32Value(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED MlirStringRef mlirStringAttrGetValue(MlirAttribute attr)
Returns the attribute values as a string reference.
MLIR_CAPI_EXPORTED MlirAttribute mlirDenseI16ArrayGet(MlirContext ctx, intptr_t size, int16_t const *values)
MLIR_CAPI_EXPORTED MlirTypeID mlirOpaqueAttrGetTypeID(void)
Returns the typeID of an Opaque attribute.
MLIR_CAPI_EXPORTED double mlirFloatAttrGetValueDouble(MlirAttribute attr)
Returns the value stored in the given floating point attribute, interpreting the value as double.
MLIR_CAPI_EXPORTED uint64_t mlirIntegerAttrGetValueUInt(MlirAttribute attr)
Returns the value stored in the given integer attribute, assuming the value is of unsigned type and f...
MLIR_CAPI_EXPORTED MlirAttribute mlirDenseI8ArrayGet(MlirContext ctx, intptr_t size, int8_t const *values)
MLIR_CAPI_EXPORTED MlirAttribute mlirUnitAttrGet(MlirContext ctx)
Creates a unit attribute in the given context.
MLIR_CAPI_EXPORTED double mlirDenseElementsAttrGetDoubleValue(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED intptr_t mlirStridedLayoutAttrGetNumStrides(MlirAttribute attr)
MLIR_CAPI_EXPORTED MlirAttribute mlirFloatAttrDoubleGet(MlirContext ctx, MlirType type, double value)
Creates a floating point attribute in the given context with the given double value and double-precis...
MLIR_CAPI_EXPORTED MlirAttribute mlirArrayAttrGet(MlirContext ctx, intptr_t numElements, MlirAttribute const *elements)
Creates an array element containing the given list of elements in the given context.
MLIR_CAPI_EXPORTED const void * mlirDenseElementsAttrGetRawData(MlirAttribute attr)
Returns the raw data of the given dense elements attribute.
MLIR_CAPI_EXPORTED intptr_t mlirDenseArrayGetNumElements(MlirAttribute attr)
Get the size of a dense array.
MLIR_CAPI_EXPORTED bool mlirAttributeIsAFloat(MlirAttribute attr)
Checks whether the given attribute is a floating point attribute.
MLIR_CAPI_EXPORTED MlirAttribute mlirSymbolRefAttrGet(MlirContext ctx, MlirStringRef symbol, intptr_t numReferences, MlirAttribute const *references)
Creates a symbol reference attribute in the given context referencing a symbol identified by the give...
MLIR_CAPI_EXPORTED MlirTypeID mlirTypeAttrGetTypeID(void)
Returns the typeID of a Type attribute.
MLIR_CAPI_EXPORTED MlirAttribute mlirDenseElementsAttrSplatGet(MlirType shapedType, MlirAttribute element)
Creates a dense elements attribute with the given Shaped type containing a single replicated element ...
MLIR_CAPI_EXPORTED MlirTypeID mlirDictionaryAttrGetTypeID(void)
Returns the typeID of a Dictionary attribute.
MLIR_CAPI_EXPORTED MlirAttribute mlirStringAttrGet(MlirContext ctx, MlirStringRef str)
Creates a string attribute in the given context containing the given string.
MLIR_CAPI_EXPORTED MlirAttribute mlirTypeAttrGet(MlirType type)
Creates a type attribute wrapping the given type in the same context as the type.
MLIR_CAPI_EXPORTED intptr_t mlirArrayAttrGetNumElements(MlirAttribute attr)
Returns the number of elements stored in the given array attribute.
MLIR_CAPI_EXPORTED MlirAttribute mlirDenseElementsAttrRawBufferGet(MlirType shapedType, size_t rawBufferSize, const void *rawBuffer)
Creates a dense elements attribute with the given Shaped type and elements populated from a packed,...
MLIR_CAPI_EXPORTED bool mlirAttributeIsADenseI32Array(MlirAttribute attr)
MLIR_CAPI_EXPORTED bool mlirAttributeIsADenseI8Array(MlirAttribute attr)
MLIR_CAPI_EXPORTED MlirAttribute mlirStringAttrTypedGet(MlirType type, MlirStringRef str)
Creates a string attribute in the given context containing the given string.
MLIR_CAPI_EXPORTED bool mlirAttributeIsAFlatSymbolRef(MlirAttribute attr)
Checks whether the given attribute is a flat symbol reference attribute.
MLIR_CAPI_EXPORTED MlirStringRef mlirFlatSymbolRefAttrGetValue(MlirAttribute attr)
Returns the referenced symbol as a string reference.
MLIR_CAPI_EXPORTED bool mlirAttributeIsADenseI16Array(MlirAttribute attr)
MLIR_CAPI_EXPORTED bool mlirAttributeIsADenseF64Array(MlirAttribute attr)
MLIR_CAPI_EXPORTED uint32_t mlirDenseElementsAttrGetUInt32Value(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED MlirType mlirRankedTensorTypeGet(intptr_t rank, const int64_t *shape, MlirType elementType, MlirAttribute encoding)
Creates a tensor type of a fixed rank with the given shape, element type, and optional encoding in th...
MLIR_CAPI_EXPORTED bool mlirIntegerTypeIsSignless(MlirType type)
Checks whether the given integer type is signless.
MLIR_CAPI_EXPORTED bool mlirTypeIsAInteger(MlirType type)
Checks whether the given type is an integer type.
MLIR_CAPI_EXPORTED int64_t mlirShapedTypeGetDimSize(MlirType type, intptr_t dim)
Returns the dim-th dimension of the given ranked shaped type.
MLIR_CAPI_EXPORTED MlirType mlirIntegerTypeGet(MlirContext ctx, unsigned bitwidth)
Creates a signless integer type of the given bitwidth in the context.
MLIR_CAPI_EXPORTED bool mlirIntegerTypeIsUnsigned(MlirType type)
Checks whether the given integer type is unsigned.
MLIR_CAPI_EXPORTED unsigned mlirIntegerTypeGetWidth(MlirType type)
Returns the bitwidth of an integer type.
MLIR_CAPI_EXPORTED int64_t mlirShapedTypeGetRank(MlirType type)
Returns the rank of the given ranked shaped type.
MLIR_CAPI_EXPORTED MlirType mlirF64TypeGet(MlirContext ctx)
Creates a f64 type in the given context.
MLIR_CAPI_EXPORTED MlirType mlirIntegerTypeSignedGet(MlirContext ctx, unsigned bitwidth)
Creates a signed integer type of the given bitwidth in the context.
MLIR_CAPI_EXPORTED MlirType mlirF16TypeGet(MlirContext ctx)
Creates an f16 type in the given context.
MLIR_CAPI_EXPORTED bool mlirTypeIsAF64(MlirType type)
Checks whether the given type is an f64 type.
MLIR_CAPI_EXPORTED bool mlirTypeIsAF16(MlirType type)
Checks whether the given type is an f16 type.
MLIR_CAPI_EXPORTED bool mlirIntegerTypeIsSigned(MlirType type)
Checks whether the given integer type is signed.
MLIR_CAPI_EXPORTED MlirType mlirShapedTypeGetElementType(MlirType type)
Returns the element type of the shaped type.
MLIR_CAPI_EXPORTED bool mlirShapedTypeHasStaticShape(MlirType type)
Checks whether the given shaped type has a static shape.
MLIR_CAPI_EXPORTED MlirType mlirF32TypeGet(MlirContext ctx)
Creates an f32 type in the given context.
MLIR_CAPI_EXPORTED bool mlirTypeIsAShaped(MlirType type)
Checks whether the given type is a Shaped type.
MLIR_CAPI_EXPORTED MlirType mlirIntegerTypeUnsignedGet(MlirContext ctx, unsigned bitwidth)
Creates an unsigned integer type of the given bitwidth in the context.
MLIR_CAPI_EXPORTED bool mlirTypeIsAF32(MlirType type)
Checks whether the given type is an f32 type.
MLIR_CAPI_EXPORTED bool mlirTypeIsAIndex(MlirType type)
Checks whether the given type is an index type.
MLIR_CAPI_EXPORTED int64_t mlirShapedTypeGetDynamicStrideOrOffset(void)
Returns the value indicating a dynamic stride or offset in a shaped type.
static bool mlirAttributeIsNull(MlirAttribute attr)
Checks whether an attribute is null.
Definition: IR.h:1179
MLIR_CAPI_EXPORTED MlirNamedAttribute mlirNamedAttributeGet(MlirIdentifier name, MlirAttribute attr)
Associates an attribute with the name. Takes ownership of neither.
Definition: IR.cpp:1297
MLIR_CAPI_EXPORTED MlirStringRef mlirIdentifierStr(MlirIdentifier ident)
Gets the string value of the identifier.
Definition: IR.cpp:1318
MLIR_CAPI_EXPORTED MlirType mlirAttributeGetType(MlirAttribute attribute)
Gets the type of this attribute.
Definition: IR.cpp:1270
MLIR_CAPI_EXPORTED MlirContext mlirTypeGetContext(MlirType type)
Gets the context that a type was created with.
Definition: IR.cpp:1235
MLIR_CAPI_EXPORTED bool mlirTypeEqual(MlirType t1, MlirType t2)
Checks if two types are equal.
Definition: IR.cpp:1247
MLIR_CAPI_EXPORTED MlirContext mlirAttributeGetContext(MlirAttribute attribute)
Gets the context that an attribute was created with.
Definition: IR.cpp:1266
MLIR_CAPI_EXPORTED MlirIdentifier mlirIdentifierGet(MlirContext context, MlirStringRef str)
Gets an identifier with the given string value.
Definition: IR.cpp:1306
static MlirStringRef mlirStringRefCreate(const char *str, size_t length)
Constructs a string reference from the pointer and length.
Definition: Support.h:82
llvm::TypeSize divideCeil(llvm::TypeSize numerator, uint64_t denominator)
Divides the known min value of the numerator by the denominator and rounds the result up to the next ...
void populateIRAttributes(nanobind::module_ &m)
Include the generated interface declarations.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
Named MLIR attribute.
Definition: IR.h:76
MlirAttribute attribute
Definition: IR.h:78
MlirIdentifier name
Definition: IR.h:77
A pointer to a sized fragment of a string, not necessarily null-terminated.
Definition: Support.h:73
const char * data
Pointer to the first symbol.
Definition: Support.h:74
size_t length
Length of the fragment.
Definition: Support.h:75
Custom exception that allows access to error diagnostic information.
Definition: IRModule.h:1316
RAII object that captures any error diagnostics emitted to the provided context.
Definition: IRModule.h:409
std::vector< PyDiagnostic::DiagnosticInfo > take()
Definition: IRModule.h:419
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.