[Mlir-commits] [mlir] Add TOSA -> EmitC tests for MLGO mock models (PR #211833)
ioana ghiban
llvmlistbot at llvm.org
Fri Jul 24 08:40:55 PDT 2026
https://github.com/ioghiban created https://github.com/llvm/llvm-project/pull/211833
This tests are the first step towards monitoring the recently enabled TOSA -> EmitC path that ML optimization models will switch to, for a fully in-tree, framework free alternative to compile them for inference.
For simplicity, yet testing the core functionality, these tests don't use production models, but rather in-tree mock models, generated by these scripts:
[llvm/lib/Analysis/models/gen-regalloc-eviction-test-model.py](https://github.com/llvm/llvm-project/blob/main/llvm/lib/Analysis/models/gen-regalloc-eviction-test-model.py) /
[llvm/lib/Analysis/models/gen-inline-oz-test-model.py](https://github.com/llvm/llvm-project/blob/main/llvm/lib/Analysis/models/gen-inline-oz-test-model.py)
\+ [llvm/lib/Analysis/models/saved-model-to-tflite.py](https://github.com/llvm/llvm-project/blob/main/llvm/lib/Analysis/models/saved-model-to-tflite.py) + [tosa-converter-for-tflite](https://www.piwheels.org/project/tosa-converter-for-tflite/)
> Note: `saved-model-to-tflite.py` renames the TFLite converted SavedModel function to `main()`, which causes `clang` errors. Changing this behaviour requires interventions in Tensorflow, which are out of scope. Therefore, the functions were manually renamed.
> Note: The includes passed by argument to `clang` should have been handled by EmitC. This only becomes a problem when compiling these models standalone. Embedding the models in LLVM does not cause issues. Nonetheless, future work will ensure `ConvertToEmitC` includes required libraries for these ops.
>From b15f5500e791deff24a06b0c9b525bbb4b15b3e8 Mon Sep 17 00:00:00 2001
From: Ioana Ghiban <ioana.ghiban at arm.com>
Date: Fri, 24 Jul 2026 17:21:29 +0200
Subject: [PATCH] Add TOSA -> EmitC tests for MLGO mock models
---
.../EmitC/inline-oz-test-model-tosa.mlir | 57 +++++++++++++++++++
.../regalloc-eviction-test-model-tosa.mlir | 57 +++++++++++++++++++
2 files changed, 114 insertions(+)
create mode 100644 mlir/test/Integration/Dialect/EmitC/inline-oz-test-model-tosa.mlir
create mode 100644 mlir/test/Integration/Dialect/EmitC/regalloc-eviction-test-model-tosa.mlir
diff --git a/mlir/test/Integration/Dialect/EmitC/inline-oz-test-model-tosa.mlir b/mlir/test/Integration/Dialect/EmitC/inline-oz-test-model-tosa.mlir
new file mode 100644
index 0000000000000..ff5de17ba06a0
--- /dev/null
+++ b/mlir/test/Integration/Dialect/EmitC/inline-oz-test-model-tosa.mlir
@@ -0,0 +1,57 @@
+// DEFINE: %{pipeline} = "builtin.module(\
+// DEFINE: func.func(\
+// DEFINE: tosa-to-linalg-named,\
+// DEFINE: tosa-to-linalg,\
+// DEFINE: tosa-to-arith,\
+// DEFINE: tosa-to-tensor\
+// DEFINE: ),\
+// DEFINE: symbol-privatize,\
+// DEFINE: scalarize-single-element-tensor-return,\
+// DEFINE: one-shot-bufferize{\
+// DEFINE: bufferize-function-boundaries=true\
+// DEFINE: function-boundary-type-conversion=identity-layout-map\
+// DEFINE: buffer-alignment=0\
+// DEFINE: },\
+// DEFINE: buffer-results-to-out-params{\
+// DEFINE: hoist-static-allocs=true\
+// DEFINE: },\
+// DEFINE: buffer-deallocation-pipeline,\
+// DEFINE: func.func(\
+// DEFINE: convert-linalg-to-loops\
+// DEFINE: ),\
+// DEFINE: expand-strided-metadata,\
+// DEFINE: canonicalize,\
+// DEFINE: memref-elide-reinterpret-cast,\
+// DEFINE: convert-to-emitc,\
+// DEFINE: math-expand-ops{\
+// DEFINE: ops=rsqrt\
+// DEFINE: },\
+// DEFINE: arith-expand,\
+// DEFINE: convert-math-to-emitc,\
+// DEFINE: convert-arith-to-emitc\
+// DEFINE: )"
+
+// DEFINE: %{lower_to_emitc} = mlir-opt --pass-pipeline=%{pipeline} %s -o %t
+// DEFINE: %{translate} = mlir-translate -mlir-to-cpp %t -o %t.c
+// DEFINE: %{compile} = %host_cc -include stdint.h -fsyntax-only -Wpedantic -Wall -Werror -Wno-unused %t.c
+
+/// Lower via the pipeline defined above
+// RUN: rm -f %t && %{lower_to_emitc} && FileCheck %s --input-file=%t && %{translate} && %{compile}
+
+/// Generated with llvm/lib/Analysis/models/gen-inline-oz-test-model.py + llvm/lib/Analysis/models/saved-model-to-tflite.py
+/// Renamed "main" to avoid:
+/// error: 'main' should not be declared static
+/// error: return type of 'main' is not 'int'
+/// error: too many parameters (40) for 'main': must be 0, 2, or 3
+/// error: first parameter of 'main' (argument count) must be of type 'int'
+/// error: second parameter of 'main' (argument array) must be of type 'char **'
+/// error: third parameter of 'main' (environment) must be of type 'char **'
+
+// CHECK-LABEL: @mock_model
+// CHECK: emitc.constant
+module attributes {tf_saved_model.semantics, tfl.description = "MLIR Converted.", tfl.metadata = {CONVERSION_METADATA = "\0C\00\00\00\08\00\0E\00\08\00\04\00\08\00\00\00\10\00\00\00$\00\00\00\00\00\06\00\08\00\04\00\06\00\00\00\04\00\00\00\00\00\00\00\00\00\0A\00\10\00\0C\00\08\00\04\00\0A\00\00\00\01\00\00\00\02\00\00\00\04\00\00\00\06\00\00\002.15.1\00\00", min_runtime_version = "\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"}, tfl.schema_version = 3 : i32} {
+ func.func @mock_model(%arg0: tensor<i64> {tf_saved_model.index_path = ["callsite_cost"]}, %arg1: tensor<i64> {tf_saved_model.index_path = ["is_multiple_blocks"]}, %arg2: tensor<i64> {tf_saved_model.index_path = ["caller_conditionally_executed_blocks"]}, %arg3: tensor<i64> {tf_saved_model.index_path = ["cold_cc_penalty"]}, %arg4: tensor<i64> {tf_saved_model.index_path = ["callee_conditionally_executed_blocks"]}, %arg5: tensor<i64> {tf_saved_model.index_path = ["callee_users"]}, %arg6: tensor<i64> {tf_saved_model.index_path = ["callee_basic_block_count"]}, %arg7: tensor<i64> {tf_saved_model.index_path = ["nr_ctant_params"]}, %arg8: tensor<i64> {tf_saved_model.index_path = ["load_relative_intrinsic"]}, %arg9: tensor<i64> {tf_saved_model.index_path = ["jump_table_penalty"]}, %arg10: tensor<i64> {tf_saved_model.index_path = ["unsimplified_common_instructions"]}, %arg11: tensor<i64> {tf_saved_model.index_path = ["indirect_call_penalty"]}, %arg12: tensor<i64> {tf_saved_model.index_path = ["load_elimination"]}, %arg13: tensor<i64> {tf_saved_model.index_path = ["is_caller_avail_external"]}, %arg14: tensor<i64> {tf_saved_model.index_path = ["call_penalty"]}, %arg15: tensor<i64> {tf_saved_model.index_path = ["cost_estimate"]}, %arg16: tensor<i64> {tf_saved_model.index_path = ["case_cluster_penalty"]}, %arg17: tensor<i64> {tf_saved_model.index_path = ["node_count"]}, %arg18: tensor<i64> {tf_saved_model.index_path = ["call_argument_setup"]}, %arg19: tensor<i64> {tf_saved_model.index_path = ["sroa_savings"]}, %arg20: tensor<i64> {tf_saved_model.index_path = ["lowered_call_arg_setup"]}, %arg21: tensor<i64> {tf_saved_model.index_path = ["threshold"]}, %arg22: tensor<i64> {tf_saved_model.index_path = ["dead_blocks"]}, %arg23: tensor<i64> {tf_saved_model.index_path = ["constant_args"]}, %arg24: tensor<i64> {tf_saved_model.index_path = ["sroa_losses"]}, %arg25: tensor<i64> {tf_saved_model.index_path = ["simplified_instructions"]}, %arg26: tensor<i64> {tf_saved_model.index_path = ["num_loops"]}, %arg27: tensor<i32> {tf_saved_model.index_path = ["step_type"]}, %arg28: tensor<i64> {tf_saved_model.index_path = ["edge_count"]}, %arg29: tensor<i64> {tf_saved_model.index_path = ["is_callee_avail_external"]}, %arg30: tensor<i64> {tf_saved_model.index_path = ["nested_inlines"]}, %arg31: tensor<i64> {tf_saved_model.index_path = ["caller_basic_block_count"]}, %arg32: tensor<i64> {tf_saved_model.index_path = ["last_call_to_static_bonus"]}, %arg33: tensor<i64> {tf_saved_model.index_path = ["nested_inline_cost_estimate"]}, %arg34: tensor<i64> {tf_saved_model.index_path = ["callsite_height"]}, %arg35: tensor<i64> {tf_saved_model.index_path = ["constant_offset_ptr_args"]}, %arg36: tensor<i64> {tf_saved_model.index_path = ["switch_penalty"]}, %arg37: tensor<f32> {tf_saved_model.index_path = ["discount"]}, %arg38: tensor<i64> {tf_saved_model.index_path = ["caller_users"]}, %arg39: tensor<f32> {tf_saved_model.index_path = ["reward"]}) -> (tensor<i64> {tf_saved_model.index_path = ["inlining_decision"]}) attributes {tf.entry_function = {inputs = "action_callsite_cost:0,action_is_multiple_blocks:0,action_caller_conditionally_executed_blocks:0,action_cold_cc_penalty:0,action_callee_conditionally_executed_blocks:0,action_callee_users:0,action_callee_basic_block_count:0,action_nr_ctant_params:0,action_load_relative_intrinsic:0,action_jump_table_penalty:0,action_unsimplified_common_instructions:0,action_indirect_call_penalty:0,action_load_elimination:0,action_is_caller_avail_external:0,action_call_penalty:0,action_cost_estimate:0,action_case_cluster_penalty:0,action_node_count:0,action_call_argument_setup:0,action_sroa_savings:0,action_lowered_call_arg_setup:0,action_threshold:0,action_dead_blocks:0,action_constant_args:0,action_sroa_losses:0,action_simplified_instructions:0,action_num_loops:0,action_step_type:0,action_edge_count:0,action_is_callee_avail_external:0,action_nested_inlines:0,action_caller_basic_block_count:0,action_last_call_to_static_bonus:0,action_nested_inline_cost_estimate:0,action_callsite_height:0,action_constant_offset_ptr_args:0,action_switch_penalty:0,action_discount:0,action_caller_users:0,action_reward:0", outputs = "PartitionedCall:0"}, tf_saved_model.exported_names = ["action"]} {
+ %0 = "tosa.const"() <{values = dense<1> : tensor<i64>}> : () -> tensor<i64>
+ return %0 : tensor<i64>
+ }
+}
diff --git a/mlir/test/Integration/Dialect/EmitC/regalloc-eviction-test-model-tosa.mlir b/mlir/test/Integration/Dialect/EmitC/regalloc-eviction-test-model-tosa.mlir
new file mode 100644
index 0000000000000..eafbbe814c96a
--- /dev/null
+++ b/mlir/test/Integration/Dialect/EmitC/regalloc-eviction-test-model-tosa.mlir
@@ -0,0 +1,57 @@
+// DEFINE: %{pipeline} = "builtin.module(\
+// DEFINE: func.func(\
+// DEFINE: tosa-to-linalg-named,\
+// DEFINE: tosa-to-linalg,\
+// DEFINE: tosa-to-arith,\
+// DEFINE: tosa-to-tensor\
+// DEFINE: ),\
+// DEFINE: symbol-privatize,\
+// DEFINE: scalarize-single-element-tensor-return,\
+// DEFINE: one-shot-bufferize{\
+// DEFINE: bufferize-function-boundaries=true\
+// DEFINE: function-boundary-type-conversion=identity-layout-map\
+// DEFINE: buffer-alignment=0\
+// DEFINE: },\
+// DEFINE: buffer-results-to-out-params{\
+// DEFINE: hoist-static-allocs=true\
+// DEFINE: },\
+// DEFINE: buffer-deallocation-pipeline,\
+// DEFINE: func.func(\
+// DEFINE: convert-linalg-to-loops\
+// DEFINE: ),\
+// DEFINE: expand-strided-metadata,\
+// DEFINE: canonicalize,\
+// DEFINE: memref-elide-reinterpret-cast,\
+// DEFINE: convert-to-emitc,\
+// DEFINE: math-expand-ops{\
+// DEFINE: ops=rsqrt\
+// DEFINE: },\
+// DEFINE: arith-expand,\
+// DEFINE: convert-math-to-emitc,\
+// DEFINE: convert-arith-to-emitc\
+// DEFINE: )"
+
+// DEFINE: %{lower_to_emitc} = mlir-opt --pass-pipeline=%{pipeline} %s -o %t
+// DEFINE: %{translate} = mlir-translate -mlir-to-cpp %t -o %t.c
+// DEFINE: %{compile} = %host_cc -include stddef.h -include stdint.h -include stdlib.h\
+// DEFINE: -include stdbool.h -fsyntax-only -Wpedantic -Wall -Werror -Wno-unused %t.c
+
+/// Lower via the pipeline defined above
+// RUN: rm -f %t && %{lower_to_emitc} && FileCheck %s --input-file=%t && %{translate} && %{compile}
+
+/// Generated with llvm/lib/Analysis/models/gen-regalloc-eviction-test-model.py + llvm/lib/Analysis/models/saved-model-to-tflite.py
+/// Renamed "main" to avoid:
+/// error: 'main' should not be declared static
+/// error: first parameter of 'main' (argument count) must be of type 'int'
+// CHECK-LABEL: @mock_model
+// CHECK: for
+// CHECK: cmp gt
+// CHECK: conditional
+// CHECK: assign
+module attributes {tf_saved_model.semantics, tfl.description = "MLIR Converted.", tfl.metadata = {CONVERSION_METADATA = "\0C\00\00\00\08\00\0E\00\08\00\04\00\08\00\00\00\10\00\00\00$\00\00\00\00\00\06\00\08\00\04\00\06\00\00\00\04\00\00\00\00\00\00\00\00\00\0A\00\10\00\0C\00\08\00\04\00\0A\00\00\00\01\00\00\00\02\00\00\00\04\00\00\00\06\00\00\002.15.1\00\00", min_runtime_version = "1.9.0\00\00\00\00\00\00\00\00\00\00\00"}, tfl.schema_version = 3 : i32} {
+ func.func @mock_model(%arg0: tensor<33xi64> {tf_saved_model.index_path = ["mask"]}) -> (tensor<i64> {tf_saved_model.index_path = ["index_to_evict"]}) attributes {tf.entry_function = {inputs = "action_mask:0", outputs = "StatefulPartitionedCall:0"}, tf_saved_model.exported_names = ["action"]} {
+ %0 = tosa.cast %arg0 : (tensor<33xi64>) -> tensor<33xi32>
+ %1 = tosa.argmax %0 {axis = 0 : i32} : (tensor<33xi32>) -> tensor<i64>
+ return %1 : tensor<i64>
+ }
+}
More information about the Mlir-commits
mailing list