File size: 4,956 Bytes
20b9ff3 | 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 | // noesa24_avx512.cpp — IKNN-Rl1-A1 — NoeSA-24 AVX-512 Kernel
// Version: v1.1 — Fixed __mmask16
// Created: 2026-09-03T17:10:00+07:00
// Last Updated: 2026-09-03T17:15:00+07:00
// Status: PUBLISHABLE — EN ONLY — M1 Kernel Validation
// Repo: IKNN-Rl1-A1 — Integrated Knowledge-phase Neural Network — Recursive Language Iteration 1 — Architecture 1
#include "noesa24_common.h"
#include <cstdint>
#include <immintrin.h>
namespace iknn {
namespace noesa24 {
namespace avx512 {
inline __m512i compute_noesa24_block_avx512(
__m512i activations,
const uint8_t states[16],
int32_t bias_0b = 1)
{
alignas(64) int32_t act_array[16];
_mm512_store_si512(reinterpret_cast<__m512i*>(act_array), activations);
alignas(64) int32_t result[16];
for (int i = 0; i < 16; ++i) {
result[i] = compute_noesa24_single(static_cast<int8_t>(act_array[i]), states[i], bias_0b);
}
return _mm512_load_si512(reinterpret_cast<const __m512i*>(result));
}
inline __m512i compute_noesa24_shift_add_avx512(
__m512i x,
__m512i scale,
__m512i sign,
__m512i zero_mask_0a,
__m512i bias_0b)
{
__m512i prod = _mm512_sllv_epi32(x, scale);
__mmask16 neg_mask = _mm512_cmpeq_epi32_mask(sign, _mm512_set1_epi32(-1));
__m512i neg_prod = _mm512_sub_epi32(_mm512_setzero_si512(), prod);
prod = _mm512_mask_blend_epi32(neg_mask, prod, neg_prod);
prod = _mm512_andnot_si512(zero_mask_0a, prod);
return prod;
}
inline void decode_60bit_avx512(uint64_t packed60, uint8_t out_digits[13]) {
static LUT576 lut[576];
static bool lut_built = false;
if (!lut_built) {
build_lut576(lut);
lut_built = true;
}
unpack_13x24_lut(packed60, out_digits, lut);
}
} // namespace avx512
} // namespace noesa24
} // namespace iknn
#ifdef NOESA24_AVX512_TEST
#include <random>
#include <iostream>
#include <chrono>
int main() {
using namespace iknn::noesa24;
using namespace iknn::noesa24::avx512;
std::cout << "[NoeSA-24 AVX-512 Test] " << __DATE__ << std::endl;
std::cout << "24-state 4.58-bit, 13-unit/60-bit packing 99.3%, shift-add" << std::endl;
std::mt19937 rng(42);
uint8_t digits[13];
for (int i = 0; i < 13; ++i) digits[i] = rng() % 24;
uint64_t packed = pack_13x24(digits);
uint8_t unpacked[13];
unpack_13x24(packed, unpacked);
bool pack_ok = true;
for (int i = 0; i < 13; ++i) if (digits[i] != unpacked[i]) pack_ok = false;
std::cout << "Pack 13x24: " << (pack_ok ? "[PASS]" : "[FAIL]") << " packed=0x" << std::hex << packed << std::dec << std::endl;
LUT576 lut[576];
build_lut576(lut);
uint8_t unpacked_lut[13];
unpack_13x24_lut(packed, unpacked_lut, lut);
bool lut_ok = true;
for (int i = 0; i < 13; ++i) if (digits[i] != unpacked_lut[i]) lut_ok = false;
std::cout << "LUT576 decode: " << (lut_ok ? "[PASS]" : "[FAIL]") << std::endl;
int8_t act = 10;
uint8_t state = encode_state(Operator::POS_A, Scale::S2);
int32_t res = compute_noesa24_single(act, state);
std::cout << "Compute single: act=10 state=+1a S2 (shift2) => " << res << " expected 40 " << (res==40 ? "[PASS]" : "[FAIL]") << std::endl;
state = encode_state(Operator::NEG_B, Scale::S3);
res = compute_noesa24_single(act, state);
std::cout << "Compute single: act=10 state=-1b S3 (shift4) => " << res << " expected -160 " << (res==-160 ? "[PASS]" : "[FAIL]") << std::endl;
state = encode_state(Operator::ZERO_A, Scale::S1);
res = compute_noesa24_single(act, state);
std::cout << "Compute single: act=10 state=0a => " << res << " expected 0 " << (res==0 ? "[PASS]" : "[FAIL]") << std::endl;
state = encode_state(Operator::ZERO_B, Scale::S1);
res = compute_noesa24_single(act, state, 1);
std::cout << "Compute single: act=10 state=0b bias1 => " << res << " expected 1 " << (res==1 ? "[PASS]" : "[FAIL]") << std::endl;
const int ITERS = 1000000;
auto start = std::chrono::high_resolution_clock::now();
uint64_t sum = 0;
for (int it = 0; it < ITERS; ++it) {
uint8_t out[13];
unpack_13x24(packed ^ it, out);
sum += out[0];
}
auto end = std::chrono::high_resolution_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count();
std::cout << "[BENCH] Unpack 13x24 scalar: " << ITERS << " iters " << ms << "ms sum " << sum << std::endl;
start = std::chrono::high_resolution_clock::now();
sum = 0;
for (int it = 0; it < ITERS; ++it) {
uint8_t out[13];
unpack_13x24_lut(packed ^ it, out, lut);
sum += out[0];
}
end = std::chrono::high_resolution_clock::now();
ms = std::chrono::duration_cast<std::chrono::milliseconds>(end-start).count();
std::cout << "[BENCH] Unpack 13x24 LUT576: " << ITERS << " iters " << ms << "ms sum " << sum << " (target ~12 cycles Ryzen5, ~4 cycles AVX-512 VBMI2)" << std::endl;
return 0;
}
#endif
|