[llvm] [MLGO] Model selection for models lowered through EmitC (PR #212650)

Petr Hosek via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 14 12:01:42 PDT 2026


================
@@ -0,0 +1,136 @@
+# Lower MLGO models to C++ headers via the MLIR-based pipeline.
+#
+# Each entry in ${models} has the form "cli-flag,path/to/model.mlir,type".
+# For entries whose type matches ${target_type}, this function:
+#   1. Lowers model MLIR with ${mlir_opt} and translates it with ${mlir_translate}
+#      to a C++ header defining Model<N> in ${LLVM_INCLUDE_DIR}/${include_subdir}.
+#   2. Generates ${generated_file_basename}.def in ${LLVM_INCLUDE_DIR}/${include_subdir}
+#      with one MLGO_MODEL(ClassName, "cli-flag") entry per model.
+#   3. Generates ${generated_file_basename}.h in ${LLVM_INCLUDE_DIR}/${include_subdir}
+#      including all generated model headers.
+#   4. Appends the target driving generation to MLDeps in the caller's scope.
+#   5. Defines LLVM_HAVE_MLIR_LOWERING_<TARGET_TYPE>.
+function(mlgo_lower_models models mlir_opt mlir_translate target_type
+         include_subdir generated_file_basename)
+  set(def_file "${generated_file_basename}.def")
+  set(umbrella_header "${generated_file_basename}.h")
+
+  if(NOT IS_ABSOLUTE "${mlir_opt}")
+    cmake_path(ABSOLUTE_PATH mlir_opt BASE_DIRECTORY "${CMAKE_BINARY_DIR}")
+  endif()
+
+  if(NOT IS_ABSOLUTE "${mlir_translate}")
+    cmake_path(ABSOLUTE_PATH mlir_translate BASE_DIRECTORY "${CMAKE_BINARY_DIR}")
+  endif()
+
+  string(APPEND DEF_CONTENT
+    "/* Auto-generated by CMake */\n"
+    "#ifndef MLGO_MODEL\n"
+    "#  define MLGO_MODEL(CLASS_NAME, CLI_FLAG)\n"
+    "#endif\n\n"
+  )
+
+  set(HEADERS_CONTENT "/* Auto-generated by CMake */\nnamespace llvm {\n")
+  set(MLGO_GEN_TARGETS "")
+  set(MODEL_INDEX 1)
+
+  foreach(MODEL_INFO IN LISTS models)
+    # Parse comma-separated fields (from the LLVM_MLGO_MODELS flag)
+    # cli-flag,path/to/model.mlir,type
+    string(REPLACE "," ";" MODEL_FIELDS "${MODEL_INFO}")
+    list(GET MODEL_FIELDS 0 CLI_FLAG)
+    list(GET MODEL_FIELDS 1 MODEL_PATH)
+    list(GET MODEL_FIELDS 2 MODEL_TYPE)
+
+    # Only process models matching target_type
+    if (NOT MODEL_TYPE STREQUAL target_type)
+      continue()
+    endif()
+
+    set(CLASS_NAME "${target_type}_Model${MODEL_INDEX}")
+    math(EXPR MODEL_INDEX "${MODEL_INDEX} + 1")
+
+    if (NOT IS_ABSOLUTE "${MODEL_PATH}")
+      get_filename_component(MODEL_PATH "${MODEL_PATH}" ABSOLUTE BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+    endif()
+
+    set(EMITC_MLIR "${CMAKE_CURRENT_BINARY_DIR}/${CLASS_NAME}_emitc.mlir")
+    set(HEADER_FILE "${LLVM_INCLUDE_DIR}/${include_subdir}/${CLASS_NAME}.h")
+
+    # Pass pipeline to lower MLIR models to EmitC dialect
+    # TODO: Simplify with builtin pipeline for translation.
+    # TODO: It isn't ideal to hardcode this pass pipeline here. It would be better to
+    # use the transform dialect.
+    set(MLIR_PASSES
+      "func.func(tosa-to-linalg-named,tosa-to-linalg,tosa-to-arith,tosa-to-tensor)"
+      "symbol-privatize"
+      "scalarize-single-element-tensor-return"
+      "one-shot-bufferize{bufferize-function-boundaries=true function-boundary-type-conversion=identity-layout-map buffer-alignment=0}"
+      "buffer-results-to-out-params{hoist-static-allocs=true}"
+      "func.func(promote-buffers-to-stack)"
+      "buffer-deallocation-pipeline"
+      "func.func(convert-linalg-to-loops)"
+      "expand-strided-metadata"
+      "canonicalize"
+      "memref-elide-reinterpret-cast"
+      "convert-to-emitc"
+      "wrap-emitc-func-in-class{class-name-format=${CLASS_NAME}}"
+      "mlgo-add-reflection-map{included-field-attrs=tf_saved_model.index_path}"
+      "math-expand-ops{ops=rsqrt}"
+      "arith-expand"
+      "convert-math-to-emitc"
+      "convert-arith-to-emitc"
+    )
+    string(JOIN "," PASS_PIPELINE ${MLIR_PASSES})
+    set(PASS_PIPELINE "builtin.module(${PASS_PIPELINE})")
+
+    # 1. Run MLIR pipeline to lower MODEL_PATH to EmitC MLIR
+    add_custom_command(OUTPUT ${EMITC_MLIR}
+      COMMAND ${mlir_opt} "--pass-pipeline=${PASS_PIPELINE}"
+      ${MODEL_PATH} -o ${EMITC_MLIR}
+      DEPENDS ${MODEL_PATH}
+      VERBATIM
+    )
+
+    # 2. Translate EmitC MLIR to C++ header
+    add_custom_command(OUTPUT ${HEADER_FILE}
+      COMMAND ${mlir_translate} -mlir-to-cpp ${EMITC_MLIR} -o ${HEADER_FILE} --mlir-print-stacktrace-on-diagnostic
+      DEPENDS ${EMITC_MLIR}
+      VERBATIM
+    )
+
+    # Set properties so CMake knows these are generated during the build
+    set_source_files_properties(${EMITC_MLIR} PROPERTIES GENERATED 1)
+    set_source_files_properties(${HEADER_FILE} PROPERTIES GENERATED 1)
+
+    # Custom target to force generation of this header
+    add_custom_target(mlgo_model_gen_${MODEL_TYPE}_${CLASS_NAME} DEPENDS ${HEADER_FILE})
+    list(APPEND MLGO_GEN_TARGETS mlgo_model_gen_${MODEL_TYPE}_${CLASS_NAME})
+
+    # Append the model metadata to the .def file
+    string(APPEND DEF_CONTENT "MLGO_MODEL(${CLASS_NAME}, \"${CLI_FLAG}\")\n")
+
+    # Append to the master header content
+    string(APPEND HEADERS_CONTENT "namespace ${CLASS_NAME}_ns {\n#include \"${include_subdir}/${CLASS_NAME}.h\"\n} // namespace ${CLASS_NAME}_ns\nusing ${CLASS_NAME}_ns::${CLASS_NAME};\n")
+  endforeach()
+
+  string(APPEND DEF_CONTENT "\n#undef MLGO_MODEL\n")
+  string(APPEND HEADERS_CONTENT "} // namespace llvm\n")
+
+  # Stage the generated files, then only update the copies under
+  # LLVM_INCLUDE_DIR when their content changed, so that reconfiguring does not
+  # trigger rebuilds of their consumers.
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${def_file}.tmp" "${DEF_CONTENT}")
+  configure_file("${CMAKE_CURRENT_BINARY_DIR}/${def_file}.tmp"
+    "${LLVM_INCLUDE_DIR}/${include_subdir}/${def_file}" COPYONLY)
+  file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/${umbrella_header}.tmp" "${HEADERS_CONTENT}")
+  configure_file("${CMAKE_CURRENT_BINARY_DIR}/${umbrella_header}.tmp"
+    "${LLVM_INCLUDE_DIR}/${include_subdir}/${umbrella_header}" COPYONLY)
+
+  if (MLGO_GEN_TARGETS)
+    add_custom_target(mlgo_models_gen_${target_type} DEPENDS ${MLGO_GEN_TARGETS})
+    set(MLDeps ${MLDeps} mlgo_models_gen_${target_type} PARENT_SCOPE)
----------------
petrhosek wrote:

Modifying variable in the parent scope to return a value is error-prone. I either use an output variable (preferable) or a global property.

https://github.com/llvm/llvm-project/pull/212650


More information about the llvm-commits mailing list