Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions cmake/onnxruntime_mlas.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ onnxruntime_add_static_library(onnxruntime_mlas
${MLAS_SRC_DIR}/threading.cpp
${MLAS_SRC_DIR}/sgemm.cpp
${MLAS_SRC_DIR}/halfgemm.cpp
${MLAS_SRC_DIR}/halfconv.cpp
${MLAS_SRC_DIR}/qgemm.cpp
${MLAS_SRC_DIR}/qdwconv.cpp
${MLAS_SRC_DIR}/convolve.cpp
Expand Down Expand Up @@ -326,6 +327,8 @@ function(setup_kleidiai)
target_sources(onnxruntime_mlas PRIVATE
${MLAS_SRC_DIR}/kai_ukernel_interface.cpp
${MLAS_SRC_DIR}/kleidiai/sgemm_kleidiai.cpp
${MLAS_SRC_DIR}/kleidiai/halfgemm_kleidiai.cpp
${MLAS_SRC_DIR}/kleidiai/halfconv_kleidiai.cpp
${MLAS_SRC_DIR}/kleidiai/sbgemm_kleidiai.cpp
${MLAS_SRC_DIR}/kleidiai/convolve_kleidiai.cpp
${MLAS_SRC_DIR}/kleidiai/qgemm_kleidiai.cpp
Expand Down
1 change: 1 addition & 0 deletions onnxruntime/contrib_ops/cpu/moe/moe_cpu.cc
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,7 @@ Status MoE<MLFloat16>::ComputeGEMM(const MLFloat16* A, const MLFloat16* B, MLFlo
} else {
params.ldb = static_cast<size_t>(N);
}
params.BackendKernelSelectorConfig = &mlas_backend_kernel_selector_config_;

MlasHalfGemmBatch(static_cast<size_t>(M), static_cast<size_t>(N), static_cast<size_t>(K), 1, &params, nullptr);
return Status::OK();
Expand Down
130 changes: 129 additions & 1 deletion onnxruntime/core/mlas/inc/mlas.h
Original file line number Diff line number Diff line change
Expand Up @@ -893,6 +893,10 @@ struct MLAS_CONV_PARAMETERS {
size_t BatchCount;
size_t GroupCount;
size_t InputChannels;
/**
* Existing Conv layout flag from MlasConvPrepare; for HalfConv this matches
* InputOutputChannelsLast.
*/
bool ChannelsLast;
size_t InputShape[3];
size_t KernelShape[3];
Expand All @@ -911,6 +915,12 @@ struct MLAS_CONV_PARAMETERS {
const void* PackedFilter = nullptr;
size_t PackedFilterGroupStride = 0;
bool FilterIsPacked = false;
/**
* HalfConv-specific: true means caller-provided input and output tensors
* are channels-last (NHWC); false means NCHW public tensors with any NHWC
* staging handled internally.
*/
bool InputOutputChannelsLast = false;
union {
struct {
CBLAS_TRANSPOSE TransB;
Expand Down Expand Up @@ -1935,11 +1945,26 @@ struct MLAS_HALF_GEMM_DATA_PARAMS {
const MLAS_HALF_GEMM_POSTPROCESSOR* OutputProcessor = nullptr;
bool AIsfp32 = false; /**< matrix A is fp32, needs to be casted into fp16*/
bool BIsfp32 = false; /**< matrix B is fp32, needs to be casted into fp16*/
bool BIsPacked = false; /**< matrix B is pre-packed by MlasHalfGemmPackB/MlasHalfGemmConvertPackB */
const MLAS_BACKEND_KERNEL_SELECTOR_CONFIG* BackendKernelSelectorConfig = nullptr;
/**
* Matrix B uses a backend-specific direct-consumption packed layout.
* When true, B must be produced by MlasHalfGemmNativePackB, ldb must be 0,
* Bias must be nullptr, and OutputProcessor must be nullptr.
*/
bool BIsBackendNativePacked = false;
};

/**
* @brief Half precision Batched GEMM: C = A * B + Bias
* Either A or B can be fp32 or fp16
* Either A or B can be fp32 or fp16.
* Backend-native packed B is a constrained direct-consumption layout
* and does not support runtime Bias or OutputProcessor.
*
* Uses MLAS_THROW_EX(std::runtime_error, ...) for contract violations that
* cannot be safely ignored: non-empty work with null DataParams, malformed
* backend-native packed-B parameters on the K == 0 path, or backend-native
* packed B reaching the generic MLAS kernels when no backend override consumes it.
*
* Note: We only support uniform batching, so shapes and types of the
* input must be same across all parameter blocks.
Expand Down Expand Up @@ -1985,6 +2010,9 @@ MlasHalfGemmPackBSize(
* @brief For half precision GEMM, pack the right hand
* side matrix B
*
* @pre For non-zero N and K, B and PackedB must be non-null and ldb must be at
* least N.
*
* @param[in] N Number of columns
* @param[in] K Number of rows
* @param[in] B Address of matrix B
Expand All @@ -2001,6 +2029,106 @@ MlasHalfGemmPackB(
void* PackedB
);

/**
* @brief For half precision GEMM, returns the size of a backend-native
* direct-consumption packing buffer for right hand side B.
*
* The returned layout is only valid when MlasHalfGemmBatch consumes
* MLAS_HALF_GEMM_DATA_PARAMS with BIsBackendNativePacked set to true, ldb set
* to 0, Bias set to nullptr, and OutputProcessor set to nullptr. Returns 0
* when no backend-native format is available for the given transpose/shape/config.
*/
size_t
MLASCALL
MlasHalfGemmNativePackBSize(
CBLAS_TRANSPOSE TransA,
CBLAS_TRANSPOSE TransB,
size_t N,
size_t K,
const MLAS_BACKEND_KERNEL_SELECTOR_CONFIG* BackendKernelSelectorConfig
);

/**
* @brief For half precision GEMM, pack right hand side B into the
* backend-native direct-consumption format.
*
* Returns false when the backend-native format is unavailable for the given
* transpose/shape/config. The resulting buffer must be passed to
* MlasHalfGemmBatch with ldb set to 0, BIsBackendNativePacked set to true,
* Bias set to nullptr, and OutputProcessor set to nullptr.
*/
bool
MLASCALL
MlasHalfGemmNativePackB(
CBLAS_TRANSPOSE TransA,
CBLAS_TRANSPOSE TransB,
size_t N,
size_t K,
const MLAS_FP16* B,
size_t ldb,
void* PackedB,
const MLAS_BACKEND_KERNEL_SELECTOR_CONFIG* BackendKernelSelectorConfig
);

bool
MLASCALL
MlasHalfConvPrepare(
MLAS_CONV_PARAMETERS* Parameters,
size_t Dimensions,
size_t BatchCount,
size_t GroupCount,
size_t InputChannels,
const int64_t* InputShape,
const int64_t* KernelShape,
const int64_t* DilationShape,
const int64_t* Padding,
const int64_t* StrideShape,
const int64_t* OutputShape,
size_t FilterCount,
const MLAS_ACTIVATION* Activation,
size_t* WorkingBufferSize,
float Beta,
bool InputOutputChannelsLast,
MLAS_THREADPOOL* ThreadPool,
const MLAS_BACKEND_KERNEL_SELECTOR_CONFIG* BackendKernelSelectorConfig);

bool
MLASCALL
MlasHalfConv(
const MLAS_CONV_PARAMETERS* Parameters,
const MLAS_FP16* Input,
const MLAS_FP16* Filter,
// When true, Filter must point to a packed weights+bias buffer produced by
// MlasHalfConvPackWeightsAndBias and Bias must be nullptr.
bool FilterAndBiasArePacked,
const MLAS_FP16* Bias,
MLAS_FP16* WorkingBuffer,
MLAS_FP16* Output,
MLAS_THREADPOOL* ThreadPool);

size_t
MLASCALL
MlasHalfConvPackWeightsAndBiasSize(
size_t FilterCount,
size_t InputChannels,
const int64_t* KernelShape,
const int64_t* DilationShape,
const MLAS_BACKEND_KERNEL_SELECTOR_CONFIG* BackendKernelSelectorConfig);

bool
MLASCALL
MlasHalfConvPackWeightsAndBias(
size_t FilterCount,
size_t InputChannels,
const int64_t* KernelShape,
const int64_t* DilationShape,
const MLAS_FP16* Filter,
// Optional bias to bake into the packed direct-consumption buffer.
const MLAS_FP16* Bias,
void* PackedWeightsAndBias,
MLAS_THREADPOOL* ThreadPool,
const MLAS_BACKEND_KERNEL_SELECTOR_CONFIG* BackendKernelSelectorConfig);

/**
* @brief For half precision GEMM, convert the float matrix B
* to half precision and pack it into a packing buffer
Expand Down
158 changes: 158 additions & 0 deletions onnxruntime/core/mlas/lib/halfconv.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
//
// SPDX-FileCopyrightText: Copyright 2026 Arm Limited and/or its affiliates <open-source-office@arm.com>
//
// SPDX-License-Identifier: MIT
//

/*++

Module Name:

halfconv.cpp

Abstract:

This module implements public dispatch wrappers for optional half precision
convolution backends.

--*/

#include "mlasi.h"

bool
MLASCALL
MlasHalfConvPrepare(
MLAS_CONV_PARAMETERS* Parameters,
size_t Dimensions,
size_t BatchCount,
size_t GroupCount,
size_t InputChannels,
const int64_t* InputShape,
const int64_t* KernelShape,
const int64_t* DilationShape,
const int64_t* Padding,
const int64_t* StrideShape,
const int64_t* OutputShape,
size_t FilterCount,
const MLAS_ACTIVATION* Activation,
size_t* WorkingBufferSize,
float Beta,
bool InputOutputChannelsLast,
MLAS_THREADPOOL* ThreadPool,
const MLAS_BACKEND_KERNEL_SELECTOR_CONFIG* BackendKernelSelectorConfig
)
{
if (GetMlasPlatform().MlasHalfConvPrepareOverride == nullptr) {
return false;
}

return GetMlasPlatform().MlasHalfConvPrepareOverride(
Parameters,
Dimensions,
BatchCount,
GroupCount,
InputChannels,
InputShape,
KernelShape,
DilationShape,
Padding,
StrideShape,
OutputShape,
FilterCount,
Activation,
WorkingBufferSize,
Beta,
InputOutputChannelsLast,
ThreadPool,
BackendKernelSelectorConfig);
}

bool
MLASCALL
MlasHalfConv(
const MLAS_CONV_PARAMETERS* Parameters,
const MLAS_FP16* Input,
const MLAS_FP16* Filter,
bool FilterAndBiasArePacked,
const MLAS_FP16* Bias,
MLAS_FP16* WorkingBuffer,
MLAS_FP16* Output,
MLAS_THREADPOOL* ThreadPool
)
{
if (GetMlasPlatform().MlasHalfConvOverride == nullptr) {
return false;
}

if (FilterAndBiasArePacked && Bias != nullptr) {
return false;
}

return GetMlasPlatform().MlasHalfConvOverride(
Parameters,
Input,
Filter,
FilterAndBiasArePacked,
Bias,
WorkingBuffer,
Output,
ThreadPool);
}

size_t
MLASCALL
MlasHalfConvPackWeightsAndBiasSize(
size_t FilterCount,
size_t InputChannels,
const int64_t* KernelShape,
const int64_t* DilationShape,
const MLAS_BACKEND_KERNEL_SELECTOR_CONFIG* BackendKernelSelectorConfig
)
{
if (BackendKernelSelectorConfig != nullptr && !BackendKernelSelectorConfig->use_kleidiai) {
return 0;
}

if (GetMlasPlatform().MlasHalfConvPackWeightsAndBiasSizeOverride == nullptr) {
return 0;
}

return GetMlasPlatform().MlasHalfConvPackWeightsAndBiasSizeOverride(
FilterCount,
InputChannels,
KernelShape,
DilationShape);
}

bool
MLASCALL
MlasHalfConvPackWeightsAndBias(
size_t FilterCount,
size_t InputChannels,
const int64_t* KernelShape,
const int64_t* DilationShape,
const MLAS_FP16* Filter,
const MLAS_FP16* Bias,
void* PackedWeightsAndBias,
MLAS_THREADPOOL* ThreadPool,
const MLAS_BACKEND_KERNEL_SELECTOR_CONFIG* BackendKernelSelectorConfig
)
{
if (BackendKernelSelectorConfig != nullptr && !BackendKernelSelectorConfig->use_kleidiai) {
return false;
}

if (GetMlasPlatform().MlasHalfConvPackWeightsAndBiasOverride == nullptr) {
return false;
}

return GetMlasPlatform().MlasHalfConvPackWeightsAndBiasOverride(
FilterCount,
InputChannels,
KernelShape,
DilationShape,
Filter,
Bias,
PackedWeightsAndBias,
ThreadPool);
}
Loading
Loading