// File: gemm.h
#pragma once
#include <cstdint>

// Per-definition constants for this gemm Q4_K (weight-only) specialisation.
// C[m, n] = sum_k A[m, k] * B[n, k]  (B is the [N, K] "weight" matrix, transposed)
// A is a raw bf16 bit pattern (uint16_t) -- activations stay at the bf16
// baseline tier (real GGML never stores activations statically in a
// k-quant format either -- see kernel.cpp for the dynamic quantization this
// implies). B is Q4_K-quantized, exposed as three flat (non-bit-packed-scale)
// tensors:
//   B_q4:     [N, K/2]  uint8  -- byte i holds element 2i (low nibble),
//                                  element 2i+1 (high nibble), plain
//                                  sequential order (not ggml's own block-
//                                  interleaved order -- this is a simplified
//                                  Definition-level ABI, not GGML's bit-exact
//                                  block_q4_K struct).
//   B_scales: [N, K/32] raw fp16 bit pattern (uint16_t) -- one value per
//                                  32-element sub-block, already combining
//                                  GGML's per-superblock `d` and per-sub-block
//                                  6-bit `sc` into one number.
//   B_mins:   [N, K/32] raw fp16 bit pattern (uint16_t) -- same, combining
//                                  `dmin*m`.
// Dequant is `w[l] = B_scales[sb]*nibble(l) - B_mins[sb]`.
// Output accumulates/returns in fp32.
namespace gemm_def {
constexpr int N = 2048;
constexpr int K = 2048;
constexpr int K_half = 1024;
constexpr int K_sub = 64;
} // namespace gemm_def

#ifdef __cplusplus
extern "C" {
#endif
// LLM target: implement this in kernel.cpp.
// M is the only var dim. A: (M, K) bf16; B_q4: (N, K/2) uint8;
// B_scales/B_mins: (N, K/32) raw fp16 bits; output: (M, N) float32.
void inner_gemm(const uint16_t* A, float* output, const uint8_t* B_q4,
                 const uint16_t* B_scales, const uint16_t* B_mins, int M);
#ifdef __cplusplus
}
#endif