diff --git a/.github/workflows/minimal-onnx-dialect.yml b/.github/workflows/minimal-onnx-dialect.yml new file mode 100644 index 0000000000..5ff9fb4274 --- /dev/null +++ b/.github/workflows/minimal-onnx-dialect.yml @@ -0,0 +1,50 @@ +name: Minimal ONNX dialect build + +on: + pull_request: + push: + +jobs: + build-minimal: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + - uses: actions/setup-python@v4 + with: + python-version: '3.10' + - name: Install prerequisites + run: | + sudo apt-get update + sudo apt-get install -y ninja-build cmake gcc g++ python3-pip + - name: Cache MLIR build + id: cache-mlir + uses: actions/cache@v3 + with: + path: llvm-project + key: ${{ runner.os }}-mlir-${{ hashFiles('utils/clone-mlir.sh', 'utils/build-mlir.sh') }} + - name: Clone + build MLIR + if: steps.cache-mlir.outputs.cache-hit != 'true' + run: | + bash utils/clone-mlir.sh + bash utils/build-mlir.sh + - name: Configure minimal build + run: | + cmake -S . -B build -G Ninja \ + -DMLIR_DIR=$GITHUB_WORKSPACE/llvm-project/build/lib/cmake/mlir \ + -DONNX_MLIR_ENABLE_ONLY_ONNX_DIALECT=ON \ + -DCMAKE_BUILD_TYPE=Release + - name: Build test-onnx-to-mlir + run: | + cmake --build build --target test-onnx-to-mlir -j2 + - name: Smoke test + run: | + echo 'digraph G { }' > /tmp/empty.onnx || true + # Use a known small ONNX from torch-mlir tests if present in tree; otherwise skip. + if [ -f third_party/onnx/onnx/backend/test/data/node/test_relu/model.onnx ]; then + build/Release/bin/test-onnx-to-mlir third_party/onnx/onnx/backend/test/data/node/test_relu/model.onnx | head -n 20 + else + echo 'Minimal build completed.' + fi + diff --git a/CMakeLists.txt b/CMakeLists.txt index b9ef78d799..bd222187a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,7 @@ option(ONNX_MLIR_ENABLE_WERROR "Enable warnings as errors." OFF) option(ONNX_MLIR_SUPPRESS_THIRD_PARTY_WARNINGS "Suppress warning in third_party code." ON) option(ONNX_MLIR_ENABLE_JAVA "Set to ON for building the Java runtime, tools, and tests" ON) option(ONNX_MLIR_ENABLE_PYRUNTIME_LIGHT "Set to ON for building Python driver of running the compiled model without llvm-project." OFF) +option(ONNX_MLIR_ENABLE_ONLY_ONNX_DIALECT "Build only ONNX dialect without lowering passes and runtime" OFF) set(CMAKE_CXX_STANDARD 17) @@ -162,7 +163,10 @@ endif() set(CMAKE_MESSAGE_LOG_LEVEL NOTICE) # Add third party subdirectories and define options appropriate to run their cmakes. -if (ONNX_MLIR_ENABLE_PYRUNTIME_LIGHT) +if (ONNX_MLIR_ENABLE_ONLY_ONNX_DIALECT) + # Minimal build: only include ONNX protobuf library. + add_subdirectory(third_party/onnx) +elseif (ONNX_MLIR_ENABLE_PYRUNTIME_LIGHT) add_subdirectory(third_party/onnx) add_subdirectory(third_party/pybind11) else() @@ -195,13 +199,15 @@ endif() # compile flags updated via llvm_update_compile_flags, so we need to do that to # benchmark and rapidcheck as well, so that we can successfully link against them. # Otherwise, some of the flags for exceptions (among others) are not set correctly. -llvm_update_compile_flags(benchmark) -llvm_update_compile_flags(benchmark_main) -llvm_update_compile_flags(rapidcheck) +if (NOT ONNX_MLIR_ENABLE_ONLY_ONNX_DIALECT) + llvm_update_compile_flags(benchmark) + llvm_update_compile_flags(benchmark_main) + llvm_update_compile_flags(rapidcheck) -if (ONNX_MLIR_ENABLE_STABLEHLO) - llvm_update_compile_flags(stablehlo-opt) - llvm_update_compile_flags(stablehlo-translate) + if (ONNX_MLIR_ENABLE_STABLEHLO) + llvm_update_compile_flags(stablehlo-opt) + llvm_update_compile_flags(stablehlo-translate) + endif() endif() # Increase the log level for onnx-mlir @@ -216,11 +222,19 @@ if (ONNX_MLIR_SUPPRESS_THIRD_PARTY_WARNINGS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSUPPRESS_THIRD_PARTY_WARNINGS") endif() -if (ONNX_MLIR_ENABLE_STABLEHLO) +if (ONNX_MLIR_ENABLE_STABLEHLO AND NOT ONNX_MLIR_ENABLE_ONLY_ONNX_DIALECT) add_compile_definitions(ONNX_MLIR_ENABLE_STABLEHLO) endif() -if (ONNX_MLIR_ENABLE_PYRUNTIME_LIGHT) +if (ONNX_MLIR_ENABLE_ONLY_ONNX_DIALECT) + # Minimal build: only include headers and ONNX dialect source. + add_subdirectory(include) + add_subdirectory(src/Interface) + add_subdirectory(src/Support) + add_subdirectory(src/Builder) + add_subdirectory(src/Dialect/Mlir) + add_subdirectory(src/Dialect/ONNX) +elseif (ONNX_MLIR_ENABLE_PYRUNTIME_LIGHT) add_subdirectory(src) else() add_subdirectory(utils) @@ -228,4 +242,4 @@ else() add_subdirectory(src) add_subdirectory(docs) add_subdirectory(test) -endif() +endif() \ No newline at end of file diff --git a/README.md b/README.md index 93a2e32626..e92c4e3944 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,38 @@ After installation, an `onnx-mlir` executable should appear in the `build/Debug/ If you have difficulties building, rebuilding, or testing `onnx-mlir`, check this [page](docs/TestingHighLevel.md) for helpful hints. +### Minimal build for ONNX dialect only + +For consumers that only need the ONNX dialect (without lowering passes, runtime, or non-essential dialects), configure with: + +``` +cmake -S . -B build -G Ninja \ + -DMLIR_DIR=/path/to/llvm-project/build/lib/cmake/mlir \ + -DONNX_MLIR_ENABLE_ONLY_ONNX_DIALECT=ON \ + -DCMAKE_BUILD_TYPE=Release + +cmake --build build --target test-onnx-to-mlir -j$(nproc) +``` + +This builds only the following components: +- `include/` +- `src/Interface/` (only interfaces required by ONNX) +- `src/Support/` +- `src/Builder/` +- `src/Dialect/Mlir/` +- `src/Dialect/ONNX/` + +And provides a small test executable `test-onnx-to-mlir` that loads an ONNX model and prints ONNX dialect IR: + +``` +build/Release/bin/test-onnx-to-mlir model.onnx > model.mlir +``` + +Notes: +- Release builds are recommended to reduce memory usage during compilation. +- SpecializedKernel and Krnl dependencies are excluded in this mode. + + ## Using ONNX-MLIR The usage of `onnx-mlir` is as such: diff --git a/docs/MinimalONNXDialectBuild.md b/docs/MinimalONNXDialectBuild.md new file mode 100644 index 0000000000..ee31199fff --- /dev/null +++ b/docs/MinimalONNXDialectBuild.md @@ -0,0 +1,48 @@ + + +## Minimal ONNX dialect build + +This document describes how to build a minimal subset of ONNX-MLIR that exposes only the ONNX dialect and the minimal helpers required to parse ONNX models and produce ONNX dialect MLIR. + +### Rationale + +Some projects want to import the ONNX dialect IR without bringing the full onnx-mlir stack (lowering passes, Krnl dialect, runtime). The CMake option `ONNX_MLIR_ENABLE_ONLY_ONNX_DIALECT` enables such a build. + +### What gets built + +When `-DONNX_MLIR_ENABLE_ONLY_ONNX_DIALECT=ON` is set, the following subdirectories are included: + +- `include/` +- `src/Interface/` (ShapeInference, ResultTypeInference, HasOnnxSubgraph, ShapeHelper) +- `src/Support/` +- `src/Builder/` (for `ImportFrontendModelFile` and builders) +- `src/Dialect/Mlir/` (utility builders only; no Krnl or Compiler dependencies) +- `src/Dialect/ONNX/` + +In addition, a small utility `test-onnx-to-mlir` is built to load an ONNX model and print the ONNX dialect IR. + +### Configure and build + +``` +cmake -S . -B build -G Ninja \ + -DMLIR_DIR=/path/to/llvm-project/build/lib/cmake/mlir \ + -DONNX_MLIR_ENABLE_ONLY_ONNX_DIALECT=ON \ + -DCMAKE_BUILD_TYPE=Release + +cmake --build build --target test-onnx-to-mlir -j$(nproc) +``` + +Release builds are recommended to lower memory usage during compilation. + +### Using the test helper + +``` +build/Release/bin/test-onnx-to-mlir /path/to/model.onnx > model.mlir +``` + +### Notes + +- Krnl and Compiler modules are excluded. +- SpecializedKernel interface is excluded. +- The minimal build still requires the upstream LLVM/MLIR toolchain and ONNX protobuf. + diff --git a/src/Builder/CMakeLists.txt b/src/Builder/CMakeLists.txt index cfdd25751d..296126876c 100644 --- a/src/Builder/CMakeLists.txt +++ b/src/Builder/CMakeLists.txt @@ -21,4 +21,4 @@ add_onnx_mlir_library(OMBuilder configure_file(OpBuildTable.inc.dc.in ${CMAKE_CURRENT_BINARY_DIR}/OpBuildTable.inc.dc @ONLY - ) + ) \ No newline at end of file diff --git a/src/Dialect/Mlir/CMakeLists.txt b/src/Dialect/Mlir/CMakeLists.txt index 01b4062aa4..3644418894 100644 --- a/src/Dialect/Mlir/CMakeLists.txt +++ b/src/Dialect/Mlir/CMakeLists.txt @@ -7,12 +7,7 @@ add_onnx_mlir_library(OMMlirDialects DialectBuilder.cpp VectorMachineSupport.cpp - DEPENDS - OMKrnlIncGen - OMSpecializedKernelOpInterface - LINK_LIBS PUBLIC - OMCompilerOptions MLIRMathDialect MLIRAffineDialect MLIRSCFDialect diff --git a/src/Dialect/Mlir/DialectBuilder.cpp b/src/Dialect/Mlir/DialectBuilder.cpp index 2573272136..63783649e6 100644 --- a/src/Dialect/Mlir/DialectBuilder.cpp +++ b/src/Dialect/Mlir/DialectBuilder.cpp @@ -25,7 +25,6 @@ #include "llvm/Support/Debug.h" // Please do not add dependences on ONNX or KRNL dialects. -#include "src/Compiler/CompilerOptions.hpp" #include "src/Dialect/Mlir/DialectBuilder.hpp" #include "src/Dialect/Mlir/VectorMachineSupport.hpp" @@ -1757,16 +1756,12 @@ Value MemRefBuilder::dim(Value val, Value index) const { void MemRefBuilder::prefetch(Value memref, ValueRange indices, bool isWrite, unsigned locality, bool isData) { - if (disableMemRefPrefetch) - return; b().create( loc(), memref, indices, isWrite, locality, isData); } void MemRefBuilder::prefetchIE(Value memref, ArrayRef indices, bool isWrite, unsigned locality, bool isData) { - if (disableMemRefPrefetch) - return; SmallVector indexVals; IndexExpr::getValues(indices, indexVals); prefetch(memref, indexVals, isWrite, locality, isData); diff --git a/src/Dialect/Mlir/VectorMachineSupport.cpp b/src/Dialect/Mlir/VectorMachineSupport.cpp index 8e3e50f9de..5363991eab 100644 --- a/src/Dialect/Mlir/VectorMachineSupport.cpp +++ b/src/Dialect/Mlir/VectorMachineSupport.cpp @@ -9,7 +9,6 @@ // ============================================================================= #include "src/Dialect/Mlir/VectorMachineSupport.hpp" -#include "src/Compiler/CompilerOptions.hpp" #include "mlir/IR/BuiltinTypes.h" #include "llvm/Support/Debug.h" @@ -22,6 +21,29 @@ using namespace mlir; namespace onnx_mlir { +// Minimal version of getZArchNum to avoid dependency on Compiler module +namespace { +int64_t decodeZArchNum(std::string str) { + if (str == "arch12" || str == "z14") // Z14 and equivalents. + return 12; + if (str == "arch13" || str == "z15") // Z15 and equivalents. + return 13; + if (str == "arch14" || str == "z16") // Z16 and equivalents. + return 14; + if (str == "arch15" || str == "z17") // Z17 and equivalents. + return 15; + return -1; +} + +int64_t getZArchNumLocal(const std::string &arch, const std::string cpu) { + // Give priority to march, use (deprecated) mcpu if march is not defined. + int64_t num = decodeZArchNum(arch); + if (num == -1) + num = decodeZArchNum(cpu); + return num; +} +} // anonymous namespace + // ============================================================================= // Handling of global vector machine support pointer @@ -31,7 +53,7 @@ namespace onnx_mlir { /*static*/ void VectorMachineSupport::setGlobalVectorMachineSupport( const std::string &arch, const std::string &cpu, const std::string &attr) { // IBM Z servers use march (deprecated mcpu), process here. - int64_t zArchNum = getZArchNum(arch, cpu); + int64_t zArchNum = getZArchNumLocal(arch, cpu); if (zArchNum == 12) { globalVectorMachineSupport = new ZArch12VectorMachineSupport(); } else if (zArchNum == 13) { diff --git a/src/Dialect/ONNX/CMakeLists.txt b/src/Dialect/ONNX/CMakeLists.txt index 1802f7d8ee..eaf9c636ed 100644 --- a/src/Dialect/ONNX/CMakeLists.txt +++ b/src/Dialect/ONNX/CMakeLists.txt @@ -124,7 +124,22 @@ add_onnx_mlir_library(OMONNXOps MLIRMemRefTransforms ) +# Add the generated directory to the include path so interface headers can find the generated files +target_include_directories(OMONNXOps PRIVATE ${GEN_DIR}) + configure_file(ONNXOps.td.inc.dc.in ${CMAKE_CURRENT_BINARY_DIR}/ONNXOps.td.inc.dc @ONLY ) + +# Add test executable +add_onnx_mlir_executable(test-onnx-to-mlir + test-onnx-to-mlir.cpp + + LINK_LIBS PRIVATE + OMONNXOps + OMBuilder + MLIRFuncDialect + MLIRSupport + LLVMSupport + ) diff --git a/src/Dialect/ONNX/test-onnx-to-mlir.cpp b/src/Dialect/ONNX/test-onnx-to-mlir.cpp new file mode 100644 index 0000000000..f881bf4f38 --- /dev/null +++ b/src/Dialect/ONNX/test-onnx-to-mlir.cpp @@ -0,0 +1,47 @@ +// test-onnx-to-mlir.cpp + +#include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/IR/BuiltinOps.h" +#include "mlir/IR/DialectRegistry.h" +#include "mlir/IR/MLIRContext.h" + +#include "src/Builder/FrontendDialectTransformer.hpp" +#include "src/Dialect/ONNX/ONNXDialect.hpp" +#include "llvm/Support/InitLLVM.h" +#include "llvm/Support/raw_ostream.h" + +int main(int argc, char **argv) { + llvm::InitLLVM y(argc, argv); + + if (argc != 2) { + llvm::errs() << "Usage: test-onnx-to-mlir \n"; + return 1; + } + + mlir::MLIRContext context; + + // Register the ONNX dialect. + mlir::DialectRegistry registry; + registry.insert(); + registry.insert(); + context.appendDialectRegistry(registry); + context.loadAllAvailableDialects(); + + // Import the ONNX model. + mlir::OwningOpRef module; + std::string errorMessage; + onnx_mlir::ImportOptions options; + + int result = onnx_mlir::ImportFrontendModelFile( + argv[1], context, module, &errorMessage, options); + + if (result != 0) { + llvm::errs() << "Failed to import model: " << errorMessage << "\n"; + return 1; + } + + llvm::outs() << "Successfully imported ONNX model!\n"; + module->print(llvm::outs()); + + return 0; +} \ No newline at end of file diff --git a/src/Interface/CMakeLists.txt b/src/Interface/CMakeLists.txt index 07a1eb6873..fc3852d43b 100644 --- a/src/Interface/CMakeLists.txt +++ b/src/Interface/CMakeLists.txt @@ -4,7 +4,11 @@ add_onnx_mlir_interface(ShapeInferenceOpInterface) add_onnx_mlir_interface(ShapeHelperOpInterface) add_onnx_mlir_interface(ResultTypeInferenceOpInterface) add_onnx_mlir_interface(HasOnnxSubgraphOpInterface) -add_onnx_mlir_interface(SpecializedKernelOpInterface) + +# Conditionally build the SpecializedKernel interface. +if(NOT ONNX_MLIR_ENABLE_ONLY_ONNX_DIALECT) + add_onnx_mlir_interface(SpecializedKernelOpInterface) +endif() add_onnx_mlir_library(OMShapeInferenceOpInterface ShapeInferenceOpInterface.cpp @@ -50,14 +54,15 @@ add_onnx_mlir_library(OMHasOnnxSubgraphOpInterface MLIRIR LLVMSupport ) - -add_onnx_mlir_library(OMSpecializedKernelOpInterface - SpecializedKernelOpInterface.cpp - - DEPENDS - OMSpecializedKernelOpInterfaceIncGen - - LINK_LIBS PUBLIC - MLIRIR - LLVMSupport - ) +if(NOT ONNX_MLIR_ENABLE_ONLY_ONNX_DIALECT) + add_onnx_mlir_library(OMSpecializedKernelOpInterface + SpecializedKernelOpInterface.cpp + + DEPENDS + OMSpecializedKernelOpInterfaceIncGen + + LINK_LIBS PUBLIC + MLIRIR + LLVMSupport + ) +endif() \ No newline at end of file