MLIR 23.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 <algorithm>
10#include <cmath>
11#include <cstdint>
12#include <cstring>
13#include <optional>
14#include <string>
15#include <string_view>
16#include <utility>
17#include <vector>
18
20#include "mlir-c/BuiltinTypes.h"
27
28namespace nb = nanobind;
29using namespace nanobind::literals;
30using namespace mlir;
32
33//------------------------------------------------------------------------------
34// Docstrings (trivial, non-duplicated docstrings are included inline).
35//------------------------------------------------------------------------------
36
37static const char kDenseElementsAttrGetDocstring[] =
38 R"(Gets a DenseElementsAttr from a Python buffer or array.
39
40When `type` is not provided, then some limited type inferencing is done based
41on the buffer format. Support presently exists for 8/16/32/64 signed and
42unsigned integers and float16/float32/float64. DenseElementsAttrs of these
43types can also be converted back to a corresponding buffer.
44
45For conversions outside of these types, a `type=` must be explicitly provided
46and the buffer contents must be bit-castable to the MLIR internal
47representation:
48
49 * Integer types: the buffer must be byte aligned to the next byte boundary.
50 * Floating point types: Must be bit-castable to the given floating point
51 size.
52 * i1 (bool): Each boolean value is stored as a single byte (0 or 1).
53
54If a single element buffer is passed, then a splat will be created.
55
56Args:
57 array: The array or buffer to convert.
58 signless: If inferring an appropriate MLIR type, use signless types for
59 integers (defaults True).
60 type: Skips inference of the MLIR element type and uses this instead. The
61 storage size must be consistent with the actual contents of the buffer.
62 shape: Overrides the shape of the buffer when constructing the MLIR
63 shaped type. This is needed when the physical and logical shape differ.
64 context: Explicit context, if not from context manager.
65
66Returns:
67 DenseElementsAttr on success.
68
69Raises:
70 ValueError: If the type of the buffer or array cannot be matched to an MLIR
71 type or if the buffer does not meet expectations.
72)";
73
75 R"(Gets a DenseElementsAttr from a Python list of attributes.
76
77Note that it can be expensive to construct attributes individually.
78For a large number of elements, consider using a Python buffer or array instead.
79
80Args:
81 attrs: A list of attributes.
82 type: The desired shape and type of the resulting DenseElementsAttr.
83 If not provided, the element type is determined based on the type
84 of the 0th attribute and the shape is `[len(attrs)]`.
85 context: Explicit context, if not from context manager.
86
87Returns:
88 DenseElementsAttr on success.
89
90Raises:
91 ValueError: If the type of the attributes does not match the type
92 specified by `shaped_type`.
93)";
94
96 R"(Gets a DenseResourceElementsAttr from a Python buffer or array.
97
98This function does minimal validation or massaging of the data, and it is
99up to the caller to ensure that the buffer meets the characteristics
100implied by the shape.
101
102The backing buffer and any user objects will be retained for the lifetime
103of the resource blob. This is typically bounded to the context but the
104resource can have a shorter lifespan depending on how it is used in
105subsequent processing.
106
107Args:
108 buffer: The array or buffer to convert.
109 name: Name to provide to the resource (may be changed upon collision).
110 type: The explicit ShapedType to construct the attribute with.
111 context: Explicit context, if not from context manager.
112
113Returns:
114 DenseResourceElementsAttr on success.
115
116Raises:
117 ValueError: If the type of the buffer or array cannot be matched to an MLIR
118 type or if the buffer does not meet expectations.
119)";
120
121namespace {
122/// Local helper adapted from llvm::scope_exit.
123template <typename Callable>
124class [[nodiscard]] scope_exit {
125 Callable ExitFunction;
126 bool Engaged = true; // False once moved-from or release()d.
127
128public:
129 template <typename Fp>
130 explicit scope_exit(Fp &&F) : ExitFunction(std::forward<Fp>(F)) {}
131
132 scope_exit(scope_exit &&Rhs)
133 : ExitFunction(std::move(Rhs.ExitFunction)), Engaged(Rhs.Engaged) {
134 Rhs.release();
135 }
136 scope_exit(const scope_exit &) = delete;
137 scope_exit &operator=(scope_exit &&) = delete;
138 scope_exit &operator=(const scope_exit &) = delete;
139
140 void release() { Engaged = false; }
141
142 ~scope_exit() {
143 if (Engaged)
144 ExitFunction();
145 }
146};
147
148template <typename Callable>
149scope_exit(Callable) -> scope_exit<Callable>;
150} // namespace
151
152namespace mlir {
153namespace python {
155
157 void *ptr, Py_ssize_t itemsize, const char *format, Py_ssize_t ndim,
158 std::vector<Py_ssize_t> shape_in, std::vector<Py_ssize_t> strides_in,
159 bool readonly,
160 std::unique_ptr<Py_buffer, void (*)(Py_buffer *)> owned_view_in)
162 shape(std::move(shape_in)), strides(std::move(strides_in)),
163 readonly(readonly), owned_view(std::move(owned_view_in)) {
164 size = 1;
165 for (Py_ssize_t i = 0; i < ndim; ++i) {
166 size *= shape[i];
167 }
168}
169
170nb_buffer_info nb_buffer::request() const {
171 int flags = PyBUF_STRIDES | PyBUF_FORMAT;
172 auto *view = new Py_buffer();
173 if (PyObject_GetBuffer(ptr(), view, flags) != 0) {
174 delete view;
175 throw nb::python_error();
176 }
177 return nb_buffer_info(view);
178}
179
180template <>
182 static const char *format() { return "?"; }
183};
184template <>
185struct nb_format_descriptor<int8_t> {
186 static const char *format() { return "b"; }
187};
188template <>
189struct nb_format_descriptor<uint8_t> {
190 static const char *format() { return "B"; }
191};
192template <>
193struct nb_format_descriptor<int16_t> {
194 static const char *format() { return "h"; }
195};
196template <>
197struct nb_format_descriptor<uint16_t> {
198 static const char *format() { return "H"; }
199};
200template <>
201struct nb_format_descriptor<int32_t> {
202 static const char *format() { return "i"; }
203};
204template <>
205struct nb_format_descriptor<uint32_t> {
206 static const char *format() { return "I"; }
207};
208template <>
210 static const char *format() { return "q"; }
211};
212template <>
213struct nb_format_descriptor<uint64_t> {
214 static const char *format() { return "Q"; }
215};
216template <>
217struct nb_format_descriptor<float> {
218 static const char *format() { return "f"; }
219};
220template <>
221struct nb_format_descriptor<double> {
222 static const char *format() { return "d"; }
223};
224
226 c.def_static(
227 "get",
228 [](PyAffineMap &affineMap) {
229 MlirAttribute attr = mlirAffineMapAttrGet(affineMap.get());
230 return PyAffineMapAttribute(affineMap.getContext(), attr);
231 },
232 nb::arg("affine_map"), "Gets an attribute wrapping an AffineMap.");
233 c.def_prop_ro(
234 "value",
235 [](PyAffineMapAttribute &self) {
237 },
238 "Returns the value of the AffineMap attribute");
239}
240
242 c.def_static(
243 "get",
244 [](PyIntegerSet &integerSet) {
245 MlirAttribute attr = mlirIntegerSetAttrGet(integerSet.get());
246 return PyIntegerSetAttribute(integerSet.getContext(), attr);
247 },
248 nb::arg("integer_set"), "Gets an attribute wrapping an IntegerSet.");
249}
250
251nb::typed<nb::object, PyAttribute>
253 // TODO: Throw is an inefficient way to stop iteration.
254 if (PyArrayAttribute::PyArrayAttributeIterator::nextIndex >=
256 PyArrayAttribute::PyArrayAttributeIterator::attr.get())) {
257 PyErr_SetNone(PyExc_StopIteration);
258 // python functions should return NULL after setting any exception
259 return nb::object();
260 }
261 return PyAttribute(
262 this->PyArrayAttribute::PyArrayAttributeIterator::attr
263 .getContext(),
265 PyArrayAttribute::PyArrayAttributeIterator::attr.get(),
266 PyArrayAttribute::PyArrayAttributeIterator::nextIndex++))
267 .maybeDownCast();
268}
269
271 nb::class_<PyArrayAttributeIterator>(m, "ArrayAttributeIterator")
272 .def("__iter__", &PyArrayAttributeIterator::dunderIter)
273 .def("__next__", &PyArrayAttributeIterator::dunderNext);
274}
275
276MlirAttribute PyArrayAttribute::getItem(intptr_t i) const {
277 return mlirArrayAttrGetElement(*this, i);
278}
279
281 c.def_static(
282 "get",
283 [](const nb::list &attributes, DefaultingPyMlirContext context) {
284 std::vector<MlirAttribute> mlirAttributes;
285 mlirAttributes.reserve(nb::len(attributes));
286 for (auto attribute : attributes) {
287 mlirAttributes.push_back(pyTryCast<PyAttribute>(attribute));
288 }
289 MlirAttribute attr = mlirArrayAttrGet(
290 context->get(), mlirAttributes.size(), mlirAttributes.data());
291 return PyArrayAttribute(context->getRef(), attr);
292 },
293 nb::arg("attributes"), nb::arg("context") = nb::none(),
294 "Gets a uniqued Array attribute");
295 c.def("__getitem__",
296 [](PyArrayAttribute &arr,
297 intptr_t i) -> nb::typed<nb::object, PyAttribute> {
298 if (i >= mlirArrayAttrGetNumElements(arr))
299 throw nb::index_error("ArrayAttribute index out of range");
300 return PyAttribute(arr.getContext(), arr.getItem(i)).maybeDownCast();
301 })
302 .def("__len__",
303 [](const PyArrayAttribute &arr) {
304 return mlirArrayAttrGetNumElements(arr);
305 })
306 .def("__iter__", [](const PyArrayAttribute &arr) {
307 return PyArrayAttributeIterator(arr);
308 });
309 c.def("__add__", [](PyArrayAttribute arr, const nb::list &extras) {
310 std::vector<MlirAttribute> attributes;
311 intptr_t numOldElements = mlirArrayAttrGetNumElements(arr);
312 attributes.reserve(numOldElements + nb::len(extras));
313 for (intptr_t i = 0; i < numOldElements; ++i)
314 attributes.push_back(arr.getItem(i));
315 for (nb::handle attr : extras)
316 attributes.push_back(pyTryCast<PyAttribute>(attr));
317 MlirAttribute arrayAttr = mlirArrayAttrGet(
318 arr.getContext()->get(), attributes.size(), attributes.data());
319 return PyArrayAttribute(arr.getContext(), arrayAttr);
320 });
321}
323 c.def_static(
324 "get",
325 [](PyType &type, double value, DefaultingPyLocation loc) {
326 PyMlirContext::ErrorCapture errors(loc->getContext());
327 MlirAttribute attr = mlirFloatAttrDoubleGetChecked(loc, type, value);
328 if (mlirAttributeIsNull(attr))
329 throw MLIRError("Invalid attribute", errors.take());
330 return PyFloatAttribute(type.getContext(), attr);
331 },
332 nb::arg("type"), nb::arg("value"), nb::arg("loc") = nb::none(),
333 "Gets an uniqued float point attribute associated to a type");
334 c.def_static(
335 "get_unchecked",
336 [](PyType &type, double value, DefaultingPyMlirContext context) {
337 PyMlirContext::ErrorCapture errors(context->getRef());
338 MlirAttribute attr =
339 mlirFloatAttrDoubleGet(context.get()->get(), type, value);
340 if (mlirAttributeIsNull(attr))
341 throw MLIRError("Invalid attribute", errors.take());
342 return PyFloatAttribute(type.getContext(), attr);
343 },
344 nb::arg("type"), nb::arg("value"), nb::arg("context") = nb::none(),
345 "Gets an uniqued float point attribute associated to a type");
346 c.def_static(
347 "get_f32",
348 [](double value, DefaultingPyMlirContext context) {
349 MlirAttribute attr = mlirFloatAttrDoubleGet(
350 context->get(), mlirF32TypeGet(context->get()), value);
351 return PyFloatAttribute(context->getRef(), attr);
352 },
353 nb::arg("value"), nb::arg("context") = nb::none(),
354 "Gets an uniqued float point attribute associated to a f32 type");
355 c.def_static(
356 "get_f64",
357 [](double value, DefaultingPyMlirContext context) {
358 MlirAttribute attr = mlirFloatAttrDoubleGet(
359 context->get(), mlirF64TypeGet(context->get()), value);
360 return PyFloatAttribute(context->getRef(), attr);
361 },
362 nb::arg("value"), nb::arg("context") = nb::none(),
363 "Gets an uniqued float point attribute associated to a f64 type");
364 c.def_prop_ro("value", mlirFloatAttrGetValueDouble,
365 "Returns the value of the float attribute");
366 c.def("__float__", mlirFloatAttrGetValueDouble,
367 "Converts the value of the float attribute to a Python float");
368}
369
371 c.def_static(
372 "get",
373 [](PyType &type, nb::object value) {
374 // Handle IndexType - it doesn't have a bit width or signedness.
375 if (mlirTypeIsAIndex(type)) {
376 int64_t intValue = nb::cast<int64_t>(value);
377 MlirAttribute attr = mlirIntegerAttrGet(type, intValue);
378 return PyIntegerAttribute(type.getContext(), attr);
379 }
380
381 // Get the bit width of the integer type.
382 unsigned bitWidth = mlirIntegerTypeGetWidth(type);
383
384 // Try to use the fast path for small integers.
385 if (bitWidth <= 64) {
386 int64_t intValue = nb::cast<int64_t>(value);
387 MlirAttribute attr = mlirIntegerAttrGet(type, intValue);
388 return PyIntegerAttribute(type.getContext(), attr);
389 }
390
391 // For larger integers, convert Python int to array of 64-bit words.
392 unsigned numWords = std::ceil(static_cast<double>(bitWidth) / 64);
393 std::vector<uint64_t> words(numWords, 0);
394
395 // Extract words from Python integer (little-endian order).
396 nb::object mask = nb::int_(0xFFFFFFFFFFFFFFFFULL);
397 nb::object shift = nb::int_(64);
398 nb::object current = value;
399
400 // Handle negative numbers for signed types by converting to two's
401 // complement representation.
402 if (mlirIntegerTypeIsSigned(type)) {
403 nb::object zero = nb::int_(0);
404 if (nb::cast<bool>(current < zero)) {
405 nb::object twoToTheBitWidth = nb::int_(1) << nb::int_(bitWidth);
406 current = current + twoToTheBitWidth;
407 }
408 }
409
410 for (unsigned i = 0; i < numWords; ++i) {
411 words[i] = nb::cast<uint64_t>(current & mask);
412 current = current >> shift;
413 }
414
415 MlirAttribute attr =
416 mlirIntegerAttrGetFromWords(type, numWords, words.data());
417 return PyIntegerAttribute(type.getContext(), attr);
418 },
419 nb::arg("type"), nb::arg("value"),
420 "Gets an uniqued integer attribute associated to a type");
421 c.def_prop_ro("value", toPyInt, "Returns the value of the integer attribute");
422 c.def("__int__", toPyInt,
423 "Converts the value of the integer attribute to a Python int");
424 c.def_prop_ro_static("static_typeid", [](nb::object & /*class*/) {
426 });
427}
428
429nb::object PyIntegerAttribute::toPyInt(PyIntegerAttribute &self) {
430 MlirType type = mlirAttributeGetType(self);
431 unsigned bitWidth = mlirIntegerAttrGetValueBitWidth(self);
432
433 // For integers that fit in 64 bits, use the fast path.
434 if (bitWidth <= 64) {
436 return nb::int_(mlirIntegerAttrGetValueInt(self));
437 if (mlirIntegerTypeIsSigned(type))
438 return nb::int_(mlirIntegerAttrGetValueSInt(self));
439 return nb::int_(mlirIntegerAttrGetValueUInt(self));
440 }
441
442 // For larger integers, reconstruct the value from raw words.
443 unsigned numWords = mlirIntegerAttrGetValueNumWords(self);
444 std::vector<uint64_t> words(numWords);
445 mlirIntegerAttrGetValueWords(self, words.data());
446
447 // Build the Python integer by shifting and ORing the words together.
448 // Words are in little-endian order (least significant first).
449 nb::object result = nb::int_(0);
450 nb::object shift = nb::int_(64);
451 for (unsigned i = numWords; i > 0; --i) {
452 result = result << shift;
453 result = result | nb::int_(words[i - 1]);
454 }
455
456 // Handle signed integers: if the sign bit is set, subtract 2^bitWidth.
457 if (mlirIntegerTypeIsSigned(type)) {
458 // Check if sign bit is set (most significant bit of the value).
459 bool signBitSet = (words[numWords - 1] >> ((bitWidth - 1) % 64)) & 1;
460 if (signBitSet) {
461 nb::object twoToTheBitWidth = nb::int_(1) << nb::int_(bitWidth);
462 result = result - twoToTheBitWidth;
463 }
464 }
465
466 return result;
467}
468
470 c.def_static(
471 "get",
472 [](bool value, DefaultingPyMlirContext context) {
473 MlirAttribute attr = mlirBoolAttrGet(context->get(), value);
474 return PyBoolAttribute(context->getRef(), attr);
475 },
476 nb::arg("value"), nb::arg("context") = nb::none(),
477 "Gets an uniqued bool attribute");
478 c.def_prop_ro("value", mlirBoolAttrGetValue,
479 "Returns the value of the bool attribute");
480 c.def("__bool__", mlirBoolAttrGetValue,
481 "Converts the value of the bool attribute to a Python bool");
482}
483
485PySymbolRefAttribute::fromList(const std::vector<std::string> &symbols,
486 PyMlirContext &context) {
487 if (symbols.empty())
488 throw std::runtime_error("SymbolRefAttr must be composed of at least "
489 "one symbol.");
490 MlirStringRef rootSymbol = toMlirStringRef(symbols[0]);
491 std::vector<MlirAttribute> referenceAttrs;
492 for (size_t i = 1; i < symbols.size(); ++i) {
493 referenceAttrs.push_back(
494 mlirFlatSymbolRefAttrGet(context.get(), toMlirStringRef(symbols[i])));
495 }
496 return PySymbolRefAttribute(context.getRef(),
497 mlirSymbolRefAttrGet(context.get(), rootSymbol,
498 referenceAttrs.size(),
499 referenceAttrs.data()));
500}
501
503 c.def_static(
504 "get",
505 [](const std::vector<std::string> &symbols,
506 DefaultingPyMlirContext context) {
507 return PySymbolRefAttribute::fromList(symbols, context.resolve());
508 },
509 nb::arg("symbols"), nb::arg("context") = nb::none(),
510 "Gets a uniqued SymbolRef attribute from a list of symbol names");
511 c.def_prop_ro(
512 "value",
513 [](PySymbolRefAttribute &self) {
515 std::vector<std::string> symbols = {
516 std::string(rootRef.data, rootRef.length)};
517 for (int i = 0; i < mlirSymbolRefAttrGetNumNestedReferences(self);
518 ++i) {
521 symbols.push_back(std::string(nestedRef.data, nestedRef.length));
522 }
523 return symbols;
524 },
525 "Returns the value of the SymbolRef attribute as a list[str]");
526}
527
529 c.def_static(
530 "get",
531 [](const std::string &value, DefaultingPyMlirContext context) {
532 MlirAttribute attr =
533 mlirFlatSymbolRefAttrGet(context->get(), toMlirStringRef(value));
534 return PyFlatSymbolRefAttribute(context->getRef(), attr);
535 },
536 nb::arg("value"), nb::arg("context") = nb::none(),
537 "Gets a uniqued FlatSymbolRef attribute");
538 c.def_prop_ro(
539 "value",
540 [](PyFlatSymbolRefAttribute &self) {
542 return nb::str(stringRef.data, stringRef.length);
543 },
544 "Returns the value of the FlatSymbolRef attribute as a string");
545}
546
548 c.def_static(
549 "get",
550 [](const std::string &dialectNamespace, const nb_buffer &buffer,
551 PyType &type, DefaultingPyMlirContext context) {
552 const nb_buffer_info bufferInfo = buffer.request();
553 intptr_t bufferSize = bufferInfo.size;
554 MlirAttribute attr = mlirOpaqueAttrGet(
555 context->get(), toMlirStringRef(dialectNamespace), bufferSize,
556 static_cast<char *>(bufferInfo.ptr), type);
557 return PyOpaqueAttribute(context->getRef(), attr);
558 },
559 nb::arg("dialect_namespace"), nb::arg("buffer"), nb::arg("type"),
560 nb::arg("context") = nb::none(),
561 // clang-format off
562 nb::sig("def get(dialect_namespace: str, buffer: typing_extensions.Buffer, type: Type, context: Context | None = None) -> OpaqueAttr"),
563 // clang-format on
564 "Gets an Opaque attribute.");
565 c.def_prop_ro(
566 "dialect_namespace",
567 [](PyOpaqueAttribute &self) {
569 return nb::str(stringRef.data, stringRef.length);
570 },
571 "Returns the dialect namespace for the Opaque attribute as a string");
572 c.def_prop_ro(
573 "data",
574 [](PyOpaqueAttribute &self) {
575 MlirStringRef stringRef = mlirOpaqueAttrGetData(self);
576 return nb::bytes(stringRef.data, stringRef.length);
577 },
578 "Returns the data for the Opaqued attributes as `bytes`");
579}
580
582PyDenseElementsAttribute::getFromList(const nb::list &attributes,
583 std::optional<PyType> explicitType,
584 DefaultingPyMlirContext contextWrapper) {
585 const size_t numAttributes = nb::len(attributes);
586 if (numAttributes == 0)
587 throw nb::value_error("Attributes list must be non-empty.");
588
589 MlirType shapedType;
590 if (explicitType) {
591 if ((!mlirTypeIsAShaped(*explicitType) ||
592 !mlirShapedTypeHasStaticShape(*explicitType))) {
593
594 std::string message = nanobind::detail::join(
595 "Expected a static ShapedType for the shaped_type parameter: ",
596 nb::cast<std::string>(nb::repr(nb::cast(*explicitType))));
597 throw nb::value_error(message.c_str());
598 }
599 shapedType = *explicitType;
600 } else {
601 std::vector<int64_t> shape = {static_cast<int64_t>(numAttributes)};
602 shapedType = mlirRankedTensorTypeGet(
603 shape.size(), shape.data(),
606 }
607
608 std::vector<MlirAttribute> mlirAttributes;
609 mlirAttributes.reserve(numAttributes);
610 for (const nb::handle &attribute : attributes) {
611 MlirAttribute mlirAttribute = pyTryCast<PyAttribute>(attribute);
612 MlirType attrType = mlirAttributeGetType(mlirAttribute);
613 mlirAttributes.push_back(mlirAttribute);
614
615 if (!mlirTypeEqual(mlirShapedTypeGetElementType(shapedType), attrType)) {
616 std::string message = nanobind::detail::join(
617 "All attributes must be of the same type and match the type "
618 "parameter: expected=",
619 nb::cast<std::string>(nb::repr(nb::cast(shapedType))),
620 ", but got=", nb::cast<std::string>(nb::repr(nb::cast(attrType))));
621 throw nb::value_error(message.c_str());
622 }
623 }
624
625 MlirAttribute elements = mlirDenseElementsAttrGet(
626 shapedType, mlirAttributes.size(), mlirAttributes.data());
627
628 return PyDenseElementsAttribute(contextWrapper->getRef(), elements);
629}
630
632 const nb_buffer &array, bool signless,
633 const std::optional<PyType> &explicitType,
634 std::optional<std::vector<int64_t>> explicitShape,
635 DefaultingPyMlirContext contextWrapper) {
636 // Request a contiguous view. In exotic cases, this will cause a copy.
637 int flags = PyBUF_ND;
638 if (!explicitType) {
639 flags |= PyBUF_FORMAT;
640 }
641 Py_buffer view;
642 if (PyObject_GetBuffer(array.ptr(), &view, flags) != 0) {
643 throw nb::python_error();
644 }
645 scope_exit freeBuffer([&]() { PyBuffer_Release(&view); });
646
647 MlirContext context = contextWrapper->get();
648 MlirAttribute attr = getAttributeFromBuffer(
649 view, signless, explicitType, std::move(explicitShape), context);
650 if (mlirAttributeIsNull(attr)) {
651 throw std::invalid_argument(
652 "DenseElementsAttr could not be constructed from the given buffer. "
653 "This may mean that the Python buffer layout does not match that "
654 "MLIR expected layout and is a bug.");
655 }
656 return PyDenseElementsAttribute(contextWrapper->getRef(), attr);
657}
658
661 PyAttribute &elementAttr) {
662 auto contextWrapper =
664 if (!mlirAttributeIsAInteger(elementAttr) &&
665 !mlirAttributeIsAFloat(elementAttr)) {
666 std::string message = "Illegal element type for DenseElementsAttr: ";
667 message.append(nb::cast<std::string>(nb::repr(nb::cast(elementAttr))));
668 throw nb::value_error(message.c_str());
669 }
670 if (!mlirTypeIsAShaped(shapedType) ||
671 !mlirShapedTypeHasStaticShape(shapedType)) {
672 std::string message =
673 "Expected a static ShapedType for the shaped_type parameter: ";
674 message.append(nb::cast<std::string>(nb::repr(nb::cast(shapedType))));
675 throw nb::value_error(message.c_str());
676 }
677 MlirType shapedElementType = mlirShapedTypeGetElementType(shapedType);
678 MlirType attrType = mlirAttributeGetType(elementAttr);
679 if (!mlirTypeEqual(shapedElementType, attrType)) {
680 std::string message =
681 "Shaped element type and attribute type must be equal: shaped=";
682 message.append(nb::cast<std::string>(nb::repr(nb::cast(shapedType))));
683 message.append(", element=");
684 message.append(nb::cast<std::string>(nb::repr(nb::cast(elementAttr))));
685 throw nb::value_error(message.c_str());
686 }
687
688 MlirAttribute elements =
689 mlirDenseElementsAttrSplatGet(shapedType, elementAttr);
690 return PyDenseElementsAttribute(contextWrapper->getRef(), elements);
691}
692
696
697std::unique_ptr<nb_buffer_info> PyDenseElementsAttribute::accessBuffer() {
698 MlirType shapedType = mlirAttributeGetType(*this);
699 MlirType elementType = mlirShapedTypeGetElementType(shapedType);
700 std::string format;
701
702 if (mlirTypeIsAF32(elementType)) {
703 // f32
704 return bufferInfo<float>(shapedType);
705 }
706 if (mlirTypeIsAF64(elementType)) {
707 // f64
708 return bufferInfo<double>(shapedType);
709 }
710 if (mlirTypeIsAF16(elementType)) {
711 // f16
712 return bufferInfo<uint16_t>(shapedType, "e");
713 }
714 if (mlirTypeIsAIndex(elementType)) {
715 // Same as IndexType::kInternalStorageBitWidth
716 return bufferInfo<int64_t>(shapedType);
717 }
718 if (mlirTypeIsAInteger(elementType) &&
719 mlirIntegerTypeGetWidth(elementType) == 32) {
720 if (mlirIntegerTypeIsSignless(elementType) ||
721 mlirIntegerTypeIsSigned(elementType)) {
722 // i32
723 return bufferInfo<int32_t>(shapedType);
724 }
725 if (mlirIntegerTypeIsUnsigned(elementType)) {
726 // unsigned i32
727 return bufferInfo<uint32_t>(shapedType);
728 }
729 } else if (mlirTypeIsAInteger(elementType) &&
730 mlirIntegerTypeGetWidth(elementType) == 64) {
731 if (mlirIntegerTypeIsSignless(elementType) ||
732 mlirIntegerTypeIsSigned(elementType)) {
733 // i64
734 return bufferInfo<int64_t>(shapedType);
735 }
736 if (mlirIntegerTypeIsUnsigned(elementType)) {
737 // unsigned i64
738 return bufferInfo<uint64_t>(shapedType);
739 }
740 } else if (mlirTypeIsAInteger(elementType) &&
741 mlirIntegerTypeGetWidth(elementType) == 8) {
742 if (mlirIntegerTypeIsSignless(elementType) ||
743 mlirIntegerTypeIsSigned(elementType)) {
744 // i8
745 return bufferInfo<int8_t>(shapedType);
746 }
747 if (mlirIntegerTypeIsUnsigned(elementType)) {
748 // unsigned i8
749 return bufferInfo<uint8_t>(shapedType);
750 }
751 } else if (mlirTypeIsAInteger(elementType) &&
752 mlirIntegerTypeGetWidth(elementType) == 16) {
753 if (mlirIntegerTypeIsSignless(elementType) ||
754 mlirIntegerTypeIsSigned(elementType)) {
755 // i16
756 return bufferInfo<int16_t>(shapedType);
757 }
758 if (mlirIntegerTypeIsUnsigned(elementType)) {
759 // unsigned i16
760 return bufferInfo<uint16_t>(shapedType);
761 }
762 } else if (mlirTypeIsAInteger(elementType) &&
763 mlirIntegerTypeGetWidth(elementType) == 1) {
764 // i1 / bool
765 return bufferInfo<bool>(shapedType);
766 }
767
768 // TODO: Currently crashes the program.
769 // Reported as https://github.com/pybind/pybind11/issues/3336
770 throw std::invalid_argument(
771 "unsupported data type for conversion to Python buffer");
772}
773
774template <typename ClassT>
776 const char *pyClassName) {
777 std::string getSig1 =
778 // clang-format off
779 "def get(array: typing_extensions.Buffer, signless: bool = True, type: Type | None = None, shape: Sequence[int] | None = None, context: Context | None = None) -> " +
780 // clang-format on
781 std::string(pyClassName);
782 std::string getSig2 =
783 // clang-format off
784 "def get(attrs: Sequence[Attribute], type: Type | None = None, context: Context | None = None) -> " +
785 // clang-format on
786 std::string(pyClassName);
787 std::string getSplatSig =
788 // clang-format off
789 "def get_splat(shaped_type: Type, element_attr: Attribute) -> " +
790 // clang-format on
791 std::string(pyClassName);
792
793 c.def_static("get", PyDenseElementsAttribute::getFromBuffer, nb::arg("array"),
794 nb::arg("signless") = true, nb::arg("type") = nb::none(),
795 nb::arg("shape") = nb::none(), nb::arg("context") = nb::none(),
796 nb::sig(getSig1.c_str()), kDenseElementsAttrGetDocstring)
797 .def_static("get", PyDenseElementsAttribute::getFromList,
798 nb::arg("attrs"), nb::arg("type") = nb::none(),
799 nb::arg("context") = nb::none(), nb::sig(getSig2.c_str()),
801 .def_static("get_splat", PyDenseElementsAttribute::getSplat,
802 nb::arg("shaped_type"), nb::arg("element_attr"),
803 nb::sig(getSplatSig.c_str()),
804 ("Gets a " + std::string(pyClassName) +
805 " where all values are the same")
806 .c_str());
807}
808
810 c.def("__len__", &PyDenseElementsAttribute::dunderLen);
812 c.def_prop_ro("is_splat",
813 [](PyDenseElementsAttribute &self) -> bool {
814 return mlirDenseElementsAttrIsSplat(self);
815 })
816 .def("get_splat_value",
818 -> nb::typed<nb::object, PyAttribute> {
820 throw nb::value_error(
821 "get_splat_value called on a non-splat attribute");
822 return PyAttribute(self.getContext(),
824 .maybeDownCast();
825 });
826}
827
828bool PyDenseElementsAttribute::isUnsignedIntegerFormat(
829 std::string_view format) {
830 if (format.empty())
831 return false;
832 char code = format[0];
833 return code == 'I' || code == 'B' || code == 'H' || code == 'L' ||
834 code == 'Q';
835}
836
837bool PyDenseElementsAttribute::isSignedIntegerFormat(std::string_view format) {
838 if (format.empty())
839 return false;
840 char code = format[0];
841 return code == 'i' || code == 'b' || code == 'h' || code == 'l' ||
842 code == 'q';
843}
844
845MlirType PyDenseElementsAttribute::getShapedType(
846 std::optional<MlirType> bulkLoadElementType,
847 std::optional<std::vector<int64_t>> explicitShape, Py_buffer &view) {
848 std::vector<int64_t> shape;
849 if (explicitShape) {
850 shape.insert(shape.end(), explicitShape->begin(), explicitShape->end());
851 } else {
852 shape.insert(shape.end(), view.shape, view.shape + view.ndim);
853 }
854
855 if (mlirTypeIsAShaped(*bulkLoadElementType)) {
856 if (explicitShape) {
857 throw std::invalid_argument("Shape can only be specified explicitly "
858 "when the type is not a shaped type.");
859 }
860 return *bulkLoadElementType;
861 }
862 MlirAttribute encodingAttr = mlirAttributeGetNull();
863 return mlirRankedTensorTypeGet(shape.size(), shape.data(),
864 *bulkLoadElementType, encodingAttr);
865}
866
867MlirAttribute PyDenseElementsAttribute::getAttributeFromBuffer(
868 Py_buffer &view, bool signless, std::optional<PyType> explicitType,
869 const std::optional<std::vector<int64_t>> &explicitShape,
870 MlirContext &context) {
871 // Detect format codes that are suitable for bulk loading. This includes
872 // all byte aligned integer and floating point types up to 8 bytes.
873 // Notably, this excludes exotics types which do not have a direct
874 // representation in the buffer protocol (i.e. complex, etc).
875 std::optional<MlirType> bulkLoadElementType;
876 if (explicitType) {
877 bulkLoadElementType = *explicitType;
878 } else {
879 std::string_view format(view.format);
880 if (format == "f") {
881 // f32
882 assert(view.itemsize == 4 && "mismatched array itemsize");
883 bulkLoadElementType = mlirF32TypeGet(context);
884 } else if (format == "d") {
885 // f64
886 assert(view.itemsize == 8 && "mismatched array itemsize");
887 bulkLoadElementType = mlirF64TypeGet(context);
888 } else if (format == "e") {
889 // f16
890 assert(view.itemsize == 2 && "mismatched array itemsize");
891 bulkLoadElementType = mlirF16TypeGet(context);
892 } else if (format == "?") {
893 // i1
894 bulkLoadElementType = mlirIntegerTypeGet(context, 1);
895 } else if (isSignedIntegerFormat(format)) {
896 if (view.itemsize == 4) {
897 // i32
898 bulkLoadElementType = signless ? mlirIntegerTypeGet(context, 32)
899 : mlirIntegerTypeSignedGet(context, 32);
900 } else if (view.itemsize == 8) {
901 // i64
902 bulkLoadElementType = signless ? mlirIntegerTypeGet(context, 64)
903 : mlirIntegerTypeSignedGet(context, 64);
904 } else if (view.itemsize == 1) {
905 // i8
906 bulkLoadElementType = signless ? mlirIntegerTypeGet(context, 8)
907 : mlirIntegerTypeSignedGet(context, 8);
908 } else if (view.itemsize == 2) {
909 // i16
910 bulkLoadElementType = signless ? mlirIntegerTypeGet(context, 16)
911 : mlirIntegerTypeSignedGet(context, 16);
912 }
913 } else if (isUnsignedIntegerFormat(format)) {
914 if (view.itemsize == 4) {
915 // unsigned i32
916 bulkLoadElementType = signless
917 ? mlirIntegerTypeGet(context, 32)
918 : mlirIntegerTypeUnsignedGet(context, 32);
919 } else if (view.itemsize == 8) {
920 // unsigned i64
921 bulkLoadElementType = signless
922 ? mlirIntegerTypeGet(context, 64)
923 : mlirIntegerTypeUnsignedGet(context, 64);
924 } else if (view.itemsize == 1) {
925 // i8
926 bulkLoadElementType = signless ? mlirIntegerTypeGet(context, 8)
927 : mlirIntegerTypeUnsignedGet(context, 8);
928 } else if (view.itemsize == 2) {
929 // i16
930 bulkLoadElementType = signless
931 ? mlirIntegerTypeGet(context, 16)
932 : mlirIntegerTypeUnsignedGet(context, 16);
933 }
934 }
935 if (!bulkLoadElementType) {
936 throw std::invalid_argument(
937 std::string("unimplemented array format conversion from format: ") +
938 std::string(format));
939 }
940 }
941
942 MlirType type = getShapedType(bulkLoadElementType, explicitShape, view);
943 return mlirDenseElementsAttrRawBufferGet(type, view.len, view.buf);
944}
945
946PyType_Slot PyDenseElementsAttribute::slots[] = {
947 {Py_bf_getbuffer,
948 reinterpret_cast<void *>(PyDenseElementsAttribute::bf_getbuffer)},
949 {Py_bf_releasebuffer,
950 reinterpret_cast<void *>(PyDenseElementsAttribute::bf_releasebuffer)},
951 {0, nullptr},
952};
953
954/*static*/ int PyDenseElementsAttribute::bf_getbuffer(PyObject *obj,
955 Py_buffer *view,
956 int flags) {
957 view->obj = nullptr;
958 std::unique_ptr<nb_buffer_info> info;
959 try {
960 auto *attr = nb::cast<PyDenseElementsAttribute *>(nb::handle(obj));
961 info = attr->accessBuffer();
962 } catch (nb::python_error &e) {
963 e.restore();
964 nb::chain_error(PyExc_BufferError, "Error converting attribute to buffer");
965 return -1;
966 } catch (std::exception &e) {
967 nb::chain_error(PyExc_BufferError,
968 "Error converting attribute to buffer: %s", e.what());
969 return -1;
970 }
971 view->obj = obj;
972 view->ndim = 1;
973 view->buf = info->ptr;
974 view->itemsize = info->itemsize;
975 view->len = info->itemsize;
976 for (auto s : info->shape) {
977 view->len *= s;
978 }
979 view->readonly = info->readonly;
980 if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) {
981 view->format = const_cast<char *>(info->format);
982 }
983 if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) {
984 view->ndim = static_cast<int>(info->ndim);
985 view->strides = info->strides.data();
986 view->shape = info->shape.data();
987 }
988 view->suboffsets = nullptr;
989 view->internal = info.release();
990 Py_INCREF(obj);
991 return 0;
992}
993
994/*static*/ void PyDenseElementsAttribute::bf_releasebuffer(PyObject *,
995 Py_buffer *view) {
996 delete reinterpret_cast<nb_buffer_info *>(view->internal);
997}
998
1000 if (pos < 0 || pos >= dunderLen()) {
1001 throw nb::index_error("attempt to access out of bounds element");
1002 }
1003
1004 MlirType type = mlirAttributeGetType(*this);
1005 type = mlirShapedTypeGetElementType(type);
1006 // Index type can also appear as a DenseIntElementsAttr and therefore can be
1007 // casted to integer.
1008 assert(mlirTypeIsAInteger(type) ||
1009 mlirTypeIsAIndex(type) && "expected integer/index element type in "
1010 "dense int elements attribute");
1011 // Dispatch element extraction to an appropriate C function based on the
1012 // elemental type of the attribute. nb::int_ is implicitly
1013 // constructible from any C++ integral type and handles bitwidth correctly.
1014 // TODO: consider caching the type properties in the constructor to avoid
1015 // querying them on each element access.
1016 if (mlirTypeIsAIndex(type)) {
1017 return nb::int_(mlirDenseElementsAttrGetIndexValue(*this, pos));
1018 }
1019 unsigned width = mlirIntegerTypeGetWidth(type);
1020 bool isUnsigned = mlirIntegerTypeIsUnsigned(type);
1021 if (isUnsigned) {
1022 if (width == 1) {
1023 return nb::int_(int(mlirDenseElementsAttrGetBoolValue(*this, pos)));
1024 }
1025 if (width == 8) {
1026 return nb::int_(mlirDenseElementsAttrGetUInt8Value(*this, pos));
1027 }
1028 if (width == 16) {
1029 return nb::int_(mlirDenseElementsAttrGetUInt16Value(*this, pos));
1030 }
1031 if (width == 32) {
1032 return nb::int_(mlirDenseElementsAttrGetUInt32Value(*this, pos));
1033 }
1034 if (width == 64) {
1035 return nb::int_(mlirDenseElementsAttrGetUInt64Value(*this, pos));
1036 }
1037 } else {
1038 if (width == 1) {
1039 return nb::int_(int(mlirDenseElementsAttrGetBoolValue(*this, pos)));
1040 }
1041 if (width == 8) {
1042 return nb::int_(mlirDenseElementsAttrGetInt8Value(*this, pos));
1043 }
1044 if (width == 16) {
1045 return nb::int_(mlirDenseElementsAttrGetInt16Value(*this, pos));
1046 }
1047 if (width == 32) {
1048 return nb::int_(mlirDenseElementsAttrGetInt32Value(*this, pos));
1049 }
1050 if (width == 64) {
1051 return nb::int_(mlirDenseElementsAttrGetInt64Value(*this, pos));
1052 }
1053 }
1054 throw nb::type_error("Unsupported integer type");
1055}
1056
1061
1062// Py_IsFinalizing is part of the stable ABI since 3.13. Before that, it was
1063// available as the private _Py_IsFinalizing, which is not part of the limited
1064// API.
1065#if defined(Py_LIMITED_API) && Py_LIMITED_API < 0x030d0000
1066// Under limited API targeting < 3.13, use sys.is_finalizing() via C API.
1067// PySys_GetObject avoids import machinery (safe during finalization).
1068static int Py_IsFinalizing(void) {
1069 // PySys_GetObject returns a borrowed reference; no Py_DECREF needed.
1070 PyObject *fn = PySys_GetObject("is_finalizing");
1071 if (!fn)
1072 return 0;
1073 PyObject *result = PyObject_CallNoArgs(fn);
1074 if (!result) {
1075 PyErr_Clear();
1076 return 0;
1077 }
1078 int val = PyObject_IsTrue(result);
1079 Py_DECREF(result);
1080 return val > 0 ? 1 : 0;
1081}
1082#elif PY_VERSION_HEX < 0x030d0000
1083#define Py_IsFinalizing _Py_IsFinalizing
1084#endif
1085
1088 const nb_buffer &buffer, const std::string &name, const PyType &type,
1089 std::optional<size_t> alignment, bool isMutable,
1090 DefaultingPyMlirContext contextWrapper) {
1091 if (!mlirTypeIsAShaped(type)) {
1092 throw std::invalid_argument(
1093 "Constructing a DenseResourceElementsAttr requires a ShapedType.");
1094 }
1095
1096 // Do not request any conversions as we must ensure to use caller
1097 // managed memory.
1098 int flags = PyBUF_STRIDES;
1099 std::unique_ptr<Py_buffer> view = std::make_unique<Py_buffer>();
1100 if (PyObject_GetBuffer(buffer.ptr(), view.get(), flags) != 0) {
1101 throw nb::python_error();
1102 }
1103
1104 // This scope releaser will only release if we haven't yet transferred
1105 // ownership.
1106 scope_exit freeBuffer([&]() {
1107 if (view)
1108 PyBuffer_Release(view.get());
1109 });
1110
1111 if (!PyBuffer_IsContiguous(view.get(), 'A')) {
1112 throw std::invalid_argument("Contiguous buffer is required.");
1113 }
1114
1115 // Infer alignment to be the stride of one element if not explicit.
1116 size_t inferredAlignment;
1117 if (alignment)
1118 inferredAlignment = *alignment;
1119 else if (view->ndim == 0)
1120 inferredAlignment = view->itemsize;
1121 else
1122 inferredAlignment = view->strides[view->ndim - 1];
1123
1124 // The userData is a Py_buffer* that the deleter owns.
1125 auto deleter = [](void *userData, const void *data, size_t size,
1126 size_t align) {
1127 if (Py_IsFinalizing())
1128 return;
1129 assert(Py_IsInitialized() && "expected interpreter to be initialized");
1130 Py_buffer *ownedView = static_cast<Py_buffer *>(userData);
1131 nb::gil_scoped_acquire gil;
1132 PyBuffer_Release(ownedView);
1133 delete ownedView;
1134 };
1135
1136 size_t rawBufferSize = view->len;
1137 MlirAttribute attr = mlirUnmanagedDenseResourceElementsAttrGet(
1138 type, toMlirStringRef(name), view->buf, rawBufferSize, inferredAlignment,
1139 isMutable, deleter, static_cast<void *>(view.get()));
1140 if (mlirAttributeIsNull(attr)) {
1141 throw std::invalid_argument(
1142 "DenseResourceElementsAttr could not be constructed from the given "
1143 "buffer. "
1144 "This may mean that the Python buffer layout does not match that "
1145 "MLIR expected layout and is a bug.");
1146 }
1147 view.release();
1148 return PyDenseResourceElementsAttribute(contextWrapper->getRef(), attr);
1149}
1150
1152 c.def_static(
1154 nb::arg("array"), nb::arg("name"), nb::arg("type"),
1155 nb::arg("alignment") = nb::none(), nb::arg("is_mutable") = false,
1156 nb::arg("context") = nb::none(),
1157 // clang-format off
1158 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"),
1159 // clang-format on
1161}
1162
1166
1167bool PyDictAttribute::dunderContains(const std::string &name) const {
1168 return !mlirAttributeIsNull(
1170}
1171
1173 c.def("__contains__", &PyDictAttribute::dunderContains);
1174 c.def("__len__", &PyDictAttribute::dunderLen);
1175 c.def_static(
1176 "get",
1177 [](const nb::dict &attributes, DefaultingPyMlirContext context) {
1178 std::vector<MlirNamedAttribute> mlirNamedAttributes;
1179 mlirNamedAttributes.reserve(attributes.size());
1180 for (std::pair<nb::handle, nb::handle> it : attributes) {
1181 auto &mlirAttr = nb::cast<PyAttribute &>(it.second);
1182 auto name = nb::cast<std::string>(it.first);
1183 mlirNamedAttributes.push_back(mlirNamedAttributeGet(
1186 mlirAttr));
1187 }
1188 MlirAttribute attr =
1189 mlirDictionaryAttrGet(context->get(), mlirNamedAttributes.size(),
1190 mlirNamedAttributes.data());
1191 return PyDictAttribute(context->getRef(), attr);
1192 },
1193 nb::arg("value") = nb::dict(), nb::arg("context") = nb::none(),
1194 "Gets an uniqued dict attribute");
1195 c.def("__getitem__",
1196 [](PyDictAttribute &self,
1197 const std::string &name) -> nb::typed<nb::object, PyAttribute> {
1198 MlirAttribute attr =
1200 if (mlirAttributeIsNull(attr))
1201 throw nb::key_error("attempt to access a non-existent attribute");
1202 return PyAttribute(self.getContext(), attr).maybeDownCast();
1203 });
1204 c.def("__getitem__", [](PyDictAttribute &self, intptr_t index) {
1205 if (index < 0 || index >= self.dunderLen()) {
1206 throw nb::index_error("attempt to access out of bounds attribute");
1207 }
1209 return PyNamedAttribute(
1210 namedAttr.attribute,
1211 std::string(mlirIdentifierStr(namedAttr.name).data));
1212 });
1213}
1214
1216 if (pos < 0 || pos >= dunderLen()) {
1217 throw nb::index_error("attempt to access out of bounds element");
1218 }
1219
1220 MlirType type = mlirAttributeGetType(*this);
1221 type = mlirShapedTypeGetElementType(type);
1222 // Dispatch element extraction to an appropriate C function based on the
1223 // elemental type of the attribute. nb::float_ is implicitly
1224 // constructible from float and double.
1225 // TODO: consider caching the type properties in the constructor to avoid
1226 // querying them on each element access.
1227 if (mlirTypeIsAF32(type)) {
1228 return nb::float_(mlirDenseElementsAttrGetFloatValue(*this, pos));
1229 }
1230 if (mlirTypeIsAF64(type)) {
1231 return nb::float_(mlirDenseElementsAttrGetDoubleValue(*this, pos));
1232 }
1233 throw nb::type_error("Unsupported floating-point type");
1234}
1235
1240
1242 c.def_static(
1243 "get",
1244 [](const PyType &value, DefaultingPyMlirContext context) {
1245 MlirAttribute attr = mlirTypeAttrGet(value.get());
1246 return PyTypeAttribute(context->getRef(), attr);
1247 },
1248 nb::arg("value"), nb::arg("context") = nb::none(),
1249 "Gets a uniqued Type attribute");
1250 c.def_prop_ro(
1251 "value", [](PyTypeAttribute &self) -> nb::typed<nb::object, PyType> {
1252 return PyType(self.getContext(), mlirTypeAttrGetValue(self.get()))
1253 .maybeDownCast();
1254 });
1255}
1256
1258 c.def_static(
1259 "get",
1260 [](DefaultingPyMlirContext context) {
1261 return PyUnitAttribute(context->getRef(),
1262 mlirUnitAttrGet(context->get()));
1263 },
1264 nb::arg("context") = nb::none(), "Create a Unit attribute.");
1265}
1266
1268 c.def_static(
1269 "get",
1270 [](int64_t offset, const std::vector<int64_t> &strides,
1272 MlirAttribute attr = mlirStridedLayoutAttrGet(
1273 ctx->get(), offset, strides.size(), strides.data());
1274 return PyStridedLayoutAttribute(ctx->getRef(), attr);
1275 },
1276 nb::arg("offset"), nb::arg("strides"), nb::arg("context") = nb::none(),
1277 "Gets a strided layout attribute.");
1278 c.def_static(
1279 "get_fully_dynamic",
1280 [](int64_t rank, DefaultingPyMlirContext ctx) {
1282 std::vector<int64_t> strides(rank);
1283 std::fill(strides.begin(), strides.end(), dynamic);
1284 MlirAttribute attr = mlirStridedLayoutAttrGet(
1285 ctx->get(), dynamic, strides.size(), strides.data());
1286 return PyStridedLayoutAttribute(ctx->getRef(), attr);
1287 },
1288 nb::arg("rank"), nb::arg("context") = nb::none(),
1289 "Gets a strided layout attribute with dynamic offset and strides of "
1290 "a "
1291 "given rank.");
1292 c.def_prop_ro(
1293 "offset",
1294 [](PyStridedLayoutAttribute &self) {
1295 return mlirStridedLayoutAttrGetOffset(self);
1296 },
1297 "Returns the value of the float point attribute");
1298 c.def_prop_ro(
1299 "strides",
1300 [](PyStridedLayoutAttribute &self) {
1302 std::vector<int64_t> strides(size);
1303 for (intptr_t i = 0; i < size; i++) {
1304 strides[i] = mlirStridedLayoutAttrGetStride(self, i);
1305 }
1306 return strides;
1307 },
1308 "Returns the value of the float point attribute");
1309}
1310
1311nb::object denseArrayAttributeCaster(PyAttribute &pyAttribute) {
1313 return nb::cast(PyDenseBoolArrayAttribute(pyAttribute));
1314 if (PyDenseI8ArrayAttribute::isaFunction(pyAttribute))
1315 return nb::cast(PyDenseI8ArrayAttribute(pyAttribute));
1317 return nb::cast(PyDenseI16ArrayAttribute(pyAttribute));
1319 return nb::cast(PyDenseI32ArrayAttribute(pyAttribute));
1321 return nb::cast(PyDenseI64ArrayAttribute(pyAttribute));
1323 return nb::cast(PyDenseF32ArrayAttribute(pyAttribute));
1325 return nb::cast(PyDenseF64ArrayAttribute(pyAttribute));
1326 std::string msg =
1327 std::string("Can't cast unknown element type DenseArrayAttr (") +
1328 nb::cast<std::string>(nb::repr(nb::cast(pyAttribute))) + ")";
1329 throw nb::type_error(msg.c_str());
1330}
1331
1334 return nb::cast(PyDenseFPElementsAttribute(pyAttribute));
1336 return nb::cast(PyDenseIntElementsAttribute(pyAttribute));
1337 std::string msg =
1338 std::string(
1339 "Can't cast unknown element type DenseIntOrFPElementsAttr (") +
1340 nb::cast<std::string>(nb::repr(nb::cast(pyAttribute))) + ")";
1341 throw nb::type_error(msg.c_str());
1342}
1343
1345 if (PyBoolAttribute::isaFunction(pyAttribute))
1346 return nb::cast(PyBoolAttribute(pyAttribute));
1347 if (PyIntegerAttribute::isaFunction(pyAttribute))
1348 return nb::cast(PyIntegerAttribute(pyAttribute));
1349 std::string msg = std::string("Can't cast unknown attribute type Attr (") +
1350 nb::cast<std::string>(nb::repr(nb::cast(pyAttribute))) +
1351 ")";
1352 throw nb::type_error(msg.c_str());
1353}
1354
1357 return nb::cast(PyFlatSymbolRefAttribute(pyAttribute));
1358 if (PySymbolRefAttribute::isaFunction(pyAttribute))
1359 return nb::cast(PySymbolRefAttribute(pyAttribute));
1360 std::string msg = std::string("Can't cast unknown SymbolRef attribute (") +
1361 nb::cast<std::string>(nb::repr(nb::cast(pyAttribute))) +
1362 ")";
1363 throw nb::type_error(msg.c_str());
1364}
1365
1367 c.def_static(
1368 "get",
1369 [](const std::string &value, DefaultingPyMlirContext context) {
1370 MlirAttribute attr =
1371 mlirStringAttrGet(context->get(), toMlirStringRef(value));
1372 return PyStringAttribute(context->getRef(), attr);
1373 },
1374 nb::arg("value"), nb::arg("context") = nb::none(),
1375 "Gets a uniqued string attribute");
1376 c.def_static(
1377 "get",
1378 [](const nb::bytes &value, DefaultingPyMlirContext context) {
1379 MlirAttribute attr =
1380 mlirStringAttrGet(context->get(), toMlirStringRef(value));
1381 return PyStringAttribute(context->getRef(), attr);
1382 },
1383 nb::arg("value"), nb::arg("context") = nb::none(),
1384 "Gets a uniqued string attribute");
1385 c.def_static(
1386 "get_typed",
1387 [](PyType &type, const std::string &value) {
1388 MlirAttribute attr =
1390 return PyStringAttribute(type.getContext(), attr);
1391 },
1392 nb::arg("type"), nb::arg("value"),
1393 "Gets a uniqued string attribute associated to a type");
1394 c.def_prop_ro(
1395 "value",
1396 [](PyStringAttribute &self) {
1397 MlirStringRef stringRef = mlirStringAttrGetValue(self);
1398 return nb::str(stringRef.data, stringRef.length);
1399 },
1400 "Returns the value of the string attribute");
1401 c.def_prop_ro(
1402 "value_bytes",
1403 [](PyStringAttribute &self) {
1404 MlirStringRef stringRef = mlirStringAttrGetValue(self);
1405 return nb::bytes(stringRef.data, stringRef.length);
1406 },
1407 "Returns the value of the string attribute as `bytes`");
1408}
1409
1410static MlirDynamicAttrDefinition
1411getDynamicAttrDef(const std::string &fullAttrName,
1412 DefaultingPyMlirContext context) {
1413 size_t dotPos = fullAttrName.find('.');
1414 if (dotPos == std::string::npos) {
1415 throw nb::value_error("Expected full attribute name to be in the format "
1416 "'<dialectName>.<attributeName>'.");
1417 }
1418
1419 std::string dialectName = fullAttrName.substr(0, dotPos);
1420 std::string attrName = fullAttrName.substr(dotPos + 1);
1421 PyDialects dialects(context->getRef());
1422 MlirDialect dialect = dialects.getDialectForKey(dialectName, false);
1423 if (!mlirDialectIsAExtensibleDialect(dialect))
1424 throw nb::value_error(
1425 ("Dialect '" + dialectName + "' is not an extensible dialect.")
1426 .c_str());
1427
1428 MlirDynamicAttrDefinition attrDef = mlirExtensibleDialectLookupAttrDefinition(
1429 dialect, toMlirStringRef(attrName));
1430 if (attrDef.ptr == nullptr) {
1431 throw nb::value_error(("Dialect '" + dialectName +
1432 "' does not contain an attribute named '" +
1433 attrName + "'.")
1434 .c_str());
1435 }
1436 return attrDef;
1437}
1438
1440 c.def_static(
1441 "get",
1442 [](const std::string &fullAttrName, const std::vector<PyAttribute> &attrs,
1443 DefaultingPyMlirContext context) {
1444 std::vector<MlirAttribute> mlirAttrs;
1445 mlirAttrs.reserve(attrs.size());
1446 for (const auto &attr : attrs)
1447 mlirAttrs.push_back(attr.get());
1448
1449 MlirDynamicAttrDefinition attrDef =
1450 getDynamicAttrDef(fullAttrName, context);
1451 MlirAttribute attr =
1452 mlirDynamicAttrGet(attrDef, mlirAttrs.data(), mlirAttrs.size());
1453 return PyDynamicAttribute(context->getRef(), attr);
1454 },
1455 nb::arg("full_attr_name"), nb::arg("attributes"),
1456 nb::arg("context") = nb::none(), "Create a dynamic attribute.");
1457 c.def_prop_ro(
1458 "params",
1459 [](PyDynamicAttribute &self) {
1460 size_t numParams = mlirDynamicAttrGetNumParams(self);
1461 std::vector<PyAttribute> params;
1462 params.reserve(numParams);
1463 for (size_t i = 0; i < numParams; ++i)
1464 params.emplace_back(self.getContext(),
1465 mlirDynamicAttrGetParam(self, i));
1466 return params;
1467 },
1468 "Returns the parameters of the dynamic attribute as a list of "
1469 "attributes.");
1470 c.def_prop_ro("attr_name", [](PyDynamicAttribute &self) {
1471 MlirDynamicAttrDefinition attrDef = mlirDynamicAttrGetAttrDef(self);
1473 MlirDialect dialect = mlirDynamicAttrDefinitionGetDialect(attrDef);
1474 MlirStringRef dialectNamespace = mlirDialectGetNamespace(dialect);
1475 return std::string(dialectNamespace.data, dialectNamespace.length) + "." +
1476 std::string(name.data, name.length);
1477 });
1478 c.def_static(
1479 "lookup_typeid",
1480 [](const std::string &fullAttrName, DefaultingPyMlirContext context) {
1481 MlirDynamicAttrDefinition attrDef =
1482 getDynamicAttrDef(fullAttrName, context);
1484 },
1485 nb::arg("full_attr_name"), nb::arg("context") = nb::none(),
1486 "Look up the TypeID for the given dynamic attribute name.");
1487}
1488
1489void populateIRAttributes(nb::module_ &m) {
1492 PyDenseBoolArrayAttribute::PyDenseArrayIterator::bind(m);
1494 PyDenseI8ArrayAttribute::PyDenseArrayIterator::bind(m);
1496 PyDenseI16ArrayAttribute::PyDenseArrayIterator::bind(m);
1498 PyDenseI32ArrayAttribute::PyDenseArrayIterator::bind(m);
1500 PyDenseI64ArrayAttribute::PyDenseArrayIterator::bind(m);
1502 PyDenseF32ArrayAttribute::PyDenseArrayIterator::bind(m);
1504 PyDenseF64ArrayAttribute::PyDenseArrayIterator::bind(m);
1507 nb::cast<nb::callable>(nb::cpp_function(denseArrayAttributeCaster)));
1508
1517 nb::cast<nb::callable>(
1518 nb::cpp_function(denseIntOrFPElementsAttributeCaster)));
1520
1525 nb::cast<nb::callable>(
1526 nb::cpp_function(symbolRefOrFlatSymbolRefAttributeCaster)));
1527
1537 nb::cast<nb::callable>(nb::cpp_function(integerOrBoolAttributeCaster)));
1539
1542}
1543} // namespace MLIR_BINDINGS_PYTHON_DOMAIN
1544} // namespace python
1545} // namespace mlir
#define Py_IsFinalizing
static const char kDenseElementsAttrGetDocstring[]
static const char kDenseResourceElementsAttrGetFromBufferDocstring[]
static const char kDenseElementsAttrGetFromListDocstring[]
MlirContext mlirAttributeGetContext(MlirAttribute attribute)
Definition IR.cpp:1284
MlirType mlirAttributeGetType(MlirAttribute attribute)
Definition IR.cpp:1288
ReferrentTy * get() const
PyMlirContextRef & getContext()
Accesses the context reference.
Definition IRCore.h:297
Used in function arguments when None should resolve to the current context manager set instance.
Definition IRCore.h:524
Used in function arguments when None should resolve to the current context manager set instance.
Definition IRCore.h:278
Wrapper around the generic MlirAttribute.
Definition IRCore.h:1001
PyAttribute(PyMlirContextRef contextRef, MlirAttribute attr)
Definition IRCore.h:1003
static void bind(nanobind::module_ &m, PyType_Slot *slots=nullptr)
Definition IRCore.h:1083
nanobind::class_< PyAffineMapAttribute, PyAttribute > ClassTy
Definition IRCore.h:1058
static void bindFactoryMethods(ClassT &c, const char *pyClassName)
Registers get/get_splat factory methods with the concrete return type in the nb::sig.
static PyDenseElementsAttribute getSplat(const PyType &shapedType, PyAttribute &elementAttr)
static PyDenseElementsAttribute getFromList(const nanobind::list &attributes, std::optional< PyType > explicitType, DefaultingPyMlirContext contextWrapper)
static PyDenseElementsAttribute getFromBuffer(const nb_buffer &array, bool signless, const std::optional< PyType > &explicitType, std::optional< std::vector< int64_t > > explicitShape, DefaultingPyMlirContext contextWrapper)
Refinement of PyDenseElementsAttribute for attributes containing floating-point values.
Refinement of the PyDenseElementsAttribute for attributes containing integer (and boolean) values.
nanobind::int_ dunderGetItem(intptr_t pos) const
Returns the element at the given linear position.
static PyDenseResourceElementsAttribute getFromBuffer(const nb_buffer &buffer, const std::string &name, const PyType &type, std::optional< size_t > alignment, bool isMutable, DefaultingPyMlirContext contextWrapper)
User-level object for accessing dialects with dotted syntax such as: ctx.dialect.std.
Definition IRCore.h:473
MlirDialect getDialectForKey(const std::string &key, bool attrError)
Definition IRCore.cpp:820
Float Point Attribute subclass - FloatAttr.
static PyGlobals & get()
Most code should get the globals via this static accessor.
Definition Globals.cpp:59
void registerTypeCaster(MlirTypeID mlirTypeID, nanobind::callable typeCaster, bool replace=false)
Adds a user-friendly type caster.
Definition Globals.cpp:112
static PyMlirContextRef forContext(MlirContext context)
Returns a context reference for the singleton PyMlirContext wrapper for the given context.
Definition IRCore.cpp:486
MlirContext get()
Accesses the underlying MlirContext.
Definition IRCore.h:211
PyMlirContextRef getRef()
Gets a strong reference to this context, which will ensure it is kept alive for the life of the refer...
Definition IRCore.cpp:471
Represents a Python MlirNamedAttr, carrying an optional owned name.
Definition IRCore.h:1027
static PySymbolRefAttribute fromList(const std::vector< std::string > &symbols, PyMlirContext &context)
A TypeID provides an efficient and unique identifier for a specific C++ type.
Definition IRCore.h:900
Wrapper around the generic MlirType.
Definition IRCore.h:874
nanobind::typed< nanobind::object, PyType > maybeDownCast()
Definition IRCore.cpp:1942
Unit Attribute subclass. Unit attributes don't have values.
MLIR_CAPI_EXPORTED MlirAttribute mlirAffineMapAttrGet(MlirAffineMap map)
Creates an affine map attribute wrapping the given map.
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 uint8_t mlirDenseElementsAttrGetUInt8Value(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED int64_t mlirStridedLayoutAttrGetOffset(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 unsigned mlirIntegerAttrGetValueNumWords(MlirAttribute attr)
Returns the number of 64-bit words that make up the integer attribute's underlying APInt value.
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 uint64_t mlirDenseElementsAttrGetIndexValue(MlirAttribute attr, intptr_t pos)
MLIR_CAPI_EXPORTED MlirTypeID mlirIntegerAttrGetTypeID(void)
Returns the typeID of an Integer attribute.
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 MlirTypeID mlirDenseIntOrFPElementsAttrGetTypeID(void)
Returns the typeID of an DenseIntOrFPElements 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 MlirAttribute mlirIntegerAttrGet(MlirType type, int64_t value)
Creates an integer attribute of the given type with the given integer value.
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 MlirAttribute mlirSymbolRefAttrGetNestedReference(MlirAttribute attr, intptr_t pos)
Returns pos-th reference nested in the given symbol reference attribute.
MLIR_CAPI_EXPORTED void mlirIntegerAttrGetValueWords(MlirAttribute attr, uint64_t *words)
Copies the 64-bit words making up the integer attribute's APInt value into the provided buffer.
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 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 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 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 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 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 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 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 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 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 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 MlirAttribute mlirDenseElementsAttrSplatGet(MlirType shapedType, MlirAttribute element)
Creates a dense elements attribute with the given Shaped type containing a single replicated element ...
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 unsigned mlirIntegerAttrGetValueBitWidth(MlirAttribute attr)
Returns the bit width of the integer attribute's underlying APInt value.
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 MlirAttribute mlirStringAttrTypedGet(MlirType type, MlirStringRef str)
Creates a string attribute in the given context containing the given string.
MLIR_CAPI_EXPORTED MlirAttribute mlirIntegerAttrGetFromWords(MlirType type, unsigned numWords, const uint64_t *words)
Creates an integer attribute of the given type from an array of 64-bit words.
MLIR_CAPI_EXPORTED MlirStringRef mlirFlatSymbolRefAttrGetValue(MlirAttribute attr)
Returns the referenced symbol as a string reference.
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 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 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.
MLIR_CAPI_EXPORTED MlirAttribute mlirDynamicAttrGetParam(MlirAttribute attr, intptr_t index)
Get the parameter at the given index in the provided dynamic attribute.
MLIR_CAPI_EXPORTED MlirDialect mlirDynamicAttrDefinitionGetDialect(MlirDynamicAttrDefinition attrDef)
Get the dialect that the given dynamic attribute definition belongs to.
MLIR_CAPI_EXPORTED MlirAttribute mlirDynamicAttrGet(MlirDynamicAttrDefinition attrDef, MlirAttribute *attrs, intptr_t numAttrs)
Get a dynamic attribute by instantiating the given attribute definition with the provided attributes.
MLIR_CAPI_EXPORTED bool mlirDialectIsAExtensibleDialect(MlirDialect dialect)
Check if the given dialect is an extensible dialect.
MLIR_CAPI_EXPORTED MlirDynamicAttrDefinition mlirDynamicAttrGetAttrDef(MlirAttribute attr)
Get the attribute definition of the given dynamic attribute.
MLIR_CAPI_EXPORTED MlirDynamicAttrDefinition mlirExtensibleDialectLookupAttrDefinition(MlirDialect dialect, MlirStringRef attrName)
Look up a registered attribute definition by attribute name in the given dialect.
MLIR_CAPI_EXPORTED MlirTypeID mlirDynamicAttrDefinitionGetTypeID(MlirDynamicAttrDefinition attrDef)
Get the type ID of a dynamic attribute definition.
MLIR_CAPI_EXPORTED MlirStringRef mlirDynamicAttrDefinitionGetName(MlirDynamicAttrDefinition attrDef)
Get the name of the given dynamic attribute definition.
MLIR_CAPI_EXPORTED intptr_t mlirDynamicAttrGetNumParams(MlirAttribute attr)
Get the number of parameters in the given dynamic attribute.
MLIR_CAPI_EXPORTED MlirStringRef mlirDialectGetNamespace(MlirDialect dialect)
Returns the namespace of the given dialect.
Definition IR.cpp:136
MLIR_CAPI_EXPORTED MlirNamedAttribute mlirNamedAttributeGet(MlirIdentifier name, MlirAttribute attr)
Associates an attribute with the name. Takes ownership of neither.
Definition IR.cpp:1315
MLIR_CAPI_EXPORTED MlirStringRef mlirIdentifierStr(MlirIdentifier ident)
Gets the string value of the identifier.
Definition IR.cpp:1336
MLIR_CAPI_EXPORTED MlirContext mlirTypeGetContext(MlirType type)
Gets the context that a type was created with.
Definition IR.cpp:1253
MLIR_CAPI_EXPORTED bool mlirTypeEqual(MlirType t1, MlirType t2)
Checks if two types are equal.
Definition IR.cpp:1265
MLIR_CAPI_EXPORTED MlirIdentifier mlirIdentifierGet(MlirContext context, MlirStringRef str)
Gets an identifier with the given string value.
Definition IR.cpp:1324
nb::object denseIntOrFPElementsAttributeCaster(PyAttribute &pyAttribute)
nb::object symbolRefOrFlatSymbolRefAttributeCaster(PyAttribute &pyAttribute)
nb::object integerOrBoolAttributeCaster(PyAttribute &pyAttribute)
MlirStringRef toMlirStringRef(const std::string &s)
Definition IRCore.h:1330
static T pyTryCast(nanobind::handle object)
nb::object denseArrayAttributeCaster(PyAttribute &pyAttribute)
static MlirDynamicAttrDefinition getDynamicAttrDef(const std::string &fullAttrName, DefaultingPyMlirContext context)
MLIR_PYTHON_API_EXPORTED void populateIRAttributes(nanobind::module_ &m)
Include the generated interface declarations.
std::string join(const Ts &...args)
Helper function to concatenate arguments into a std::string.
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:78
const char * data
Pointer to the first symbol.
Definition Support.h:79
size_t length
Length of the fragment.
Definition Support.h:80
Custom exception that allows access to error diagnostic information.
Definition IRCore.h:1317
RAII object that captures any error diagnostics emitted to the provided context.
Definition IRCore.h:433
std::vector< PyDiagnostic::DiagnosticInfo > take()
Definition IRCore.h:443
nb_buffer_info(void *ptr, Py_ssize_t itemsize, const char *format, Py_ssize_t ndim, std::vector< Py_ssize_t > shape_in, std::vector< Py_ssize_t > strides_in, bool readonly=false, std::unique_ptr< Py_buffer, void(*)(Py_buffer *)> owned_view_in=std::unique_ptr< Py_buffer, void(*)(Py_buffer *)>(nullptr, nullptr))