// File: kernel.cpp
// Reference-scalar conv2d.
// 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 float* input, float* output,
    const float* weight, const float* bias,
    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 float* 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 float* w_co  = weight + (long)co * C_in * Kh * Kw;
            for (int oh = 0; oh < H_out; ++oh) {
                for (int ow = 0; ow < W_out; ++ow) {
                    float sum = bias[co];
                    for (int ci = 0; ci < C_in; ++ci) {
                        const float* in_c = in_n + (long)ci * H * W;
                        const float* 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)
                                    sum += in_c[ih * W + iw] * w_c[kh * Kw + kw];
                            }
                        }
                    }
                    out_c[oh * W_out + ow] = sum;
                }
            }
        }
    }
}