/* SPDX-License-Identifier: AGPL-3.0-or-later */ /* Copyright (C) 2026 David (Corey) Herrera */ /** * @file test_bfp.c * @brief Off-device test: ft_bfp.c is bit-exact against the committed block-float * reference vectors, for BFP8 and BFP4, exp_a and exp_b, pack and unpack. * * NO DEVICE IS TOUCHED. The comparison is against * reference/ft_bfp_reference_vectors.h, written by * reference/generate_bfp_reference.c only after its independent * definition-level reference agreed with ft_bfp.c on every byte and word. * * --------------------------------------------------------------------------- * THE VECTORS ARE THE TEST, SO THE VECTORS ARE THEMSELVES CHECKED * --------------------------------------------------------------------------- * "Bit-exact on random floats" is a weak claim: random floats never land on a * round-to-nearest-even tie, never carry a denormal, and rarely span more than * a couple of binades inside one 16-element block. So this file first asserts * what the input vectors actually CONTAIN — ties of both parities, exact * zeros, signed zeros, denormals, infinities, NaN, mantissa saturation, and * exponent differences past the 31-bit shift boundary — and only then asserts * that the packed bytes match. A coverage check that fails means the vectors * stopped testing something, even if every byte still matches. * * @status Green on macOS/arm64 under * `cc -std=c99 -Wall -Wextra -Werror -pedantic -Wshadow -Wconversion`. * Mutation-proven: see docs/tt_bringup_log.md §12. * @issues None * @todo None */ #include #include #include #include #include "ft_bfp.h" #include "ft_tt_tilize.h" #include "ft_bfp_reference_vectors.h" /* ------------------------------------------------------------------------- */ /* Tiny harness */ /* ------------------------------------------------------------------------- */ static int checks_run; static int checks_failed; static void check(int condition, const char *what) { checks_run++; if (condition) { printf(" ok %s\n", what); } else { checks_failed++; printf(" FAIL %s\n", what); } } static void check_u64(uint64_t got, uint64_t want, const char *what) { checks_run++; if (got == want) { printf(" ok %s = %" PRIu64 "\n", what, got); } else { checks_failed++; printf(" FAIL %s = %" PRIu64 ", expected %" PRIu64 "\n", what, got, want); } } static void section(const char *name) { printf("\n== %s ==\n", name); } /* ------------------------------------------------------------------------- */ /* Vector coverage — what is actually in the inputs */ /* ------------------------------------------------------------------------- */ #define TOTAL_VALUES (FT_BFP_REF_TILE_COUNT * FT_BFP_REF_TILE_VALUES) typedef struct { uint32_t zeros; uint32_t negative_zeros; uint32_t denormals; uint32_t infinities; uint32_t nans; uint32_t max_mantissa; /**< fraction 0x7fffff — the saturation feeder */ uint32_t blocks; uint32_t blocks_shift_over_31; /**< blocks with an exponent spread > 31 */ uint32_t blocks_uniform_exp; } vector_coverage; static void survey_vectors(vector_coverage *cov) { memset(cov, 0, sizeof(*cov)); for (uint32_t i = 0; i < TOTAL_VALUES; i++) { uint32_t bits = ft_bfp_ref_input_bits[i]; uint32_t exp = (bits >> 23) & 0xffu; uint32_t frac = bits & 0x7fffffu; if (exp == 0 && frac == 0) { cov->zeros++; if (bits >> 31) cov->negative_zeros++; } else if (exp == 0) { cov->denormals++; } else if (exp == 0xffu && frac == 0) { cov->infinities++; } else if (exp == 0xffu) { cov->nans++; } if (frac == 0x7fffffu) cov->max_mantissa++; } /* A block is 16 contiguous values of a face row; in the row-major tile * that is a contiguous run of 16, so blocks tile the input linearly. */ for (uint32_t b = 0; b < TOTAL_VALUES / FT_BFP_BLOCK_VALUES; b++) { const uint32_t *block = &ft_bfp_ref_input_bits[b * FT_BFP_BLOCK_VALUES]; uint32_t min_exp = 0xffffffffu; uint32_t max_exp = 0; cov->blocks++; for (uint32_t j = 0; j < FT_BFP_BLOCK_VALUES; j++) { uint32_t exp = (block[j] >> 23) & 0xffu; if (exp == 0) continue; /* zero and denormal do not participate */ if (exp < min_exp) min_exp = exp; if (exp > max_exp) max_exp = exp; } if (min_exp == 0xffffffffu) continue; if (max_exp - min_exp > 31) cov->blocks_shift_over_31++; if (max_exp == min_exp) cov->blocks_uniform_exp++; } } static void test_vector_coverage(void) { vector_coverage cov; section("reference vectors cover the interesting paths"); survey_vectors(&cov); check(cov.zeros > 0, "vectors contain exact zeros"); check(cov.negative_zeros > 0, "vectors contain negative zeros"); check(cov.denormals > 0, "vectors contain denormals"); check(cov.infinities > 0, "vectors contain infinities"); check(cov.nans > 0, "vectors contain NaN"); check(cov.max_mantissa > 0, "vectors contain full mantissas (saturation feeder)"); check(cov.blocks_shift_over_31 > 0, "vectors contain blocks whose exponent spread exceeds 31"); check(cov.blocks_uniform_exp > 0, "vectors contain blocks with a single exponent"); printf(" zeros=%u (-0: %u) denormals=%u inf=%u nan=%u full-mantissa=%u\n", cov.zeros, cov.negative_zeros, cov.denormals, cov.infinities, cov.nans, cov.max_mantissa); printf(" blocks=%u spread>31=%u uniform-exp=%u\n", cov.blocks, cov.blocks_shift_over_31, cov.blocks_uniform_exp); } /* ------------------------------------------------------------------------- */ /* Ties — proven reached, not assumed */ /* ------------------------------------------------------------------------- */ static void test_tie_coverage(void) { static float values[TOTAL_VALUES]; static unsigned char packed[TOTAL_VALUES * 2]; uint64_t seen = 0, up = 0; section("round-to-nearest-even ties are actually exercised"); for (uint32_t i = 0; i < TOTAL_VALUES; i++) memcpy(&values[i], &ft_bfp_ref_input_bits[i], sizeof(float)); ft_bfp_tie_counters_reset(); check(ft_bfp_pack_tiles(FT_BFP_BFP8_B, values, FT_BFP_REF_TILE_COUNT, packed) == FT_BFP_OK, "BFP8 pack succeeded"); ft_bfp_tie_counters(&seen, &up); check(seen > 0, "BFP8 pack hit the tie path"); check(up > 0, "BFP8 ties rounded UP at least once (odd guard bit)"); check(seen > up, "BFP8 ties rounded DOWN at least once (even guard bit)"); printf(" BFP8 ties: %" PRIu64 " (%" PRIu64 " up, %" PRIu64 " down)\n", seen, up, seen - up); ft_bfp_tie_counters_reset(); check(ft_bfp_pack_tiles(FT_BFP_BFP4_B, values, FT_BFP_REF_TILE_COUNT, packed) == FT_BFP_OK, "BFP4 pack succeeded"); ft_bfp_tie_counters(&seen, &up); check(seen > 0, "BFP4 pack hit the tie path"); check(up > 0, "BFP4 ties rounded UP at least once"); check(seen > up, "BFP4 ties rounded DOWN at least once"); printf(" BFP4 ties: %" PRIu64 " (%" PRIu64 " up, %" PRIu64 " down)\n", seen, up, seen - up); ft_bfp_tie_counters_reset(); } /* ------------------------------------------------------------------------- */ /* Bit-exactness against the reference vectors */ /* ------------------------------------------------------------------------- */ static void compare_packed(ft_bfp_format format, const char *name, const uint32_t *expected, size_t expected_words) { static float values[TOTAL_VALUES]; static uint32_t packed[TOTAL_VALUES]; /* >= 272 words per tile, comfortably */ size_t words = ft_bfp_tile_bytes(format) / 4u * FT_BFP_REF_TILE_COUNT; size_t mismatches = 0; size_t first_mismatch = 0; for (uint32_t i = 0; i < TOTAL_VALUES; i++) memcpy(&values[i], &ft_bfp_ref_input_bits[i], sizeof(float)); memset(packed, 0xa5, sizeof(packed)); if (ft_bfp_pack_tiles(format, values, FT_BFP_REF_TILE_COUNT, packed) != FT_BFP_OK) { check(0, name); return; } if (words != expected_words) { checks_run++; checks_failed++; printf(" FAIL %s: produced %zu words, reference has %zu\n", name, words, expected_words); return; } for (size_t i = 0; i < words; i++) { if (packed[i] != expected[i]) { if (mismatches == 0) first_mismatch = i; mismatches++; } } checks_run++; if (mismatches == 0) { printf(" ok %s: %zu/%zu words identical to the reference\n", name, words, words); } else { checks_failed++; printf(" FAIL %s: %zu/%zu words differ; first at word %zu (got 0x%08x, reference 0x%08x)\n", name, mismatches, words, first_mismatch, packed[first_mismatch], expected[first_mismatch]); } } /** Pack the reference tiles one call per tile; 1 if the words match the reference. */ static int per_tile_packing_matches_reference(void) { static float values[TOTAL_VALUES]; static uint32_t packed[TOTAL_VALUES]; size_t tile_words = ft_bfp_tile_bytes(FT_BFP_BFP8_B) / 4u; for (uint32_t i = 0; i < TOTAL_VALUES; i++) memcpy(&values[i], &ft_bfp_ref_input_bits[i], sizeof(float)); for (uint32_t t = 0; t < FT_BFP_REF_TILE_COUNT; t++) if (ft_bfp_pack_tiles(FT_BFP_BFP8_B, values + t * FT_BFP_REF_TILE_VALUES, 1, packed + t * tile_words) != FT_BFP_OK) return 0; return memcmp(packed, ft_bfp_ref_bfp8b, sizeof(ft_bfp_ref_bfp8b)) == 0; } static void test_pack_bit_exact(void) { section("pack is bit-exact against the reference vectors"); check_u64(ft_bfp_tile_bytes(FT_BFP_BFP8_B), 1088, "BFP8 tile bytes"); check_u64(ft_bfp_tile_bytes(FT_BFP_BFP4_B), 576, "BFP4 tile bytes"); check_u64(ft_bfp_tile_bytes(FT_BFP_BFP8_A), 1088, "BFP8 exp_a tile bytes"); check_u64(ft_bfp_tile_bytes(FT_BFP_BFP4_A), 576, "BFP4 exp_a tile bytes"); compare_packed(FT_BFP_BFP8_B, "BFP8_b", ft_bfp_ref_bfp8b, sizeof(ft_bfp_ref_bfp8b) / sizeof(ft_bfp_ref_bfp8b[0])); compare_packed(FT_BFP_BFP4_B, "BFP4_b", ft_bfp_ref_bfp4b, sizeof(ft_bfp_ref_bfp4b) / sizeof(ft_bfp_ref_bfp4b[0])); compare_packed(FT_BFP_BFP8_A, "BFP8 exp_a", ft_bfp_ref_bfp8_expa, sizeof(ft_bfp_ref_bfp8_expa) / sizeof(ft_bfp_ref_bfp8_expa[0])); compare_packed(FT_BFP_BFP4_A, "BFP4 exp_a", ft_bfp_ref_bfp4_expa, sizeof(ft_bfp_ref_bfp4_expa) / sizeof(ft_bfp_ref_bfp4_expa[0])); /* compare_packed packs all four tiles in one call; pin that packing them one * call per tile gives the same words. */ check(per_tile_packing_matches_reference(), "per-tile and single-call packing agree (BFP8_b)"); } static void test_unpack_bit_exact(void) { size_t index = 0; size_t mismatches = 0; section("unpack is bit-exact against the reference vectors"); for (uint32_t e = 0; e < FT_BFP_REF_UNPACK_EXP_B_COUNT; e++) { uint32_t shared = ft_bfp_ref_unpack_shared_exp_b[e]; for (uint32_t d = 0; d < 256; d++) { if (ft_bfp_convert_datum(FT_BFP_BFP8_B, (uint8_t)d, shared) != ft_bfp_ref_unpack_bfp8b[index]) mismatches++; index++; } } check_u64(mismatches, 0, "BFP8_b unpack mismatches over 256 data x every shared exponent"); index = 0; mismatches = 0; for (uint32_t e = 0; e < FT_BFP_REF_UNPACK_EXP_B_COUNT; e++) { uint32_t shared = ft_bfp_ref_unpack_shared_exp_b[e]; for (uint32_t d = 0; d < 16; d++) { if (ft_bfp_convert_datum(FT_BFP_BFP4_B, (uint8_t)d, shared) != ft_bfp_ref_unpack_bfp4b[index]) mismatches++; index++; } } check_u64(mismatches, 0, "BFP4_b unpack mismatches"); index = 0; mismatches = 0; for (uint32_t e = 0; e < FT_BFP_REF_UNPACK_EXP_A_COUNT; e++) { uint32_t shared = ft_bfp_ref_unpack_shared_exp_a[e]; for (uint32_t d = 0; d < 256; d++) { if (ft_bfp_convert_datum(FT_BFP_BFP8_A, (uint8_t)d, shared) != ft_bfp_ref_unpack_bfp8_expa[index]) mismatches++; index++; } } check_u64(mismatches, 0, "BFP8 exp_a unpack mismatches"); index = 0; mismatches = 0; for (uint32_t e = 0; e < FT_BFP_REF_UNPACK_EXP_A_COUNT; e++) { uint32_t shared = ft_bfp_ref_unpack_shared_exp_a[e]; for (uint32_t d = 0; d < 16; d++) { if (ft_bfp_convert_datum(FT_BFP_BFP4_A, (uint8_t)d, shared) != ft_bfp_ref_unpack_bfp4_expa[index]) mismatches++; index++; } } check_u64(mismatches, 0, "BFP4 exp_a unpack mismatches"); } /* ------------------------------------------------------------------------- */ /* Behaviour the header promises */ /* ------------------------------------------------------------------------- */ static float float_from_bits(uint32_t bits) { float f; memcpy(&f, &bits, sizeof(f)); return f; } static uint32_t bits_from_float(float f) { uint32_t bits; memcpy(&bits, &f, sizeof(bits)); return bits; } static void test_documented_behaviour(void) { static float tile[FT_TT_TILE_VALUES]; static unsigned char packed[1088]; static float restored[FT_TT_TILE_VALUES]; section("documented edge behaviour"); check_u64(ft_bfp_convert_float_bits(FT_BFP_BFP8_B, 0x00000000u, 127), 0, "+0 packs to datum 0"); check_u64(ft_bfp_convert_float_bits(FT_BFP_BFP8_B, 0x80000000u, 127), 0, "-0 packs to datum 0 (sign dropped)"); check_u64(ft_bfp_convert_float_bits(FT_BFP_BFP8_B, 0x00000001u, 127), 0, "smallest denormal packs to datum 0"); check_u64(ft_bfp_convert_float_bits(FT_BFP_BFP8_B, 0x007fffffu, 127), 0, "largest denormal packs to datum 0"); /* 1.99999988 under its own exponent: mantissa 0xffffff >> 17 = 0x7f, and * the residue rounds up, which must saturate rather than carry. */ check_u64(ft_bfp_convert_float_bits(FT_BFP_BFP8_B, 0x3f7fffffu, 126), 0x7f, "rounding overflow saturates at 0x7f"); check_u64(ft_bfp_convert_float_bits(FT_BFP_BFP4_B, 0x3f7fffffu, 126), 0x7, "BFP4 rounding overflow saturates"); /* A value 2^40 below the block's shared exponent shifts away entirely. */ check_u64(ft_bfp_convert_float_bits(FT_BFP_BFP8_B, 0xbf800000u, 127 + 40), 0, "value far below the shared exponent packs to +0, not -0"); /* Exactly representable: 1.0 with shared exponent 127 is 0x40, and it must * come back as exactly 1.0. */ check_u64(ft_bfp_convert_float_bits(FT_BFP_BFP8_B, 0x3f800000u, 127), 0x40, "1.0 packs to 0x40"); check_u64(ft_bfp_convert_datum(FT_BFP_BFP8_B, 0x40, 127), 0x3f800000u, "0x40 unpacks to exactly 1.0"); /* Whole-tile round trip on values that BFP8 represents exactly: a power of * two per block plus multiples of 2^-7 of it. */ for (uint32_t row = 0; row < FT_TT_TILE_HEIGHT; row++) { for (uint32_t col = 0; col < FT_TT_TILE_WIDTH; col++) tile[row * FT_TT_TILE_WIDTH + col] = float_from_bits(0x3f800000u) * (float)(64 + (col % 64)) / 64.0f; } check(ft_bfp_pack_tiles(FT_BFP_BFP8_B, tile, 1, packed) == FT_BFP_OK, "pack of an exactly-representable tile"); check(ft_bfp_unpack_tiles(FT_BFP_BFP8_B, packed, 1, restored) == FT_BFP_OK, "unpack of that tile"); { size_t differing = 0; for (uint32_t i = 0; i < FT_TT_TILE_VALUES; i++) { if (bits_from_float(restored[i]) != bits_from_float(tile[i])) differing++; } check_u64(differing, 0, "exactly-representable tile survives pack+unpack unchanged"); } section("argument validation"); check(ft_bfp_pack_tiles((ft_bfp_format)99, tile, 1, packed) == FT_BFP_EINVAL, "unknown format is rejected"); check(ft_bfp_pack_tiles(FT_BFP_BFP8_B, NULL, 1, packed) == FT_BFP_EINVAL, "NULL input is rejected"); check(ft_bfp_pack_tiles(FT_BFP_BFP8_B, tile, 1, NULL) == FT_BFP_EINVAL, "NULL output is rejected"); check(ft_bfp_pack_tiles(FT_BFP_BFP8_B, NULL, 0, NULL) == FT_BFP_OK, "zero tiles is a no-op, not an error"); check_u64(ft_bfp_tile_bytes((ft_bfp_format)99), 0, "unknown format has no tile size"); } int main(void) { printf("test_bfp — ft_bfp.c against the block-float reference vectors\n"); test_vector_coverage(); test_tie_coverage(); test_pack_bit_exact(); test_unpack_bit_exact(); test_documented_behaviour(); printf("\n%d checks, %d failed\n", checks_run, checks_failed); return checks_failed == 0 ? 0 : 1; }