Skip to content

Conversation

@kimm240
Copy link
Contributor

@kimm240 kimm240 commented Dec 10, 2025

Overview

The Linalg pipeline transforms ONNX models into executable LLVM IR through a series of dialect conversions and optimizations. This document provides a detailed breakdown of all passes applied in the pipeline, including their locations, levels, and transformations.

Pipeline Flow

ONNX IR → [Preprocessing] → Linalg → [Bufferization] → Loops → Affine/SCF → CF → LLVM IR

Pass Application Summary Table

Step Pass Name Level Location Role Input → Output
Phase 1: ONNX → Linalg (addONNXToLinalgPasses)
1.1 createConvertONNXToLinalg() Func src/Conversion/ONNXToLinalg/ConvertONNXToLinalg.cpp
src/Compiler/CompilerPasses.cpp:243
ONNX → Linalg conversion onnx.MatMullinalg.matmul
1.2 ConvertONNXEntryPointToKrnlPass Module src/Compiler/CompilerPasses.cpp:251-278
(uses src/Conversion/ONNXToKrnl/ConvertONNXToKrnl.cpp)
Entry point conversion onnx.EntryPointkrnl.EntryPoint
1.3 createOneShotBufferizePass() Module MLIR standard library
src/Compiler/CompilerPasses.cpp:284
Tensor → Memref tensor<...>memref<...>
1.4 createCanonicalizerPass() Module MLIR standard library
src/Compiler/CompilerPasses.cpp:287
Canonicalization Optimization
Phase 2: Linalg → Affine/SCF → CF (addLinalgToAffinePasses)
2.1 createConvertLinalgToLoopsPass() Func MLIR standard library
src/Compiler/CompilerPasses.cpp:297
Linalg → Loops linalg.matmulaffine.for
2.2 createBufferLoopHoistingPass() Func MLIR standard library
src/Compiler/CompilerPasses.cpp:304
Memory allocation hoisting Move allocations outside loops
2.3 buildBufferDeallocationPipeline() Func MLIR standard library
src/Compiler/CompilerPasses.cpp:306-307
Memory deallocation Insert dealloc operations
2.4 createOptimizeAllocationLivenessPass() Func MLIR standard library
src/Compiler/CompilerPasses.cpp:308
Lifetime optimization Optimize allocation lifetimes
2.5 createConvertBufferizationToMemRefPass() Func MLIR standard library
src/Compiler/CompilerPasses.cpp:309
Bufferization → MemRef Standardize to memref ops
2.6 createLowerAffinePass() Func MLIR standard library
src/Compiler/CompilerPasses.cpp:312
Affine → SCF affine.forscf.for
2.7 createSCFToControlFlowPass() Func MLIR standard library
src/Compiler/CompilerPasses.cpp:313
SCF → CF scf.forcf.br
Phase 3: CF → LLVM (addLinalgToLLVMPasses)
3.1 createConvertKrnlToLLVMPass() Module src/Conversion/KrnlToLLVM/ConvertKrnlToLLVM.cpp
src/Compiler/CompilerPasses.cpp:334
Krnl → LLVM + Runtime krnl.EntryPoint → LLVM + Runtime functions
3.2 createReconcileUnrealizedCastsPass() Module MLIR standard library
src/Compiler/CompilerPasses.cpp:339
Cast resolution Resolve type casts
3.3 createCanonicalizerPass() Module MLIR standard library
src/Compiler/CompilerPasses.cpp:340
Final canonicalization Final optimization

Test

In test/mlir/conversion/onnx_to_linalg,

Test MLIR Code

Make MatMul.mlir in test/mlir/conversion/onnx_to_linalg
which has this code.

// Test MatMul conversion from ONNX to Linalg to LLVM IR
// This file tests the full pipeline: ONNX -> Linalg -> Affine -> LLVM IR

module {
  func.func @main_graph(%arg0: tensor<2x3xf32>, %arg1: tensor<3x4xf32>) -> tensor<2x4xf32> {
    %0 = "onnx.MatMul"(%arg0, %arg1) : (tensor<2x3xf32>, tensor<3x4xf32>) -> tensor<2x4xf32>
    return %0 : tensor<2x4xf32>
  }
  "onnx.EntryPoint"() {func = @main_graph} : () -> ()
}

ONNX → LLVM dialect

export PATH=$PATH:$(pwd)/build/Release/bin && onnx-mlir --use-linalg-path --EmitLLVMIR MatMul.mlir -o test_linalg

LLVM dialect → .so

onnx-mlir -O3 --EmitLib test_linalg.onnx.mlir

Compile driver for check

g++ --std=c++11 driver.cpp -o driver -I ~/onnx-mlir/include -L ~/onnx-mlir/build/Release/lib -lcruntime -ldl

Run Driver

export LD_LIBRARY_PATH=~/onnx-mlir/build/Release/lib:$LD_LIBRARY_PATH && ./driver

Result of Run

Found 2 entry point(s)
Expected result (2x4):
  Row 0: 38, 44, 50, 56
  Row 1: 83, 98, 113, 128

Actual output:
  Row 0: 38 44 50 56 
  Row 1: 83 98 113 128 

@jenkins-droid
Copy link
Collaborator

Can one of the admins verify this patch?

1 similar comment
@jenkins-droid
Copy link
Collaborator

Can one of the admins verify this patch?

@kimm240 kimm240 force-pushed the feature/linalg-to-llvm-pipeline branch from 956dfab to 7c0e1be Compare December 10, 2025 07:39
@jenkins-droid
Copy link
Collaborator

Can one of the admins verify this patch?

1 similar comment
@jenkins-droid
Copy link
Collaborator

Can one of the admins verify this patch?

@kimm240 kimm240 force-pushed the feature/linalg-to-llvm-pipeline branch from 1757183 to e505707 Compare December 10, 2025 09:10
@jenkins-droid
Copy link
Collaborator

Can one of the admins verify this patch?

hyun gyu kim added 23 commits December 15, 2025 18:29
Implement a new conversion pipeline from ONNX dialect to Linalg dialect.

Features:
- Convert ONNX MatMul operation to linalg.matmul
- Support 2D x 2D matrix multiplication only
- Use C++ style casting (dyn_cast) following coding guidelines
- Use latest MLIR API (OpTy::create pattern)
- Proper rank guard to reject unsupported dimensions

Implementation:
- Created ONNXToLinalg conversion infrastructure
- Implemented MatMul lowering pattern with rank validation
- Added ConvertONNXToLinalg pass registration

Tests:
- 3 positive test cases (2D x 2D with various sizes)
- 3 negative test cases (1D, 2D x 1D, 3D batch - not lowered)
- All tests pass with FileCheck validation

Files added:
- src/Conversion/ONNXToLinalg/ONNXToLinalgCommon.hpp
- src/Conversion/ONNXToLinalg/Math/MatMul.cpp
- src/Conversion/ONNXToLinalg/ConvertONNXToLinalg.cpp
- src/Conversion/ONNXToLinalg/CMakeLists.txt
- test/mlir/conversion/onnx_to_linalg/Math/MatMul.mlir

Files modified:
- src/Conversion/CMakeLists.txt (add subdirectory)
- src/Pass/Passes.hpp (add pass declaration)
- src/Tools/onnx-mlir-opt/RegisterPasses.cpp (register pass)

TODO: Add support for 1D, 2D x 1D, and batch matmul in future PRs
Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
- Add addONNXToLinalgPasses function to CompilerPasses.cpp
- Register tensor dialect in CompilerDialects.cpp
- Add Linalg passes header to CompilerPasses.cpp
- Integrate ONNX to Linalg pipeline into addPasses function

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
- Add bufferization passes to addONNXToLinalgPasses function
- Include buffer loop hoisting, deallocation pipeline, and memref conversion
- Complete the pipeline: ONNX → Linalg → Bufferization → Loops → Affine → LLVM
- Tested: ONNX to Linalg conversion works correctly

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
- Add useLinalgPath global variable and command line option
- Modify addPasses to conditionally execute Krnl or Linalg pipeline
- When --use-linalg-path is set, use Linalg lowering path instead of Krnl
- Default behavior remains Krnl path for compatibility
- Tested: Both paths work correctly

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
…gToLLVMPasses

- Split addONNXToLinalgPasses into two functions similar to Krnl pipeline
- addLinalgToAffinePasses: bufferization + Linalg to Loops + Lower Affine
- addLinalgToLLVMPasses: SCF to CF + Vector to LLVM + Control Flow to LLVM + MemRef to LLVM + Func to LLVM + Reconcile casts
- Update addPasses to call these functions conditionally based on emissionTarget
- This allows Linalg path to lower to Affine level when --EmitMLIR is used, similar to Krnl path

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
…ecution order

- Translate all Korean comments to English
- Add clear step-by-step comments explaining pass execution order
- Compare with Krnl path to identify differences
- Reorganize pass execution logic for better clarity
- Note: Linalg lowering passes are called but may not be executing properly

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
…nalg path

- Ensure addONNXToMLIRPasses is called when emissionTarget >= EmitMLIR and useLinalgPath is enabled
- Add check in ConvertONNXToLinalgPass to skip if no ONNX ops are present
- Reorganize pass execution logic to guarantee ONNX→Linalg conversion happens before Linalg→Affine lowering
- Note: Pass execution order is now correct, but Linalg lowering still not working as expected

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
- Move Linalg lowering passes into addONNXToMLIRPasses to ensure correct execution order
- Use nested pass manager to ensure ConvertONNXToLinalgPass runs before bufferization
- Add debug logs to track pass execution order
- Note: createLinalgBufferizePass() doesn't exist, using bufferization pipeline instead
- Note: Pass execution order issue still exists - ConvertONNXToLinalgPass runs after bufferization passes

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
- Move ConvertONNXToLinalgPass and Linalg lowering passes to end of addONNXToMLIRPasses
- Use pm.addNestedPass for ConvertONNXToLinalgPass, then pm.nest for subsequent passes
- This ensures module-level passes run first, then nested passes in order
- Note: Still investigating why bufferization passes don't execute after ConvertONNXToLinalgPass

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
…tion

- Tested various bufferization approaches:
  1. one-shot-bufferize: fails due to missing dialect extension registration
  2. convert-linalg-to-loops: doesn't convert tensor to memref
  3. buffer-loop-hoisting: only works on existing memrefs, not tensors

- Changed pass order to run convert-linalg-to-loops first
- Note: convert-linalg-to-loops doesn't handle tensor->memref conversion
- Root cause: Need tensor to memref conversion before lowering passes

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
- Add BufferizableOpInterface registration for one-shot bufferization
- Required for Linalg path to work with one-shot-bufferize pass
- Note: func dialect doesn't have BufferizableOpInterfaceImpl.h
- Progress: arith, linalg, tensor registered; func needs different approach

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
- Add FuncBufferizableOpInterfaceImpl.h header
- Register func dialect's BufferizableOpInterface using bufferization::func_ext namespace
- This enables one-shot-bufferize to work with func dialect operations
- All required dialects (arith, func, linalg, tensor) now have BufferizableOpInterface registered
- one-shot-bufferize now successfully converts tensor to memref

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
- Add one-shot-bufferize pass after ONNX->Linalg conversion
- Fix pass ordering: buffer management must run before convert-scf-to-cf
- buildBufferDeallocationPipeline requires structured control-flow loops
- All passes now execute successfully: ONNX -> Linalg -> Memref -> Loops -> Affine -> LLVM
- Successfully generates LLVM dialect IR

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
- Split addONNXToMLIRPasses: move Linalg-specific passes to addONNXToLinalgPasses
- addONNXToLinalgPasses: ONNX -> Linalg conversion (similar to addONNXToKrnlPasses)
- addLinalgToAffinePasses: Linalg -> Affine conversion (similar to addKrnlToAffinePasses)
- addLinalgToLLVMPasses: Linalg -> LLVM conversion (similar to addKrnlToLLVMPasses)
- Update addPasses to call functions in order: ONNX->Linalg, Linalg->Affine, Linalg->LLVM
- All emission targets (ONNXIR, MLIR, LLVMIR) now work correctly
- Structure now matches Krnl path for consistency

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
- Compare MatMul results from both pipelines at MLIR level
- Both pipelines produce identical computation logic:
  * Same input/output types (memref<2x3xf32>, memref<3x4xf32> -> memref<2x4xf32>)
  * Same memory allocation pattern
  * Same mathematical operations (arith.mulf, arith.addf)
  * Same loop order (i x j x k)
- Differences are only in loop representation:
  * Krnl: affine.for (structured loops)
  * Linalg: cf.br (unstructured, after SCF->CF conversion)
- Verified that both pipelines compute identical MatMul results

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
- Add RemoveONNXEntryPointPass to remove onnx.EntryPoint operations
- Krnl path converts onnx.EntryPoint to krnl.EntryPoint, but Linalg path doesn't use Krnl
- onnx.EntryPoint cannot be converted to LLVM, so it must be removed
- All emission targets (ONNXIR, MLIR, LLVMIR) now work correctly
- Linalg pipeline now successfully generates LLVM IR without errors

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
- Replace C-style casts (int) with C++ style static_cast<int>()
- Follow onnx-mlir coding practices for type casting
- Update debug logging in addPasses function

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
- Remove all [DEBUG] log statements from CompilerPasses.cpp and ConvertONNXToLinalg.cpp
- Simplify ConvertONNXToLinalgPass::runOnOperation by removing debug code
- Apply clang-format to ensure code style consistency
- Clean up unnecessary variables and logging statements

Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
Signed-off-by: hyun gyu kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
- Modified addLinalgToLLVMPasses to use createConvertKrnlToLLVMPass() instead of individual dialect conversion passes
- This ensures runtime functions (omQueryEntryPoints, omInputSignature, omOutputSignature) are generated
- Updated driver.cpp to use dlopen/dlsym instead of ExecutionSession.hpp
- Added outputNameNoExt parameter to addLinalgToLLVMPasses function signature

Signed-off-by: Hyun Gyu Kim <[email protected]>
- Identified that Linalg pipeline generates empty signatures [ ]@[ ]
- Krnl pipeline correctly generates signatures with type, dims, and name info
- Root cause: EntryPoint conversion happens after bufferization or is missing
- Need to convert onnx.EntryPoint to krnl.EntryPoint before bufferization

Signed-off-by: Hyun Gyu Kim <[email protected]>
- Replicate ONNXEntryPointLowering pattern from ConvertONNXToKrnl.cpp
  directly in CompilerPasses.cpp to avoid header dependency issues
- Ensure identical signature generation as Krnl pipeline
- Fix namespace issues (onnx_mlir::krnl instead of mlir::krnl)
- Linalg pipeline now correctly generates runtime entry point functions
  (omQueryEntryPoints, omInputSignature, omOutputSignature)
- Verified MatMul execution produces correct results with proper input shapes

Signed-off-by: Hyun Gyu Kim <[email protected]>
- Convert all Korean comments to English in test driver
- Improve code readability for international contributors
- Driver tests MatMul execution with correct input shapes (2x3 and 3x4)

Signed-off-by: Hyun Gyu Kim <[email protected]>
hyun gyu kim and others added 20 commits December 15, 2025 18:29
- Add driver.cpp in test/mlir/conversion/onnx_to_linalg/
- Driver tests MatMul execution with correct input shapes (2x3 and 3x4)
- Verifies Linalg pipeline produces correct results (2x4 output)
- All comments in English for international contributors

Signed-off-by: Hyun Gyu Kim <[email protected]>
- Add populateLoweringONNXEntryPointOpPattern() function to ONNXToKrnlCommon.hpp
- Implement the function in ConvertONNXToKrnl.cpp to reuse ONNXEntryPointLowering pattern
- Replace duplicated code in CompilerPasses.cpp with function call
- Rename createConvertONNXToLinalgPass() to createConvertONNXToLinalg() to match MLIR naming convention
- Remove code duplication and improve maintainability

Signed-off-by: Hyun Gyu Kim <[email protected]>
- Format CompilerPasses.cpp: fix include order and line breaks
- Format ConvertONNXToLinalg.cpp: fix long line formatting

Signed-off-by: Hyun Gyu Kim <[email protected]>
- Remove unused test files from conversion directories
- Clean up temporary files

Signed-off-by: Hyun Gyu Kim <[email protected]>
- Remove unused files and organize directory structure

Signed-off-by: Hyun Gyu Kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
… in check-onnx-backend-constant (onnx#3344)

* Support empty inputs to the compiled model

Signed-off-by: Tung D. Le <[email protected]>

* better code

Signed-off-by: Tung D. Le <[email protected]>

* black

Signed-off-by: Tung D. Le <[email protected]>

---------

Signed-off-by: Tung D. Le <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
* Make dynamic dimension analysis for Reshape more general

Signed-off-by: Tung D. Le <[email protected]>

---------

Signed-off-by: Tung D. Le <[email protected]>
Co-authored-by: Alexandre Eichenberger <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
Signed-off-by: Alexandre Eichenberger <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
…zation (onnx#3340)

Signed-off-by: Tung D. Le <[email protected]>
Co-authored-by: Alexandre Eichenberger <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
* change

Signed-off-by: Chen Tong <[email protected]>

* handle null

Signed-off-by: Chen Tong <[email protected]>

* fix backend test

Signed-off-by: Tong Chen <[email protected]>

* fix check-onnx-backend-constant

Signed-off-by: Tong Chen <[email protected]>

* fix lit test

Signed-off-by: Tong Chen <[email protected]>

* for PR3344

Signed-off-by: Tong Chen <[email protected]>

* reverse

Signed-off-by: Tong Chen <[email protected]>

* disable check for dynamic

Signed-off-by: Tong Chen <[email protected]>

* remove extra changes

Signed-off-by: Tong Chen <[email protected]>

* fix dim value check

Signed-off-by: Tong Chen <[email protected]>

* format

Signed-off-by: Tong Chen <[email protected]>

* fix print

Signed-off-by: Tong Chen <[email protected]>

* format

Signed-off-by: Tong Chen <[email protected]>

---------

Signed-off-by: Chen Tong <[email protected]>
Signed-off-by: Tong Chen <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
* fix osx build for deprecation of git image

Signed-off-by: Sunny Anand <[email protected]>

* update requirements to match the installed protobuf

Signed-off-by: Sunny Anand <[email protected]>

* correct version

Signed-off-by: Sunny Anand <[email protected]>

* correct version

Signed-off-by: Sunny Anand <[email protected]>

---------

Signed-off-by: Sunny Anand <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
* Add ONNXToLinalg conversion pass with MatMul support

Implement a new conversion pipeline from ONNX dialect to Linalg dialect.

Features:
- Convert ONNX MatMul operation to linalg.matmul
- Support 2D x 2D matrix multiplication only
- Use C++ style casting (dyn_cast) following coding guidelines
- Use latest MLIR API (OpTy::create pattern)
- Proper rank guard to reject unsupported dimensions

Implementation:
- Created ONNXToLinalg conversion infrastructure
- Implemented MatMul lowering pattern with rank validation
- Added ConvertONNXToLinalg pass registration

Tests:
- 3 positive test cases (2D x 2D with various sizes)
- 3 negative test cases (1D, 2D x 1D, 3D batch - not lowered)
- All tests pass with FileCheck validation

Files added:
- src/Conversion/ONNXToLinalg/ONNXToLinalgCommon.hpp
- src/Conversion/ONNXToLinalg/Math/MatMul.cpp
- src/Conversion/ONNXToLinalg/ConvertONNXToLinalg.cpp
- src/Conversion/ONNXToLinalg/CMakeLists.txt
- test/mlir/conversion/onnx_to_linalg/Math/MatMul.mlir

Files modified:
- src/Conversion/CMakeLists.txt (add subdirectory)
- src/Pass/Passes.hpp (add pass declaration)
- src/Tools/onnx-mlir-opt/RegisterPasses.cpp (register pass)

TODO: Add support for 1D, 2D x 1D, and batch matmul in future PRs
Signed-off-by: hyun gyu kim <[email protected]>

* Rename createConvertONNXToLinalgPass to createConvertONNXToLinalg

Update function name to follow MLIR naming convention by removing 'Pass' suffix.

Signed-off-by: hyun gyu kim <[email protected]>

---------

Signed-off-by: hyun gyu kim <[email protected]>
Co-authored-by: hyun gyu kim <[email protected]>
Co-authored-by: Alexandre Eichenberger <[email protected]>
Co-authored-by: Tung D. Le <[email protected]>
Co-authored-by: Tong Chen <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
Signed-off-by: Hyun Gyu Kim <[email protected]>
@kimm240 kimm240 force-pushed the feature/linalg-to-llvm-pipeline branch from 34310e5 to 779c1b9 Compare December 15, 2025 09:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants