/* SPDX-License-Identifier: AGPL-3.0-or-later */ /* Copyright (C) 2026 David (Corey) Herrera */ /** * @file test_tilize.c * @brief Phase 3 off-device test: the 32x32 face-ordered tile layout, its * swizzled sibling, and the round trip through both on every shape the * target model uses. * * NO DEVICE IS TOUCHED. This is address arithmetic and memcpy. * * --------------------------------------------------------------------------- * WHY "ROUND-TRIP IS THE IDENTITY" IS NOT ENOUGH ON ITS OWN * --------------------------------------------------------------------------- * tilize -> untilize is the identity for ANY consistent permutation, including * a wrong one. A backend that stored tiles row-major and read them back * row-major would pass a round-trip test and then feed a Tensix garbage. So * this file pins the layout ITSELF first โ€” the four face base offsets, the * exact destination index of a handful of known (row, col) pairs, and the fact * that face order is NOT row-major over the whole tile โ€” and only then checks * the round trip over the model's shapes. * * @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 #include "ft_tt_tilize.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); } /* ------------------------------------------------------------------------- */ /* The layout itself */ /* ------------------------------------------------------------------------- */ static void test_face_index(void) { section("face ordering is what tt-metal's index expression says"); /* Face bases: face_y stride 512, face_x stride 256. */ check_u64(ft_tt_tile_face_index(0, 0), 0, "face (0,0) starts at 0"); check_u64(ft_tt_tile_face_index(0, 16), 256, "face (0,1) starts at 256"); check_u64(ft_tt_tile_face_index(16, 0), 512, "face (1,0) starts at 512"); check_u64(ft_tt_tile_face_index(16, 16), 768, "face (1,1) starts at 768"); check_u64(ft_tt_tile_face_index(31, 31), 1023, "last element is 1023"); /* Inside a face it is row-major with a stride of 16, NOT 32. */ check_u64(ft_tt_tile_face_index(0, 15), 15, "row 0 col 15"); check_u64(ft_tt_tile_face_index(1, 0), 16, "row 1 col 0 is 16, not 32"); check_u64(ft_tt_tile_face_index(15, 15), 255, "last element of face (0,0)"); check_u64(ft_tt_tile_face_index(1, 16), 272, "row 1 col 16 is in face (0,1)"); /* 512 (face (1,0)) + 1 row into the face * 16 + 3. */ check_u64(ft_tt_tile_face_index(17, 3), 531, "row 17 col 3 is in face (1,0)"); /* The whole point: this is NOT the row-major index. */ check(ft_tt_tile_face_index(0, 16) != 16, "face order differs from row-major at (0,16)"); check(ft_tt_tile_face_index(1, 0) != 32, "face order differs from row-major at (1,0)"); section("the index is a permutation of 0..1023"); { static unsigned char seen[FT_TT_TILE_VALUES]; size_t collisions = 0; memset(seen, 0, sizeof(seen)); for (uint32_t row = 0; row < FT_TT_TILE_HEIGHT; row++) { for (uint32_t col = 0; col < FT_TT_TILE_WIDTH; col++) { uint32_t index = ft_tt_tile_face_index(row, col); if (index >= FT_TT_TILE_VALUES || seen[index]) collisions++; else seen[index] = 1; } } check_u64(collisions, 0, "every (row,col) maps to a distinct index in range"); } } static void test_tile_counts(void) { section("tile counts round up"); check_u64(ft_tt_tile_count_for(0), 0, "0 columns needs 0 tiles"); check_u64(ft_tt_tile_count_for(1), 1, "1 column needs 1 tile"); check_u64(ft_tt_tile_count_for(32), 1, "32 columns needs 1 tile"); check_u64(ft_tt_tile_count_for(33), 2, "33 columns needs 2 tiles"); check_u64(ft_tt_tile_count_for(1536), 48, "1536 columns needs 48 tiles"); check_u64(ft_tt_tilize_bytes(4, 32, 32), 4096, "one fp32 tile is 4096 B"); check_u64(ft_tt_tilize_bytes(2, 32, 32), 2048, "one bf16 tile is 2048 B"); check_u64(ft_tt_tilize_bytes(4, 1, 1), 4096, "a 1x1 matrix still costs a whole tile"); check_u64(ft_tt_tilize_bytes(3, 32, 32), 0, "an unsupported element size sizes to 0"); } /* ------------------------------------------------------------------------- */ /* Round trip over the model's shapes */ /* ------------------------------------------------------------------------- */ /* * Every distinct (rows, cols) in MiniCPM5-1B-Q8_0.gguf, plus the awkward * shapes around the tile boundary. dims are (rows = GGUF dims[1], * cols = GGUF dims[0]). */ typedef struct { uint32_t rows; uint32_t cols; const char *what; } shape; static const shape SHAPES[] = { {130560, 1536, "token_embd / output (vocab x n_embd)"}, {2048, 1536, "attn_q (16 heads x 128)"}, {1536, 2048, "attn_output"}, {256, 1536, "attn_k, attn_v (GQA 2 kv heads x 128)"}, {4608, 1536, "ffn_gate, ffn_up"}, {1536, 4608, "ffn_down"}, {1, 1536, "norms as a 1-row matrix"}, {1, 1, "degenerate 1x1"}, {31, 31, "one short of a tile in both axes"}, {32, 32, "exactly one tile"}, {33, 33, "one past a tile in both axes"}, {32, 17, "partial face on the column edge"}, {17, 32, "partial rows"}, {64, 48, "two tile rows, one and a half tile columns"}, }; #define SHAPE_COUNT ((int)(sizeof(SHAPES) / sizeof(SHAPES[0]))) static uint32_t lcg_next(uint32_t *state) { *state = *state * 1664525u + 1013904223u; return *state; } /** * Fill with a value that depends on BOTH indices, so a layout bug that swaps * or duplicates a face cannot survive by luck. */ static void fill_pattern(uint32_t *matrix, uint32_t rows, uint32_t cols, uint32_t seed) { uint32_t state = seed; for (uint32_t row = 0; row < rows; row++) { for (uint32_t col = 0; col < cols; col++) matrix[(size_t)row * cols + col] = (row * 2654435761u) ^ (col * 40503u) ^ lcg_next(&state); } } static int round_trip_shape(const shape *s, size_t element_bytes, int swizzled) { size_t values = (size_t)s->rows * s->cols; size_t tile_bytes = ft_tt_tilize_bytes(element_bytes, s->rows, s->cols); unsigned char *source = malloc(values * element_bytes); unsigned char *tiles = malloc(tile_bytes); unsigned char *restored = malloc(values * element_bytes); uint32_t tile_rows = ft_tt_tile_count_for(s->rows); uint32_t tile_cols = ft_tt_tile_count_for(s->cols); size_t strip_bytes = (size_t)tile_cols * FT_TT_TILE_VALUES * element_bytes; int ok = 0; if (!source || !tiles || !restored) goto done; { uint32_t *pattern = malloc(values * sizeof(uint32_t)); if (!pattern) goto done; fill_pattern(pattern, s->rows, s->cols, (uint32_t)(s->rows * 31u + s->cols)); for (size_t i = 0; i < values; i++) memcpy(source + i * element_bytes, &pattern[i], element_bytes); free(pattern); } memset(restored, 0xa5, values * element_bytes); for (uint32_t strip = 0; strip < tile_rows; strip++) { uint32_t first = strip * FT_TT_TILE_HEIGHT; uint32_t valid = s->rows - first < FT_TT_TILE_HEIGHT ? s->rows - first : FT_TT_TILE_HEIGHT; const unsigned char *src = source + (size_t)first * s->cols * element_bytes; unsigned char *dst = restored + (size_t)first * s->cols * element_bytes; unsigned char *strip_tiles = tiles + (size_t)strip * strip_bytes; size_t stride = (size_t)s->cols * element_bytes; int rc; if (swizzled) { rc = ft_tt_tile_swizzle_strip(src, element_bytes, valid, s->cols, stride, strip_tiles); if (rc != FT_TT_TILIZE_OK) goto done; rc = ft_tt_tile_unswizzle_strip(strip_tiles, element_bytes, valid, s->cols, stride, dst); } else { rc = ft_tt_tilize_strip(src, element_bytes, valid, s->cols, stride, strip_tiles); if (rc != FT_TT_TILIZE_OK) goto done; rc = ft_tt_untilize_strip(strip_tiles, element_bytes, valid, s->cols, stride, dst); } if (rc != FT_TT_TILIZE_OK) goto done; } ok = memcmp(source, restored, values * element_bytes) == 0; done: free(source); free(tiles); free(restored); return ok; } static void test_round_trip(void) { section("tilize -> untilize is the identity on every shape we use"); for (int i = 0; i < SHAPE_COUNT; i++) { char label[160]; snprintf(label, sizeof(label), "fp32 %ux%u %s", SHAPES[i].rows, SHAPES[i].cols, SHAPES[i].what); check(round_trip_shape(&SHAPES[i], 4, 0), label); } section("the same, at 2 bytes per element (bf16)"); for (int i = 0; i < SHAPE_COUNT; i++) { char label[160]; snprintf(label, sizeof(label), "bf16 %ux%u", SHAPES[i].rows, SHAPES[i].cols); check(round_trip_shape(&SHAPES[i], 2, 0), label); } section("swizzled (no face reorder) round trip, the block-float input path"); for (int i = 0; i < SHAPE_COUNT; i++) { char label[160]; snprintf(label, sizeof(label), "swizzled fp32 %ux%u", SHAPES[i].rows, SHAPES[i].cols); check(round_trip_shape(&SHAPES[i], 4, 1), label); } } /* ------------------------------------------------------------------------- */ /* Padding and placement */ /* ------------------------------------------------------------------------- */ static void test_padding_is_zero(void) { static uint32_t source[17 * 17]; static uint32_t tiles[FT_TT_TILE_VALUES]; size_t nonzero_pad = 0; section("padding is zero, and the valid region lands where it should"); for (uint32_t i = 0; i < 17 * 17; i++) source[i] = 0xdeadbeefu; memset(tiles, 0x5a, sizeof(tiles)); check(ft_tt_tilize_strip(source, 4, 17, 17, 17 * 4, tiles) == FT_TT_TILIZE_OK, "17x17 tilizes"); for (uint32_t row = 0; row < FT_TT_TILE_HEIGHT; row++) { for (uint32_t col = 0; col < FT_TT_TILE_WIDTH; col++) { uint32_t value = tiles[ft_tt_tile_face_index(row, col)]; if (row < 17 && col < 17) { if (value != 0xdeadbeefu) nonzero_pad++; } else if (value != 0) { nonzero_pad++; } } } check_u64(nonzero_pad, 0, "misplaced or non-zero elements in the padded 17x17 tile"); section("swizzled and face-ordered agree once the faces are applied"); { static uint32_t swizzled[FT_TT_TILE_VALUES]; static uint32_t faced[FT_TT_TILE_VALUES]; static uint32_t dense[FT_TT_TILE_VALUES]; size_t differing = 0; fill_pattern(dense, FT_TT_TILE_HEIGHT, FT_TT_TILE_WIDTH, 7u); check(ft_tt_tile_swizzle_strip(dense, 4, 32, 32, 32 * 4, swizzled) == FT_TT_TILIZE_OK, "swizzle a full tile"); check(ft_tt_tilize_strip(dense, 4, 32, 32, 32 * 4, faced) == FT_TT_TILIZE_OK, "tilize the same tile"); for (uint32_t row = 0; row < FT_TT_TILE_HEIGHT; row++) { for (uint32_t col = 0; col < FT_TT_TILE_WIDTH; col++) { if (swizzled[row * FT_TT_TILE_WIDTH + col] != faced[ft_tt_tile_face_index(row, col)]) differing++; } } check_u64(differing, 0, "face order applied to the swizzled tile reproduces the tilized tile"); /* And they are genuinely different byte strings, so the check above is * not passing because both layouts happen to be the same thing. */ check(memcmp(swizzled, faced, sizeof(faced)) != 0, "the two layouts are not the same bytes"); } } static void test_argument_validation(void) { static uint32_t source[FT_TT_TILE_VALUES]; static uint32_t tiles[FT_TT_TILE_VALUES]; section("argument validation"); check(ft_tt_tilize_strip(NULL, 4, 32, 32, 128, tiles) == FT_TT_TILIZE_EINVAL, "NULL source rejected"); check(ft_tt_tilize_strip(source, 4, 32, 32, 128, NULL) == FT_TT_TILIZE_EINVAL, "NULL destination rejected"); check(ft_tt_tilize_strip(source, 3, 32, 32, 96, tiles) == FT_TT_TILIZE_EINVAL, "element size 3 rejected"); check(ft_tt_tilize_strip(source, 4, 0, 32, 128, tiles) == FT_TT_TILIZE_EINVAL, "zero rows rejected"); check(ft_tt_tilize_strip(source, 4, 33, 32, 128, tiles) == FT_TT_TILIZE_EINVAL, "more than 32 rows rejected"); check(ft_tt_tilize_strip(source, 4, 32, 0, 128, tiles) == FT_TT_TILIZE_EINVAL, "zero columns rejected"); check(ft_tt_tilize_strip(source, 4, 32, 32, 64, tiles) == FT_TT_TILIZE_EINVAL, "a stride shorter than a row rejected"); check(ft_tt_tile_swizzle_strip(source, 4, 32, 32, 64, tiles) == FT_TT_TILIZE_EINVAL, "swizzle validates too"); } int main(void) { printf("test_tilize โ€” Blackhole 32x32 face-ordered tile layout\n"); test_face_index(); test_tile_counts(); test_round_trip(); test_padding_is_zero(); test_argument_validation(); printf("\n%d checks, %d failed\n", checks_run, checks_failed); return checks_failed == 0 ? 0 : 1; }