File size: 3,916 Bytes
fb6457c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#include "blocking.h"
#include "../scalar/primitives.h"
#include <stdlib.h>
#include <string.h>

block_config_t* blocking_config_create(size_t mc, size_t nc, size_t kc) {
    block_config_t* cfg = (block_config_t*)malloc(sizeof(block_config_t));
    if (cfg) {
        cfg->mc = mc > 0 ? mc : MC;
        cfg->nc = nc > 0 ? nc : NC;
        cfg->kc = kc > 0 ? kc : KC;
    }
    return cfg;
}

void blocking_config_free(block_config_t* cfg) {
    if (cfg) free(cfg);
}

void pack_A_f32(
    float* packed,
    const matrix_t* A,
    size_t k_start, size_t k_end,
    size_t m_start, size_t m_end
) {
    if (!packed || !A) return;

    size_t kc = k_end - k_start;
    size_t mc = m_end - m_start;

    const float* a_ptr = matrix_ptr((matrix_t*)A);

    for (size_t i = 0; i < mc; ++i) {
        for (size_t k = 0; k < kc; ++k) {
            packed[i * kc + k] = a_ptr[(m_start + i) * A->stride + (k_start + k)];
        }
    }
}

void pack_B_f32(
    float* packed,
    const matrix_t* B,
    size_t k_start, size_t k_end,
    size_t n_start, size_t n_end
) {
    if (!packed || !B) return;

    size_t kc = k_end - k_start;
    size_t nc = n_end - n_start;

    const float* b_ptr = matrix_ptr((matrix_t*)B);

    for (size_t k = 0; k < kc; ++k) {
        for (size_t j = 0; j < nc; ++j) {
            packed[k * nc + j] = b_ptr[(k_start + k) * B->stride + (n_start + j)];
        }
    }
}

void microkernel_f32(
    float* C,
    const float* packed_A,
    const float* packed_B,
    size_t mc, size_t nc, size_t kc,
    size_t ldc
) {
    if (!C || !packed_A || !packed_B) return;

    for (size_t i = 0; i < mc; ++i) {
        for (size_t j = 0; j < nc; ++j) {
            float sum = 0.0f;
            for (size_t k = 0; k < kc; ++k) {
                sum = scalar_fma_f32(packed_A[i * kc + k], packed_B[k * nc + j], sum);
            }
            C[i * ldc + j] += sum;
        }
    }
}

void gemm_blocked_f32(
    const matrix_t* A,
    const matrix_t* B,
    matrix_t* C,
    float alpha,
    float beta,
    const block_config_t* cfg
) {
    if (!A || !B || !C || !cfg) return;
    if (A->cols != B->rows || A->rows != C->rows || B->cols != C->cols) return;

    size_t M = A->rows;
    size_t N = B->cols;
    size_t K = A->cols;

    size_t mc = cfg->mc;
    size_t nc = cfg->nc;
    size_t kc = cfg->kc;

    float* packed_A = (float*)malloc(mc * kc * sizeof(float));
    float* packed_B = (float*)malloc(kc * nc * sizeof(float));

    if (!packed_A || !packed_B) {
        free(packed_A);
        free(packed_B);
        return;
    }

    float* c_ptr = matrix_ptr(C);

    for (size_t i_block = 0; i_block < M; i_block += mc) {
        size_t i_end = (i_block + mc < M) ? i_block + mc : M;
        size_t i_size = i_end - i_block;

        for (size_t j_block = 0; j_block < N; j_block += nc) {
            size_t j_end = (j_block + nc < N) ? j_block + nc : N;
            size_t j_size = j_end - j_block;

            for (size_t k_block = 0; k_block < K; k_block += kc) {
                size_t k_end = (k_block + kc < K) ? k_block + kc : K;
                size_t k_size = k_end - k_block;

                pack_A_f32(packed_A, A, k_block, k_end, i_block, i_end);
                pack_B_f32(packed_B, B, k_block, k_end, j_block, j_end);

                microkernel_f32(
                    c_ptr + i_block * C->stride + j_block,
                    packed_A, packed_B,
                    i_size, j_size, k_size,
                    C->stride
                );
            }
        }
    }

    free(packed_A);
    free(packed_B);

    if (alpha != 1.0f || beta != 0.0f) {
        for (size_t i = 0; i < M; ++i) {
            for (size_t j = 0; j < N; ++j) {
                c_ptr[i * C->stride + j] = scalar_fma_f32(alpha, c_ptr[i * C->stride + j],
                                                          scalar_mul_f32(beta, c_ptr[i * C->stride + j]));
            }
        }
    }
}