Foundry/cuda_kernels/tests/tensor_shim.c

58 lines
1.9 KiB
C

/* SPDX-License-Identifier: AGPL-3.0-or-later */
/* Copyright (C) 2026 David (Corey) Herrera */
/*
* tensor_shim.c — minimal tm_tensor allocator so the REAL foundry optim.c
* (optim/optim.c) can be linked standalone into the CUDA parity harness without
* pulling in the full tensor module (which drags in cblas / metal / cuda).
*
* optim.c's Adam/AdamW path touches only: tm_zeros, tm_data_f32, tm_release, and
* the struct fields data / grad / numel / shape / ndim / dtype. We implement
* exactly those against the REAL tensor.h so the struct layout is identical to
* what optim.c was compiled against. This is NOT a reimplementation of the
* optimizer — adam_step() itself runs from the unmodified optim.c.
*/
#include "tensor/tensor.h"
#include <stdlib.h>
#include <string.h>
static size_t shim_dtype_size(tm_dtype d) {
switch (d) {
case TM_F64:
case TM_I64: return 8;
case TM_F16:
case TM_BF16: return 2;
default: return 4; /* F32 / I32 */
}
}
tm_tensor *tm_zeros(int64_t *shape, int ndim, tm_dtype dtype) {
tm_tensor *t = (tm_tensor *)calloc(1, sizeof(tm_tensor));
if (!t) return NULL;
t->ndim = ndim;
int64_t n = 1;
for (int i = 0; i < ndim; i++) { t->shape[i] = shape[i]; n *= shape[i]; }
t->numel = n;
t->dtype = dtype;
t->requires_grad = false;
t->refcount = 1;
t->owns_data = true;
t->data = calloc((size_t)n, shim_dtype_size(dtype));
return t;
}
/* Harness convenience: a tensor wrapping caller data (copied in). */
tm_tensor *shim_tensor_f32(const float *src, int64_t n) {
int64_t shape[1] = { n };
tm_tensor *t = tm_zeros(shape, 1, TM_F32);
if (src) memcpy(t->data, src, (size_t)n * sizeof(float));
return t;
}
float *tm_data_f32(tm_tensor *t) { return t ? (float *)t->data : NULL; }
void tm_release(tm_tensor *t) {
if (!t) return;
if (t->owns_data && t->data) free(t->data);
free(t);
}