[Mlir-commits] [mlir] [MLIR][Python][NOMERGE] demo building bindings with no CAPI aggregate and using mlir aggregate (PR #161782)

Maksim Levental llvmlistbot at llvm.org
Thu Oct 2 23:30:38 PDT 2025


https://github.com/makslevental updated https://github.com/llvm/llvm-project/pull/161782

>From 2460e6391bcfd9e61dd2cd208801e9b0c57888a8 Mon Sep 17 00:00:00 2001
From: makslevental <maksim.levental at gmail.com>
Date: Thu, 2 Oct 2025 22:19:58 -0700
Subject: [PATCH] [MLIR][Python] demo building bindings with no CAPI aggregate
 and using mlir aggregate

---
 mlir/examples/standalone/CMakeLists.txt       |   1 +
 .../standalone/lib/Standalone/CMakeLists.txt  |   6 +-
 .../standalone/really_alone/CMakeLists.txt    |  32 ++
 .../StandReallyAloneExtensionNanobind.cpp     |  43 +++
 .../dialects/_ods_common.py                   | 307 ++++++++++++++++++
 .../dialects/standalonereallyalone.py         |  10 +
 .../test/python/smoketest_really_alone.py     |  37 +++
 mlir/lib/Bindings/Python/IRModule.h           |   1 -
 mlir/python/CMakeLists.txt                    |   1 +
 mlir/test/Examples/standalone/test.really.toy |  14 +
 mlir/test/Examples/standalone/test.toy        |   4 +-
 mlir/test/lit.cfg.py                          |   9 +
 12 files changed, 457 insertions(+), 8 deletions(-)
 create mode 100644 mlir/examples/standalone/really_alone/CMakeLists.txt
 create mode 100644 mlir/examples/standalone/really_alone/StandReallyAloneExtensionNanobind.cpp
 create mode 100644 mlir/examples/standalone/really_alone/mlir_standreallyalone/dialects/_ods_common.py
 create mode 100644 mlir/examples/standalone/really_alone/mlir_standreallyalone/dialects/standalonereallyalone.py
 create mode 100644 mlir/examples/standalone/test/python/smoketest_really_alone.py
 create mode 100644 mlir/test/Examples/standalone/test.really.toy

diff --git a/mlir/examples/standalone/CMakeLists.txt b/mlir/examples/standalone/CMakeLists.txt
index c6c49fde12d2e..4c61bbd41d252 100644
--- a/mlir/examples/standalone/CMakeLists.txt
+++ b/mlir/examples/standalone/CMakeLists.txt
@@ -70,6 +70,7 @@ if(MLIR_ENABLE_BINDINGS_PYTHON)
     set(MLIR_BINDINGS_PYTHON_INSTALL_PREFIX "python_packages/standalone/${MLIR_PYTHON_PACKAGE_PREFIX}" CACHE STRING "" FORCE)
   endif()
   add_subdirectory(python)
+  add_subdirectory(really_alone)
 endif()
 add_subdirectory(test)
 add_subdirectory(standalone-opt)
diff --git a/mlir/examples/standalone/lib/Standalone/CMakeLists.txt b/mlir/examples/standalone/lib/Standalone/CMakeLists.txt
index 0f1705a25c8c8..f2e023461329a 100644
--- a/mlir/examples/standalone/lib/Standalone/CMakeLists.txt
+++ b/mlir/examples/standalone/lib/Standalone/CMakeLists.txt
@@ -10,9 +10,5 @@ add_mlir_dialect_library(MLIRStandalone
         DEPENDS
         MLIRStandaloneOpsIncGen
         MLIRStandalonePassesIncGen
-
-        LINK_LIBS PUBLIC
-        MLIRIR
-        MLIRInferTypeOpInterface
-        MLIRFuncDialect
         )
+target_link_options(obj.MLIRStandalone PUBLIC --unresolved-symbols=ignore-all)
diff --git a/mlir/examples/standalone/really_alone/CMakeLists.txt b/mlir/examples/standalone/really_alone/CMakeLists.txt
new file mode 100644
index 0000000000000..91b54a8c33a19
--- /dev/null
+++ b/mlir/examples/standalone/really_alone/CMakeLists.txt
@@ -0,0 +1,32 @@
+add_compile_definitions("MLIR_PYTHON_PACKAGE_PREFIX=mlir.")
+
+declare_mlir_python_sources(StandReallyAlonePythonSources)
+declare_mlir_dialect_python_bindings(
+  ADD_TO_PARENT StandReallyAlonePythonSources
+  ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/mlir_standreallyalone"
+  SOURCES
+    dialects/standalonereallyalone.py
+    dialects/_ods_common.py
+)
+
+declare_mlir_python_extension(StandReallyAlonePythonSources.NanobindExtension
+  MODULE_NAME _standReallyAloneDialectsNanobind
+  ADD_TO_PARENT StandReallyAlonePythonSources
+  SOURCES
+    StandReallyAloneExtensionNanobind.cpp
+  PRIVATE_LINK_LIBS
+    StandaloneCAPI
+  PYTHON_BINDINGS_LIBRARY nanobind
+)
+
+set(StandReallyAlonePythonModules_ROOT_PREFIX "${MLIR_BINARY_DIR}/${MLIR_BINDINGS_PYTHON_INSTALL_PREFIX}")
+add_mlir_python_modules(StandReallyAlonePythonModules
+  ROOT_PREFIX "${StandReallyAlonePythonModules_ROOT_PREFIX}/../mlir_standreallyalone"
+  INSTALL_PREFIX "${MLIR_BINDINGS_PYTHON_INSTALL_PREFIX}/../mlir_standreallyalone"
+  DECLARED_SOURCES
+    StandReallyAlonePythonSources
+    StandReallyAlonePythonSources.NanobindExtension
+    StandalonePythonSources.standalone.ops_gen
+    StandalonePythonSources.standalone.tablegen
+    MLIRPythonSources.Dialects.builtin
+)
diff --git a/mlir/examples/standalone/really_alone/StandReallyAloneExtensionNanobind.cpp b/mlir/examples/standalone/really_alone/StandReallyAloneExtensionNanobind.cpp
new file mode 100644
index 0000000000000..8044b7a540e27
--- /dev/null
+++ b/mlir/examples/standalone/really_alone/StandReallyAloneExtensionNanobind.cpp
@@ -0,0 +1,43 @@
+//===- StandaloneExtension.cpp - Extension module -------------------------===//
+//
+// This is the nanobind version of the example module. There is also a pybind11
+// example in StandaloneExtensionPybind11.cpp.
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "Standalone-c/Dialects.h"
+#include "mlir-c/Dialect/Arith.h"
+#include "mlir/Bindings/Python/Nanobind.h"
+#include "mlir/Bindings/Python/NanobindAdaptors.h"
+
+namespace nb = nanobind;
+
+NB_MODULE(_standReallyAloneDialectsNanobind, m) {
+  //===--------------------------------------------------------------------===//
+  // standalone dialect
+  //===--------------------------------------------------------------------===//
+  auto standaloneM = m.def_submodule("standalone");
+
+  standaloneM.def(
+      "register_dialects",
+      [](MlirContext context, bool load) {
+        MlirDialectHandle arithHandle = mlirGetDialectHandle__arith__();
+        MlirDialectHandle standaloneHandle =
+            mlirGetDialectHandle__standalone__();
+        mlirDialectHandleRegisterDialect(arithHandle, context);
+        mlirDialectHandleRegisterDialect(standaloneHandle, context);
+        if (load) {
+          mlirDialectHandleLoadDialect(arithHandle, context);
+          mlirDialectHandleRegisterDialect(standaloneHandle, context);
+        }
+      },
+      nb::arg("context").none() = nb::none(), nb::arg("load") = true,
+      // clang-format off
+      nb::sig("def register_dialects(context: " MAKE_MLIR_PYTHON_QUALNAME("ir.Context") ", load: bool = True) -> None")
+      // clang-format on
+  );
+}
diff --git a/mlir/examples/standalone/really_alone/mlir_standreallyalone/dialects/_ods_common.py b/mlir/examples/standalone/really_alone/mlir_standreallyalone/dialects/_ods_common.py
new file mode 100644
index 0000000000000..aeaa533e0a1f4
--- /dev/null
+++ b/mlir/examples/standalone/really_alone/mlir_standreallyalone/dialects/_ods_common.py
@@ -0,0 +1,307 @@
+#  Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+#  See https://llvm.org/LICENSE.txt for license information.
+#  SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+from typing import (
+    List as _List,
+    Optional as _Optional,
+    Sequence as _Sequence,
+    Tuple as _Tuple,
+    Type as _Type,
+    Union as _Union,
+)
+
+from mlir._mlir_libs import _mlir as _cext
+from mlir.ir import (
+    ArrayAttr,
+    Attribute,
+    BoolAttr,
+    DenseI64ArrayAttr,
+    IntegerAttr,
+    IntegerType,
+    OpView,
+    Operation,
+    ShapedType,
+    Value,
+)
+
+__all__ = [
+    "equally_sized_accessor",
+    "get_default_loc_context",
+    "get_op_result_or_value",
+    "get_op_results_or_values",
+    "get_op_result_or_op_results",
+    "segmented_accessor",
+]
+
+
+def segmented_accessor(elements, raw_segments, idx):
+    """
+    Returns a slice of elements corresponding to the idx-th segment.
+
+      elements: a sliceable container (operands or results).
+      raw_segments: an mlir.ir.Attribute, of DenseI32Array subclass containing
+          sizes of the segments.
+      idx: index of the segment.
+    """
+    segments = _cext.ir.DenseI32ArrayAttr(raw_segments)
+    start = sum(segments[i] for i in range(idx))
+    end = start + segments[idx]
+    return elements[start:end]
+
+
+def equally_sized_accessor(
+    elements, n_simple, n_variadic, n_preceding_simple, n_preceding_variadic
+):
+    """
+    Returns a starting position and a number of elements per variadic group
+    assuming equally-sized groups and the given numbers of preceding groups.
+
+      elements: a sequential container.
+      n_simple: the number of non-variadic groups in the container.
+      n_variadic: the number of variadic groups in the container.
+      n_preceding_simple: the number of non-variadic groups preceding the current
+          group.
+      n_preceding_variadic: the number of variadic groups preceding the current
+          group.
+    """
+
+    total_variadic_length = len(elements) - n_simple
+    # This should be enforced by the C++-side trait verifier.
+    assert total_variadic_length % n_variadic == 0
+
+    elements_per_group = total_variadic_length // n_variadic
+    start = n_preceding_simple + n_preceding_variadic * elements_per_group
+    return start, elements_per_group
+
+
+def get_default_loc_context(location=None):
+    """
+    Returns a context in which the defaulted location is created. If the location
+    is None, takes the current location from the stack.
+    """
+    if location is None:
+        if _cext.ir.Location.current:
+            return _cext.ir.Location.current.context
+        return None
+    return location.context
+
+
+def get_op_result_or_value(
+    arg: _Union[
+        _cext.ir.OpView, _cext.ir.Operation, _cext.ir.Value, _cext.ir.OpResultList
+    ],
+) -> _cext.ir.Value:
+    """Returns the given value or the single result of the given op.
+
+    This is useful to implement op constructors so that they can take other ops as
+    arguments instead of requiring the caller to extract results for every op.
+    Raises ValueError if provided with an op that doesn't have a single result.
+    """
+    if isinstance(arg, _cext.ir.OpView):
+        return arg.operation.result
+    elif isinstance(arg, _cext.ir.Operation):
+        return arg.result
+    elif isinstance(arg, _cext.ir.OpResultList):
+        return arg[0]
+    else:
+        assert isinstance(arg, _cext.ir.Value), f"expects Value, got {type(arg)}"
+        return arg
+
+
+def get_op_results_or_values(
+    arg: _Union[
+        _cext.ir.OpView,
+        _cext.ir.Operation,
+        _Sequence[_Union[_cext.ir.OpView, _cext.ir.Operation, _cext.ir.Value]],
+    ],
+) -> _Union[
+    _Sequence[_Union[_cext.ir.OpView, _cext.ir.Operation, _cext.ir.Value]],
+    _cext.ir.OpResultList,
+]:
+    """Returns the given sequence of values or the results of the given op.
+
+    This is useful to implement op constructors so that they can take other ops as
+    lists of arguments instead of requiring the caller to extract results for
+    every op.
+    """
+    if isinstance(arg, _cext.ir.OpView):
+        return arg.operation.results
+    elif isinstance(arg, _cext.ir.Operation):
+        return arg.results
+    else:
+        return arg
+
+
+def get_op_result_or_op_results(
+    op: _Union[_cext.ir.OpView, _cext.ir.Operation],
+) -> _Union[_cext.ir.Operation, _cext.ir.OpResult, _Sequence[_cext.ir.OpResult]]:
+    results = op.results
+    num_results = len(results)
+    if num_results == 1:
+        return results[0]
+    elif num_results > 1:
+        return results
+    elif isinstance(op, _cext.ir.OpView):
+        return op.operation
+    else:
+        return op
+
+
+ResultValueTypeTuple = _cext.ir.Operation, _cext.ir.OpView, _cext.ir.Value
+ResultValueT = _Union[ResultValueTypeTuple]
+VariadicResultValueT = _Union[ResultValueT, _Sequence[ResultValueT]]
+
+StaticIntLike = _Union[int, IntegerAttr]
+ValueLike = _Union[Operation, OpView, Value]
+MixedInt = _Union[StaticIntLike, ValueLike]
+
+IntOrAttrList = _Sequence[_Union[IntegerAttr, int]]
+OptionalIntList = _Optional[_Union[ArrayAttr, IntOrAttrList]]
+
+BoolOrAttrList = _Sequence[_Union[BoolAttr, bool]]
+OptionalBoolList = _Optional[_Union[ArrayAttr, BoolOrAttrList]]
+
+MixedValues = _Union[_Sequence[_Union[StaticIntLike, ValueLike]], ArrayAttr, ValueLike]
+
+DynamicIndexList = _Sequence[_Union[MixedInt, _Sequence[MixedInt]]]
+
+
+def _dispatch_dynamic_index_list(
+    indices: _Union[DynamicIndexList, ArrayAttr],
+) -> _Tuple[_List[ValueLike], _Union[_List[int], ArrayAttr], _List[bool]]:
+    """Dispatches a list of indices to the appropriate form.
+
+    This is similar to the custom `DynamicIndexList` directive upstream:
+    provided indices may be in the form of dynamic SSA values or static values,
+    and they may be scalable (i.e., as a singleton list) or not. This function
+    dispatches each index into its respective form. It also extracts the SSA
+    values and static indices from various similar structures, respectively.
+    """
+    dynamic_indices = []
+    static_indices = [ShapedType.get_dynamic_size()] * len(indices)
+    scalable_indices = [False] * len(indices)
+
+    # ArrayAttr: Extract index values.
+    if isinstance(indices, ArrayAttr):
+        indices = [idx for idx in indices]
+
+    def process_nonscalable_index(i, index):
+        """Processes any form of non-scalable index.
+
+        Returns False if the given index was scalable and thus remains
+        unprocessed; True otherwise.
+        """
+        if isinstance(index, int):
+            static_indices[i] = index
+        elif isinstance(index, IntegerAttr):
+            static_indices[i] = index.value  # pytype: disable=attribute-error
+        elif isinstance(index, (Operation, Value, OpView)):
+            dynamic_indices.append(index)
+        else:
+            return False
+        return True
+
+    # Process each index at a time.
+    for i, index in enumerate(indices):
+        if not process_nonscalable_index(i, index):
+            # If it wasn't processed, it must be a scalable index, which is
+            # provided as a _Sequence of one value, so extract and process that.
+            scalable_indices[i] = True
+            assert len(index) == 1
+            ret = process_nonscalable_index(i, index[0])
+            assert ret
+
+    return dynamic_indices, static_indices, scalable_indices
+
+
+# Dispatches `MixedValues` that all represents integers in various forms into
+# the following three categories:
+#   - `dynamic_values`: a list of `Value`s, potentially from op results;
+#   - `packed_values`: a value handle, potentially from an op result, associated
+#                      to one or more payload operations of integer type;
+#   - `static_values`: an `ArrayAttr` of `i64`s with static values, from Python
+#                      `int`s, from `IntegerAttr`s, or from an `ArrayAttr`.
+# The input is in the form for `packed_values`, only that result is set and the
+# other two are empty. Otherwise, the input can be a mix of the other two forms,
+# and for each dynamic value, a special value is added to the `static_values`.
+def _dispatch_mixed_values(
+    values: MixedValues,
+) -> _Tuple[_List[Value], _Union[Operation, Value, OpView], DenseI64ArrayAttr]:
+    dynamic_values = []
+    packed_values = None
+    static_values = None
+    if isinstance(values, ArrayAttr):
+        static_values = values
+    elif isinstance(values, (Operation, Value, OpView)):
+        packed_values = values
+    else:
+        static_values = []
+        for size in values or []:
+            if isinstance(size, int):
+                static_values.append(size)
+            else:
+                static_values.append(ShapedType.get_dynamic_size())
+                dynamic_values.append(size)
+        static_values = DenseI64ArrayAttr.get(static_values)
+
+    return (dynamic_values, packed_values, static_values)
+
+
+def _get_value_or_attribute_value(
+    value_or_attr: _Union[any, Attribute, ArrayAttr],
+) -> any:
+    if isinstance(value_or_attr, Attribute) and hasattr(value_or_attr, "value"):
+        return value_or_attr.value
+    if isinstance(value_or_attr, ArrayAttr):
+        return _get_value_list(value_or_attr)
+    return value_or_attr
+
+
+def _get_value_list(
+    sequence_or_array_attr: _Union[_Sequence[any], ArrayAttr],
+) -> _Sequence[any]:
+    return [_get_value_or_attribute_value(v) for v in sequence_or_array_attr]
+
+
+def _get_int_array_attr(
+    values: _Optional[_Union[ArrayAttr, IntOrAttrList]],
+) -> ArrayAttr:
+    if values is None:
+        return None
+
+    # Turn into a Python list of Python ints.
+    values = _get_value_list(values)
+
+    # Make an ArrayAttr of IntegerAttrs out of it.
+    return ArrayAttr.get(
+        [IntegerAttr.get(IntegerType.get_signless(64), v) for v in values]
+    )
+
+
+def _get_int_array_array_attr(
+    values: _Optional[_Union[ArrayAttr, _Sequence[_Union[ArrayAttr, IntOrAttrList]]]],
+) -> ArrayAttr:
+    """Creates an ArrayAttr of ArrayAttrs of IntegerAttrs.
+
+    The input has to be a collection of a collection of integers, where any
+    Python _Sequence and ArrayAttr are admissible collections and Python ints and
+    any IntegerAttr are admissible integers. Both levels of collections are
+    turned into ArrayAttr; the inner level is turned into IntegerAttrs of i64s.
+    If the input is None, an empty ArrayAttr is returned.
+    """
+    if values is None:
+        return None
+
+    # Make sure the outer level is a list.
+    values = _get_value_list(values)
+
+    # The inner level is now either invalid or a mixed sequence of ArrayAttrs and
+    # Sequences. Make sure the nested values are all lists.
+    values = [_get_value_list(nested) for nested in values]
+
+    # Turn each nested list into an ArrayAttr.
+    values = [_get_int_array_attr(nested) for nested in values]
+
+    # Turn the outer list into an ArrayAttr.
+    return ArrayAttr.get(values)
diff --git a/mlir/examples/standalone/really_alone/mlir_standreallyalone/dialects/standalonereallyalone.py b/mlir/examples/standalone/really_alone/mlir_standreallyalone/dialects/standalonereallyalone.py
new file mode 100644
index 0000000000000..edbcbb49ee036
--- /dev/null
+++ b/mlir/examples/standalone/really_alone/mlir_standreallyalone/dialects/standalonereallyalone.py
@@ -0,0 +1,10 @@
+#  Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+#  See https://llvm.org/LICENSE.txt for license information.
+#  SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+from ._ods_common import _cext
+
+_cext.globals.append_dialect_search_prefix("mlir_standreallyalone.dialects")
+
+from ._standalone_ops_gen import *
+from .._mlir_libs._standReallyAloneDialectsNanobind.standalone import *
diff --git a/mlir/examples/standalone/test/python/smoketest_really_alone.py b/mlir/examples/standalone/test/python/smoketest_really_alone.py
new file mode 100644
index 0000000000000..528389dc1f1ae
--- /dev/null
+++ b/mlir/examples/standalone/test/python/smoketest_really_alone.py
@@ -0,0 +1,37 @@
+# RUN: echo "do nothing"
+# just so lit doesn't complain about a missing RUN line
+# noinspection PyUnusedImports
+import contextlib
+import ctypes
+import sys
+
+
+ at contextlib.contextmanager
+def dl_open_guard():
+    old_flags = sys.getdlopenflags()
+    sys.setdlopenflags(old_flags | ctypes.RTLD_GLOBAL)
+    yield
+    sys.setdlopenflags(old_flags)
+
+
+with dl_open_guard():
+    # noinspection PyUnresolvedReferences
+    from mlir._mlir_libs import _mlir
+    from mlir import ir
+
+from mlir_standreallyalone.dialects import standalonereallyalone as standalone_d
+
+with ir.Context() as ctx:
+    standalone_d.register_dialects()
+    module = ir.Module.parse(
+        """
+    %0 = arith.constant 2 : i32
+    %1 = standalone.foo %0 : i32
+    """
+    )
+    # CHECK: %[[C:.*]] = arith.constant 2 : i32
+    # CHECK: standalone.foo %[[C]] : i32
+    print(str(module))
+
+# just so lit doesn't complain about this file
+# UNSUPPORTED: target={{.*}}
diff --git a/mlir/lib/Bindings/Python/IRModule.h b/mlir/lib/Bindings/Python/IRModule.h
index edbd73eade906..e712fa7780e26 100644
--- a/mlir/lib/Bindings/Python/IRModule.h
+++ b/mlir/lib/Bindings/Python/IRModule.h
@@ -23,7 +23,6 @@
 #include "mlir-c/Diagnostics.h"
 #include "mlir-c/IR.h"
 #include "mlir-c/IntegerSet.h"
-#include "mlir-c/Transforms.h"
 #include "mlir/Bindings/Python/Nanobind.h"
 #include "mlir/Bindings/Python/NanobindAdaptors.h"
 #include "llvm/ADT/DenseMap.h"
diff --git a/mlir/python/CMakeLists.txt b/mlir/python/CMakeLists.txt
index 9f5246de6bda0..aae8ebb54cb73 100644
--- a/mlir/python/CMakeLists.txt
+++ b/mlir/python/CMakeLists.txt
@@ -528,6 +528,7 @@ declare_mlir_python_extension(MLIRPythonExtension.Core
 
     # Dialects
     MLIRCAPIFunc
+    MLIRCAPIArith
 )
 
 # This extension exposes an API to register all dialects, extensions, and passes
diff --git a/mlir/test/Examples/standalone/test.really.toy b/mlir/test/Examples/standalone/test.really.toy
new file mode 100644
index 0000000000000..675fba0f921ad
--- /dev/null
+++ b/mlir/test/Examples/standalone/test.really.toy
@@ -0,0 +1,14 @@
+# RUN: "%cmake_exe" "%mlir_src_root/examples/standalone" -G "%cmake_generator" \
+# RUN: -DCMAKE_BUILD_TYPE=%cmake_build_type \
+# RUN: -DCMAKE_CXX_COMPILER=%host_cxx -DCMAKE_C_COMPILER=%host_cc \
+# RUN: -DLLVM_ENABLE_LIBCXX=%enable_libcxx -DMLIR_DIR=%mlir_cmake_dir \
+# RUN: -DLLVM_USE_LINKER=%llvm_use_linker \
+# RUN: -DMLIR_PYTHON_PACKAGE_PREFIX=mlir \
+# RUN: -DPython3_EXECUTABLE=%python \
+# RUN: -DPython_EXECUTABLE=%python | tee %t
+# RUN: "%cmake_exe" --build . --target StandReallyAlonePythonModules | tee -a %t
+# RUN: %python "%mlir_src_root/examples/standalone/test/python/smoketest_really_alone.py" | tee -a %t
+# RUN: FileCheck --input-file=%t %s
+
+# CHECK: %[[C:.*]] = arith.constant 2 : i32
+# CHECK: standalone.foo %[[C]] : i32
diff --git a/mlir/test/Examples/standalone/test.toy b/mlir/test/Examples/standalone/test.toy
index a88c115ebf197..f00dd38c55d50 100644
--- a/mlir/test/Examples/standalone/test.toy
+++ b/mlir/test/Examples/standalone/test.toy
@@ -5,8 +5,8 @@
 # RUN: -DLLVM_USE_LINKER=%llvm_use_linker \
 # RUN: -DMLIR_PYTHON_PACKAGE_PREFIX=mlir_standalone \
 # RUN: -DPython3_EXECUTABLE=%python \
-# RUN: -DPython_EXECUTABLE=%python
-# RUN: "%cmake_exe" --build . --target check-standalone | tee %t
+# RUN: -DPython_EXECUTABLE=%python | tee %t
+# RUN: "%cmake_exe" --build . --target check-standalone | tee -a %t
 # RUN: FileCheck --input-file=%t %s
 
 # Note: The number of checked tests is not important. The command will fail
diff --git a/mlir/test/lit.cfg.py b/mlir/test/lit.cfg.py
index f99c24d6e299a..138d66d84ab74 100644
--- a/mlir/test/lit.cfg.py
+++ b/mlir/test/lit.cfg.py
@@ -339,6 +339,14 @@ def find_real_python_interpreter():
         [
             os.path.join(config.mlir_obj_root, "python_packages", "mlir_core"),
             os.path.join(config.mlir_obj_root, "python_packages", "mlir_test"),
+            os.path.join(
+                config.mlir_obj_root,
+                "test",
+                "Examples",
+                "standalone",
+                "python_packages",
+                "standalone",
+            ),
         ],
         append_path=True,
     )
@@ -348,6 +356,7 @@ def find_real_python_interpreter():
 else:
     config.available_features.add("noasserts")
 
+
 def have_host_jit_feature_support(feature_name):
     mlir_runner_exe = lit.util.which("mlir-runner", config.mlir_tools_dir)
 



More information about the Mlir-commits mailing list