[Mlir-commits] [mlir] [mlir][llvm] Expose llvm array type to CAPI and Python bindings (PR #185475)

Asher Mancinelli llvmlistbot at llvm.org
Mon Mar 9 15:48:30 PDT 2026


https://github.com/ashermancinelli updated https://github.com/llvm/llvm-project/pull/185475

>From cf83cce1f25ac52e03354ab5506ea3c8e0265481 Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Sat, 7 Mar 2026 09:02:58 -0800
Subject: [PATCH 1/5] [mlir] Expose LLVMArrayType to CAPI+Python

---
 mlir/include/mlir-c/Dialect/LLVM.h       |  8 ++++++
 mlir/lib/Bindings/Python/DialectLLVM.cpp | 31 ++++++++++++++++++++++++
 mlir/lib/CAPI/Dialect/LLVM.cpp           | 12 +++++++++
 mlir/test/CAPI/llvm.c                    |  8 ++++++
 mlir/test/python/dialects/llvm.py        | 24 ++++++++++++++++++
 5 files changed, 83 insertions(+)

diff --git a/mlir/include/mlir-c/Dialect/LLVM.h b/mlir/include/mlir-c/Dialect/LLVM.h
index 7381519881e03..a9ac9a363064c 100644
--- a/mlir/include/mlir-c/Dialect/LLVM.h
+++ b/mlir/include/mlir-c/Dialect/LLVM.h
@@ -39,6 +39,11 @@ MLIR_CAPI_EXPORTED MlirType mlirLLVMVoidTypeGet(MlirContext ctx);
 
 MLIR_CAPI_EXPORTED MlirStringRef mlirLLVMVoidTypeGetName(void);
 
+/// Returns `true` if the type is an LLVM dialect array type.
+MLIR_CAPI_EXPORTED bool mlirTypeIsALLVMArrayType(MlirType type);
+
+MLIR_CAPI_EXPORTED MlirTypeID mlirLLVMArrayTypeGetTypeID(void);
+
 /// Creates an llvm.array type.
 MLIR_CAPI_EXPORTED MlirType mlirLLVMArrayTypeGet(MlirType elementType,
                                                  unsigned numElements);
@@ -48,6 +53,9 @@ MLIR_CAPI_EXPORTED MlirStringRef mlirLLVMArrayTypeGetName(void);
 /// Returns the element type of the llvm.array type.
 MLIR_CAPI_EXPORTED MlirType mlirLLVMArrayTypeGetElementType(MlirType type);
 
+/// Returns the number of elements in the llvm.array type.
+MLIR_CAPI_EXPORTED unsigned mlirLLVMArrayTypeGetNumElements(MlirType type);
+
 /// Creates an llvm.func type.
 MLIR_CAPI_EXPORTED MlirType
 mlirLLVMFunctionTypeGet(MlirType resultType, intptr_t nArgumentTypes,
diff --git a/mlir/lib/Bindings/Python/DialectLLVM.cpp b/mlir/lib/Bindings/Python/DialectLLVM.cpp
index dc06d0a3bf671..a4220780cd338 100644
--- a/mlir/lib/Bindings/Python/DialectLLVM.cpp
+++ b/mlir/lib/Bindings/Python/DialectLLVM.cpp
@@ -160,6 +160,36 @@ struct StructType : PyConcreteType<StructType> {
   }
 };
 
+//===--------------------------------------------------------------------===//
+// ArrayType
+//===--------------------------------------------------------------------===//
+
+struct ArrayType : PyConcreteType<ArrayType> {
+  static constexpr IsAFunctionTy isaFunction = mlirTypeIsALLVMArrayType;
+  static constexpr GetTypeIDFunctionTy getTypeIdFunction =
+      mlirLLVMArrayTypeGetTypeID;
+  static constexpr const char *pyClassName = "ArrayType";
+  static inline const MlirStringRef name = mlirLLVMArrayTypeGetName();
+  using Base::Base;
+
+  static void bindDerived(ClassTy &c) {
+    c.def_static(
+        "get",
+        [](PyType &elementType, unsigned numElements) {
+          return ArrayType(elementType.getContext(),
+                           mlirLLVMArrayTypeGet(elementType, numElements));
+        },
+        "element_type"_a, "num_elements"_a);
+    c.def_prop_ro("element_type",
+                  [](const ArrayType &type) {
+                    return mlirLLVMArrayTypeGetElementType(type);
+                  });
+    c.def_prop_ro("num_elements", [](const ArrayType &type) {
+      return mlirLLVMArrayTypeGetNumElements(type);
+    });
+  }
+};
+
 //===--------------------------------------------------------------------===//
 // PointerType
 //===--------------------------------------------------------------------===//
@@ -196,6 +226,7 @@ struct PointerType : PyConcreteType<PointerType> {
 
 static void populateDialectLLVMSubmodule(nanobind::module_ &m) {
   StructType::bind(m);
+  ArrayType::bind(m);
   PointerType::bind(m);
 
   m.def(
diff --git a/mlir/lib/CAPI/Dialect/LLVM.cpp b/mlir/lib/CAPI/Dialect/LLVM.cpp
index e6f58d010bda5..d91c32530fb03 100644
--- a/mlir/lib/CAPI/Dialect/LLVM.cpp
+++ b/mlir/lib/CAPI/Dialect/LLVM.cpp
@@ -49,6 +49,14 @@ MlirType mlirLLVMVoidTypeGet(MlirContext ctx) {
 
 MlirStringRef mlirLLVMVoidTypeGetName(void) { return wrap(LLVMVoidType::name); }
 
+bool mlirTypeIsALLVMArrayType(MlirType type) {
+  return isa<LLVM::LLVMArrayType>(unwrap(type));
+}
+
+MlirTypeID mlirLLVMArrayTypeGetTypeID() {
+  return wrap(LLVM::LLVMArrayType::getTypeID());
+}
+
 MlirType mlirLLVMArrayTypeGet(MlirType elementType, unsigned numElements) {
   return wrap(LLVMArrayType::get(unwrap(elementType), numElements));
 }
@@ -61,6 +69,10 @@ MlirType mlirLLVMArrayTypeGetElementType(MlirType type) {
   return wrap(cast<LLVM::LLVMArrayType>(unwrap(type)).getElementType());
 }
 
+unsigned mlirLLVMArrayTypeGetNumElements(MlirType type) {
+  return cast<LLVM::LLVMArrayType>(unwrap(type)).getNumElements();
+}
+
 MlirType mlirLLVMFunctionTypeGet(MlirType resultType, intptr_t nArgumentTypes,
                                  MlirType const *argumentTypes, bool isVarArg) {
   SmallVector<Type, 2> argumentStorage;
diff --git a/mlir/test/CAPI/llvm.c b/mlir/test/CAPI/llvm.c
index f3c4cbe036d7c..057a42dbb4b14 100644
--- a/mlir/test/CAPI/llvm.c
+++ b/mlir/test/CAPI/llvm.c
@@ -59,6 +59,14 @@ static void testTypeCreation(MlirContext ctx) {
       mlirTypeParseGet(ctx, mlirStringRefCreateFromCString(i32_4_text));
   // CHECK: !llvm.array<4 x i32>: 1
   fprintf(stderr, "%s: %d\n", i32_4_text, mlirTypeEqual(i32_4, i32_4_ref));
+  // CHECK: array_isa: 1
+  fprintf(stderr, "array_isa: %d\n", mlirTypeIsALLVMArrayType(i32_4));
+  // CHECK: array_element_type: 1
+  fprintf(stderr, "array_element_type: %d\n",
+          mlirTypeEqual(mlirLLVMArrayTypeGetElementType(i32_4), i32));
+  // CHECK: array_num_elements: 4
+  fprintf(stderr, "array_num_elements: %u\n",
+          mlirLLVMArrayTypeGetNumElements(i32_4));
 
   const char *i8_i32_i64_text = "!llvm.func<i8 (i32, i64)>";
   const MlirType i32_i64_arr[] = {i32, i64};
diff --git a/mlir/test/python/dialects/llvm.py b/mlir/test/python/dialects/llvm.py
index 305ed9aba940d..4b5020fc3e39a 100644
--- a/mlir/test/python/dialects/llvm.py
+++ b/mlir/test/python/dialects/llvm.py
@@ -102,6 +102,30 @@ def testStructType():
     assert isinstance(typ, llvm.StructType)
 
 
+# CHECK-LABEL: testArrayType
+ at constructAndPrintInModule
+def testArrayType():
+    i32 = IntegerType.get_signless(32)
+    i8 = IntegerType.get_signless(8)
+
+    arr = llvm.ArrayType.get(i32, 4)
+    # CHECK: !llvm.array<4 x i32>
+    print(arr)
+    assert arr.element_type == i32
+    assert arr.num_elements == 4
+
+    arr2 = llvm.ArrayType.get(i8, 12)
+    # CHECK: !llvm.array<12 x i8>
+    print(arr2)
+    assert arr2.element_type == i8
+    assert arr2.num_elements == 12
+
+    typ = Type.parse("!llvm.array<4 x i32>")
+    assert isinstance(typ, llvm.ArrayType)
+    assert isinstance(typ, llvm.ArrayType)
+    assert typ == arr
+
+
 # CHECK-LABEL: testSmoke
 @constructAndPrintInModule
 def testSmoke():

>From c403a38fd5b8171d96daf71bd03eabd78a6e5144 Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Mon, 9 Mar 2026 10:30:03 -0700
Subject: [PATCH 2/5] format

---
 mlir/lib/Bindings/Python/DialectLLVM.cpp | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/mlir/lib/Bindings/Python/DialectLLVM.cpp b/mlir/lib/Bindings/Python/DialectLLVM.cpp
index a4220780cd338..f17371a8bb385 100644
--- a/mlir/lib/Bindings/Python/DialectLLVM.cpp
+++ b/mlir/lib/Bindings/Python/DialectLLVM.cpp
@@ -180,10 +180,9 @@ struct ArrayType : PyConcreteType<ArrayType> {
                            mlirLLVMArrayTypeGet(elementType, numElements));
         },
         "element_type"_a, "num_elements"_a);
-    c.def_prop_ro("element_type",
-                  [](const ArrayType &type) {
-                    return mlirLLVMArrayTypeGetElementType(type);
-                  });
+    c.def_prop_ro("element_type", [](const ArrayType &type) {
+      return mlirLLVMArrayTypeGetElementType(type);
+    });
     c.def_prop_ro("num_elements", [](const ArrayType &type) {
       return mlirLLVMArrayTypeGetNumElements(type);
     });

>From a53d9709178259d138fef2358428d120faac6480 Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Mon, 9 Mar 2026 10:48:14 -0700
Subject: [PATCH 3/5] Remove duplicate assertion

---
 mlir/test/python/dialects/llvm.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/mlir/test/python/dialects/llvm.py b/mlir/test/python/dialects/llvm.py
index 4b5020fc3e39a..da8ccf223170f 100644
--- a/mlir/test/python/dialects/llvm.py
+++ b/mlir/test/python/dialects/llvm.py
@@ -122,7 +122,6 @@ def testArrayType():
 
     typ = Type.parse("!llvm.array<4 x i32>")
     assert isinstance(typ, llvm.ArrayType)
-    assert isinstance(typ, llvm.ArrayType)
     assert typ == arr
 
 

>From c23279c98977530b7445f0fc9dc244ff2916831c Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Mon, 9 Mar 2026 15:00:37 -0700
Subject: [PATCH 4/5] Add Python tests for insertvalue/extractvalue with
 ArrayType

Verify that the newly exposed LLVMArrayType works correctly
with insertvalue and extractvalue ops.

Made-with: Cursor
---
 mlir/test/python/dialects/llvm.py | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/mlir/test/python/dialects/llvm.py b/mlir/test/python/dialects/llvm.py
index da8ccf223170f..d046626354966 100644
--- a/mlir/test/python/dialects/llvm.py
+++ b/mlir/test/python/dialects/llvm.py
@@ -125,6 +125,23 @@ def testArrayType():
     assert typ == arr
 
 
+# CHECK-LABEL: testArrayTypeOps
+ at constructAndPrintInModule
+def testArrayTypeOps():
+    i32 = IntegerType.get_signless(32)
+    arr_t = llvm.ArrayType.get(i32, 4)
+
+    undef = llvm.UndefOp(arr_t)
+    c_42 = llvm.mlir_constant(IntegerAttr.get(i32, 42))
+    inserted = llvm.InsertValueOp(arr_t, undef, c_42, [0])
+    extracted = llvm.ExtractValueOp(i32, inserted, [0])
+
+    # CHECK: %[[UNDEF:.*]] = llvm.mlir.undef : !llvm.array<4 x i32>
+    # CHECK: %[[C42:.*]] = llvm.mlir.constant(42 : i32) : i32
+    # CHECK: %[[INS:.*]] = llvm.insertvalue %[[C42]], %[[UNDEF]][0] : !llvm.array<4 x i32>
+    # CHECK: %{{.*}} = llvm.extractvalue %[[INS]][0] : !llvm.array<4 x i32>
+
+
 # CHECK-LABEL: testSmoke
 @constructAndPrintInModule
 def testSmoke():

>From aebd36b75d5039e8834715788f83b9ea72f505b8 Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Mon, 9 Mar 2026 15:48:08 -0700
Subject: [PATCH 5/5] Add insert/extract tests

---
 mlir/test/python/dialects/llvm.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/mlir/test/python/dialects/llvm.py b/mlir/test/python/dialects/llvm.py
index d046626354966..7a2b8e1809c47 100644
--- a/mlir/test/python/dialects/llvm.py
+++ b/mlir/test/python/dialects/llvm.py
@@ -133,8 +133,8 @@ def testArrayTypeOps():
 
     undef = llvm.UndefOp(arr_t)
     c_42 = llvm.mlir_constant(IntegerAttr.get(i32, 42))
-    inserted = llvm.InsertValueOp(arr_t, undef, c_42, [0])
-    extracted = llvm.ExtractValueOp(i32, inserted, [0])
+    inserted = llvm.insertvalue(undef, c_42, [0])
+    llvm.extractvalue(i32, inserted, [0])
 
     # CHECK: %[[UNDEF:.*]] = llvm.mlir.undef : !llvm.array<4 x i32>
     # CHECK: %[[C42:.*]] = llvm.mlir.constant(42 : i32) : i32



More information about the Mlir-commits mailing list