// File: kernel.cpp
#include "gemm_contract.h"
#include "innerproduct_arm.h"
#include "mat.h"
#include "option.h"
#include <cstring>

namespace {
constexpr int N = 29;
constexpr int K = 800;
} // namespace

int ncnn::gemm_kernel(
    const Mat& bottom_blob, Mat& top_blob,
    const Mat& weight_data,
    const Option& opt)
{
    InnerProduct_arm ip;
    ip.num_output       = N;
    ip.bias_term        = 0;
    ip.weight_data_size = N * K;
    ip.int8_scale_term  = 0;
    ip.activation_type  = 0;
    ip.activation_params = Mat();
    // weight_data is flat (N*K), row-major with K contiguous — exactly the
    // layout InnerProduct_arm expects (reshape(K, N) done in create_pipeline).
    ip.weight_data      = const_cast<Mat&>(weight_data);

    if (ip.create_pipeline(opt) != 0) return -1;

    // bottom_blob is a genuine 2D Mat (w=K, h=M) — InnerProduct_arm handles the
    // full (M,K)->(M,N) gemm in one forward() call when dims==2.
    Mat local_top;
    if (ip.forward(bottom_blob, local_top, opt) != 0) return -1;

    const int M = top_blob.h;
    for (int m = 0; m < M; ++m)
        std::memcpy(top_blob.row(m), local_top.row(m), N * sizeof(float));
    return 0;
}