// File: kernel.cpp
// Reference-scalar conv2d w8a8ch (int8 activations + weights, per-output-channel dequant).
// LLM target: replace this file with an optimised inner_conv2d.
// All per-definition constants live in conv2d_def:: (conv2d.h).
#include "conv2d.h"
using namespace conv2d_def;

extern "C" void inner_conv2d(
    const int8_t* input, float* output,
    const int8_t* weight, const float* bias, const float* weight_scales,
    int N, int C_in, int H, int W, int C_out, int H_out, int W_out)
{
    for (int n = 0; n < N; ++n) {
        const int8_t* in_n  = input  + (long)n * C_in  * H * W;
        float*        out_n = output + (long)n * C_out * H_out * W_out;
        for (int co = 0; co < C_out; ++co) {
            float*        out_c = out_n + (long)co * H_out * W_out;
            const int8_t* w_co  = weight + (long)co * C_in * Kh * Kw;
            const double  scale = (double)input_scale * (double)weight_scales[co];
            for (int oh = 0; oh < H_out; ++oh) {
                for (int ow = 0; ow < W_out; ++ow) {
                    int64_t acc = 0;
                    for (int ci = 0; ci < C_in; ++ci) {
                        const int8_t* in_c = in_n + (long)ci * H * W;
                        const int8_t* w_c  = w_co + (long)ci * Kh * Kw;
                        for (int kh = 0; kh < Kh; ++kh) {
                            for (int kw = 0; kw < Kw; ++kw) {
                                int ih = oh * Sh - pad_top  + kh * Dh;
                                int iw = ow * Sw - pad_left + kw * Dw;
                                if (ih >= 0 && ih < H && iw >= 0 && iw < W)
                                    acc += (int64_t)in_c[ih * W + iw] * (int64_t)w_c[kh * Kw + kw];
                            }
                        }
                    }
                    double val = (double)acc * scale + (double)bias[co];
                    out_c[oh * W_out + ow] = (float)val;
                }
            }
        }
    }
}