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

// Harness contract for the llama.cpp (ggml) moe baseline.
// Called by armbench_entry_moe (binding.cpp); implemented by kernel.cpp.
// SwiGLU MoE with softmax-then-top-k routing and normalized top-k weights:
//   probs = softmax(hidden @ router^T); top-k experts; w /= sum(w)
//   out   = sum_k w_k * down_e @ (silu(gate_e @ x) * (up_e @ x))
// hidden_states is row-major bf16 [T, n_embd]; router_weight bf16 [n_expert, n_embd];
// gate/up_proj bf16 [n_expert, n_ff, n_embd]; down_proj bf16 [n_expert, n_embd, n_ff];
// out fp32 [T, n_embd]. For q8_0, hidden_states and the three projections are
// ggml block_q8_0 rows over their last axis (34-byte {fp16 d; int8 qs[32]}
// blocks, repacked by the Python adapter); router_weight stays fp32 there.
int armbench_llamacpp_moe(const void* hidden_states, const void* router_weight,
                          const void* gate_proj, const void* up_proj,
                          const void* down_proj, float* out,
                          int64_t n_tokens, int64_t n_embd, int64_t n_ff,
                          int64_t n_expert, int64_t n_expert_used, bool is_q8);