Skip to content

Conversation

@makslevental
Copy link
Contributor

@makslevental makslevental commented Oct 21, 2025

Currently ExecutionEngine tries to dump all functions declared in the module, even those which are "external" (i.e., linked/loaded at runtime). E.g.

func.func private @printF32(f32)
func.func @supported_arg_types(%arg0: i32, %arg1: f32) {
  call @printF32(%arg1) : (f32) -> ()
  return
}

fails with

Could not compile printF32:
  Symbols not found: [ __mlir_printF32 ]
Program aborted due to an unhandled Error:
Symbols not found: [ __mlir_printF32 ]

even though printF32 can be provided at final build time (i.e., when the object file is linked to some executable or shlib). E.g, if our own libmlir_c_runner_utils is linked.

So just skip functions which have no bodies during dump (i.e., are decls without defns).

@llvmbot
Copy link
Member

llvmbot commented Oct 21, 2025

@llvm/pr-subscribers-mlir-execution-engine

@llvm/pr-subscribers-mlir

Author: Maksim Levental (makslevental)

Changes

Currently ExecutionEngine tries to dump all functions declared in the module, even thoughs which "external" (i.e., linked at runtime). E.g.

module {
  func.func @<!-- -->supported_arg_types(%arg0: i32, %arg1: f32) {
    vector.print %arg0 : i32
    vector.print %arg1 : f32
    return
  }
}

fails with

Could not compile printF32:
  Symbols not found: [ __mlir_printF32 ]
Program aborted due to an unhandled Error:
Symbols not found: [ __mlir_printF32 ]

even though mlir_printF32 can and is provided by our own libmlir_c_runner_utils, which is usually loaded by the engine but of course can also be linked/loaded at runtime by whatever thing links the object file produced from the above.

So just skip functions which have no bodies during dump (i.e., are decls without defns).


Full diff: https://github.com/llvm/llvm-project/pull/164478.diff

1 Files Affected:

  • (modified) mlir/lib/ExecutionEngine/ExecutionEngine.cpp (+2)
diff --git a/mlir/lib/ExecutionEngine/ExecutionEngine.cpp b/mlir/lib/ExecutionEngine/ExecutionEngine.cpp
index 52162a43aeae3..2255633c746b3 100644
--- a/mlir/lib/ExecutionEngine/ExecutionEngine.cpp
+++ b/mlir/lib/ExecutionEngine/ExecutionEngine.cpp
@@ -239,6 +239,8 @@ ExecutionEngine::create(Operation *m, const ExecutionEngineOptions &options,
   // Remember all entry-points if object dumping is enabled.
   if (options.enableObjectDump) {
     for (auto funcOp : m->getRegion(0).getOps<LLVM::LLVMFuncOp>()) {
+      if (funcOp.getBlocks().empty())
+        continue;
       StringRef funcName = funcOp.getSymName();
       engine->functionNames.push_back(funcName.str());
     }

@makslevental
Copy link
Contributor Author

Note, I would prefer to perform this check in

void ExecutionEngine::dumpToObjectFile(StringRef filename) {
but by that point the module is not accessible.

@makslevental makslevental marked this pull request as draft October 21, 2025 19:22
@makslevental makslevental force-pushed the users/makslevental/fix-ee branch from 73f651f to 22da8d0 Compare October 21, 2025 19:35
Currently ExecutionEngine tries to dump all functions declared in the module, even thoughs which "external" (i.e., linked at runtime). E.g.

```mlir
module {
  func.func @supported_arg_types(%arg0: i32, %arg1: f32) {
    vector.print %arg0 : i32
    vector.print %arg1 : f32
    return
  }
}
```
fails with
```
Could not compile printF32:
  Symbols not found: [ __mlir_printF32 ]
Program aborted due to an unhandled Error:
Symbols not found: [ __mlir_printF32 ]
```
even though `mlir_printF32` can and is provided by our own `libmlir_c_runner_utils`, which is usually loaded by the engine but of course can also be linked/loaded at runtime by whatever thing links the object file produced from the above.

So just skip functions which have no bodies during dump (i.e., are decls without defns).
@makslevental makslevental force-pushed the users/makslevental/fix-ee branch from 22da8d0 to 25832d3 Compare October 21, 2025 19:48
add_subdirectory(lib)

set(MLIR_PYTHON_TEST_DEPENDS MLIRPythonModules)
set(MLIR_PYTHON_TEST_DEPENDS MLIRPythonModules mlir-runner)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like I (potentially) broke lots of tests in this PR #157176 because mlir/test/lit.cfg.py tries to call mlir-runner (which might not be built):

def have_host_jit_feature_support(feature_name):
mlir_runner_exe = lit.util.which("mlir-runner", config.mlir_tools_dir)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, I double checked and this is the only tool that's required.

@makslevental makslevental marked this pull request as ready for review October 21, 2025 19:52
@makslevental makslevental merged commit cd9d487 into main Oct 27, 2025
12 checks passed
@makslevental makslevental deleted the users/makslevental/fix-ee branch October 27, 2025 19:22
dvbuka pushed a commit to dvbuka/llvm-project that referenced this pull request Oct 27, 2025
Currently ExecutionEngine tries to dump all functions declared in the
module, even those which are "external" (i.e., linked/loaded at
runtime). E.g.

```mlir
func.func private @printF32(f32)
func.func @supported_arg_types(%arg0: i32, %arg1: f32) {
  call @printF32(%arg1) : (f32) -> ()
  return
}
```
fails with
```
Could not compile printF32:
  Symbols not found: [ __mlir_printF32 ]
Program aborted due to an unhandled Error:
Symbols not found: [ __mlir_printF32 ]
```
even though `printF32` can be provided at final build time (i.e., when
the object file is linked to some executable or shlib). E.g, if our own
`libmlir_c_runner_utils` is linked.

So just skip functions which have no bodies during dump (i.e., are decls
without defns).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants