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