File size: 1,658 Bytes
75e8855
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/* alp-carry — carry-chain proof kernel
 * Copyright (C) 2026 Ahmad Ali Parr
 * SPDX-License-Identifier: AGPL-3.0-only
 */

#include "tensor.h"
#include <stdlib.h>
#include <string.h>
#include <immintrin.h>

Tensor tensor_new(size_t r, size_t c) {
    size_t stride_bytes = (c * sizeof(float) + 63) & ~(size_t)63;
    size_t stride = stride_bytes / sizeof(float);
    float *d = NULL;
    if (posix_memalign((void **)&d, 64, stride_bytes * r)) abort();
    memset(d, 0, stride_bytes * r);
    return (Tensor){ d, r, c, stride };
}

void tensor_free(Tensor *t) { free(t->data); t->data = NULL; }

void tensor_randomize(Tensor *t, float lo, float hi) {
    for (size_t i = 0; i < t->rows; i++)
        for (size_t j = 0; j < t->cols; j++) {
            float u = (float)rand() / (float)RAND_MAX;
            t->data[i * t->stride + j] = lo + u * (hi - lo);
        }
}

void linear_avx2(const Tensor *x, const Tensor *w, const Tensor *b, Tensor *out) {
    for (size_t i = 0; i < x->rows; i++) {
        const float *xi = x->data + i * x->stride;
        float *oi = out->data + i * out->stride;
        memcpy(oi, b->data, b->cols * sizeof(float));
        for (size_t k = 0; k < x->cols; k++) {
            __m256 xv = _mm256_set1_ps(xi[k]);
            size_t j = 0;
            for (; j + 8 <= w->cols; j += 8) {
                __m256 wv = _mm256_loadu_ps(w->data + k * w->stride + j);
                __m256 ov = _mm256_loadu_ps(oi + j);
                _mm256_storeu_ps(oi + j, _mm256_add_ps(ov, _mm256_mul_ps(xv, wv)));
            }
            for (; j < w->cols; j++)
                oi[j] += xi[k] * w->data[k * w->stride + j];
        }
    }
}