Foundry/tt/tests/test_vector_ops.c

2970 lines
147 KiB
C

/* SPDX-License-Identifier: AGPL-3.0-or-later */
/* Copyright (C) 2026 David (Corey) Herrera */
/**
* @file test_vector_ops.c
* @brief OFF-HARDWARE gate for the vector op family — the elementwise binary and the
* REDUCE binary (softmax, RMS norm, layer norm, router normalise). Runs
* without a card, and is what has to be green before the hardware pass is worth a core.
*
* ---------------------------------------------------------------------------
* WHAT THIS CAN PROVE, AND WHAT IT CANNOT
* ---------------------------------------------------------------------------
* It CAN prove:
* - the host and the KERNEL agree on every wire constant, by parsing the device headers
* rather than by a comment claiming they match (dev notes §4: "the confident sentence
* in a doc is the one to check, because nobody re-derives it");
* - the parameter block puts every field in the word the kernel reads;
* - the circular buffers fit the arena, do not overlap, and the documented Wt ceiling is
* the real one rather than a rounded-down guess;
* - the ARRANGEMENT OF PASSES computes the op, and clears a PCC ≥ 0.99 gate with bf16 at
* every circular-buffer boundary — which is a prediction of the card's score;
* - the max-subtraction pass is load-bearing, by running a row whose range makes exp
* overflow without it.
*
* It CANNOT prove the kernel implements the model. Nothing off-hardware can. dev notes §3:
* "off-hardware suites cannot cover the copy path" — and here they cannot cover the SFPU,
* the packer, the face order or the CB credit protocol either. A green run here means the
* plan is sound, never that the op works.
*
* ---------------------------------------------------------------------------
* THE DATA
* ---------------------------------------------------------------------------
* Full-mantissa random, never small integers. A bf16-exact array is bit-identical to its
* own bf16 rendering, so it cannot tell two CB descriptor sets apart and made two
* deliberately-different builds byte-equal once (dev notes §3).
*
* Environment:
* FT_TT_KERNEL_DIR where the device headers live (default ../kernels)
*
* @status Green: 198 checks, 0 failures, on the Mac (clang). Seven mutations were run
* against the original 87 and six went red — 1, 6, 1, 1, 1 and 2 failures. The seventh
* (the row max reduced over ONE tile instead of Wt) came back GREEN and that is what
* added test_softmax_max_is_over_the_whole_row(); with it, the same mutation fails.
* The 2026-08-15 ragged-W stages carry five more red proofs, each on a `make red` clean
* rebuild: the pad value forced to 0 (4 failures), the scaler built at the PADDED width
* (2 — and PCC stayed 0.999995, so max-abs is what caught it), ONE pad lane out of 31
* written wrong (5), the layer-norm refusal removed (2), and the layer-norm stage's own
* subject removed by making W exact so there are no pad lanes at all (7).
* @issues None
* @todo None
*/
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../convert/ft_float_convert.h"
#include "../ft_tt_op_dispatch.h"
#include "../ft_tt_op_l1_layout.h"
#include "../ft_tt_op_matmul.h"
#include "../ft_tt_op_vector.h"
#include "../ft_tt_queue.h"
#include "../ft_tt_tilize.h"
#include "ft_tt_test_report.h"
#include "ft_tt_vector_reference.h"
#define PCC_ACCEPT 0.99
/** Where the device headers live, so the wire-constant pin reads the real file. */
#define KERNEL_DIRECTORY_ENVIRONMENT "FT_TT_KERNEL_DIR"
#define KERNEL_DIRECTORY_DEFAULT "../kernels"
/** Longest path this assembles. */
#define PATH_MAX_BYTES 512u
static unsigned char g_cb_buffer[FT_TT_NUM_CIRCULAR_BUFFERS * FT_TT_WORDS_PER_LOCAL_CB_CONFIG * 4];
/* ================================================================
* Reading a constant out of a device header
* ================================================================ */
/**
* The value of `enum { <name> = <value> };` in `path`.
*
* The device headers are C and C++ at once (plan Phase 6.6), so the wire constants are
* declared one per line as an anonymous `enum` rather than as `constexpr uint32_t` --
* a C translation unit cannot say `constexpr`. The FORM is what changed; the intent is
* unchanged and is the whole point of this function: the value is read out of the real
* device header rather than retyped here, because a duplicated contract with nothing
* enforcing agreement is a contract that will disagree. A missing constant is a FAILURE
* and never a default -- a default would make this check pass against a header that no
* longer declares the field.
*
* Parsed out of the real header rather than retyped here, which is the same discipline
* build_tensix_program.sh applies to the kernel-text relocation map: a duplicated contract
* with nothing enforcing agreement is a contract that will disagree. A missing constant is
* a FAILURE and never a default — a default would make this check pass against a header
* that no longer declares the field.
*
* @return 0 on success, -1 if the file or the constant is missing
*/
static int read_device_constant(const char *path, const char *name, uint32_t *out_value)
{
char line[512];
FILE *file = fopen(path, "r");
int found = -1;
if (!file)
return -1;
while (fgets(line, sizeof(line), file)) {
char parsed_name[128];
char parsed_value[64];
if (sscanf(line, " enum { %127[A-Za-z0-9_] = %63[^}] };", parsed_name,
parsed_value) != 2)
continue;
if (strcmp(parsed_name, name) != 0)
continue;
*out_value = (uint32_t)strtoul(parsed_value, NULL, 0);
found = 0;
break;
}
fclose(file);
return found;
}
/** `directory`/`file`, for the two device headers this pins against. */
static void device_header_path(char *out, size_t out_bytes, const char *file)
{
const char *directory = getenv(KERNEL_DIRECTORY_ENVIRONMENT);
if (!directory || directory[0] == '\0')
directory = KERNEL_DIRECTORY_DEFAULT;
snprintf(out, out_bytes, "%s/%s", directory, file);
}
/** One host constant against its device twin, by name. */
static void check_device_constant(const char *path, const char *name, uint32_t host_value)
{
uint32_t device_value = 0;
if (read_device_constant(path, name, &device_value) != 0) {
ft_tt_test_check_fmt(name, false, "not declared in %s", path);
return;
}
ft_tt_test_check_fmt(name, device_value == host_value, "host %u, kernel %u", host_value,
device_value);
}
/**
* Every word index, every function value and both opcodes, host against kernel.
*
* This is the check that would have caught a field moving under an op author, and it is
* cheap enough that there is no reason for any future op family not to have one.
*/
static void test_wire_constants_agree(void)
{
char vector_path[PATH_MAX_BYTES];
char queue_path[PATH_MAX_BYTES];
char reduce_path[PATH_MAX_BYTES];
ft_tt_test_step("wire constants: the host enum against the kernel's own header");
device_header_path(vector_path, sizeof(vector_path), "resident_vector_protocol.h");
device_header_path(queue_path, sizeof(queue_path), "resident_queue_protocol.h");
device_header_path(reduce_path, sizeof(reduce_path), "resident_reduce_protocol.h");
check_device_constant(vector_path, "kVecFunction", FT_TT_OP_VECTOR_FUNCTION);
check_device_constant(vector_path, "kVecTileCount", FT_TT_OP_VECTOR_TILE_COUNT);
check_device_constant(vector_path, "kVecTileCols", FT_TT_OP_VECTOR_TILE_COLS);
check_device_constant(vector_path, "kVecDepth", FT_TT_OP_VECTOR_DEPTH);
check_device_constant(vector_path, "kVecAX", FT_TT_OP_VECTOR_A_X);
check_device_constant(vector_path, "kVecAY", FT_TT_OP_VECTOR_A_Y);
check_device_constant(vector_path, "kVecABase", FT_TT_OP_VECTOR_A_BASE);
check_device_constant(vector_path, "kVecBX", FT_TT_OP_VECTOR_B_X);
check_device_constant(vector_path, "kVecBY", FT_TT_OP_VECTOR_B_Y);
check_device_constant(vector_path, "kVecBBase", FT_TT_OP_VECTOR_B_BASE);
check_device_constant(vector_path, "kVecCX", FT_TT_OP_VECTOR_C_X);
check_device_constant(vector_path, "kVecCY", FT_TT_OP_VECTOR_C_Y);
check_device_constant(vector_path, "kVecCBase", FT_TT_OP_VECTOR_C_BASE);
check_device_constant(vector_path, "kVecWords", FT_TT_OP_VECTOR_WORDS);
check_device_constant(vector_path, "kVecFnSilu", FT_TT_OP_VECTOR_FN_SILU);
check_device_constant(vector_path, "kVecFnSigmoid", FT_TT_OP_VECTOR_FN_SIGMOID);
check_device_constant(vector_path, "kVecFnAdd", FT_TT_OP_VECTOR_FN_ADD);
check_device_constant(vector_path, "kVecFnMul", FT_TT_OP_VECTOR_FN_MUL);
check_device_constant(vector_path, "kVecFnSub", FT_TT_OP_VECTOR_FN_SUB);
check_device_constant(vector_path, "kVecFnSiluMul", FT_TT_OP_VECTOR_FN_SILU_MUL);
check_device_constant(queue_path, "kOpEltwise", FT_TT_QUEUE_OP_ELTWISE);
check_device_constant(queue_path, "kOpSoftmax", FT_TT_QUEUE_OP_SOFTMAX);
check_device_constant(queue_path, "kOpReduce", FT_TT_QUEUE_OP_REDUCE);
check_device_constant(reduce_path, "kRedPass0", FT_TT_OP_REDUCE_PASS0);
check_device_constant(reduce_path, "kRedPass1", FT_TT_OP_REDUCE_PASS1);
check_device_constant(reduce_path, "kRedFinal", FT_TT_OP_REDUCE_FINAL);
check_device_constant(reduce_path, "kRedBytePool", FT_TT_OP_REDUCE_BYTE_POOL);
check_device_constant(reduce_path, "kRedByteMap", FT_TT_OP_REDUCE_BYTE_MAP);
check_device_constant(reduce_path, "kRedByteVerb", FT_TT_OP_REDUCE_BYTE_VERB);
check_device_constant(reduce_path, "kRedByteAddEps", FT_TT_OP_REDUCE_BYTE_ADD_EPS);
check_device_constant(reduce_path, "kRedBytePassCount", FT_TT_OP_REDUCE_BYTE_PASS_COUNT);
check_device_constant(reduce_path, "kRedByteSource", FT_TT_OP_REDUCE_BYTE_SOURCE);
check_device_constant(reduce_path, "kRedByteChain", FT_TT_OP_REDUCE_BYTE_CHAIN);
check_device_constant(reduce_path, "kRedPoolSum", FT_TT_OP_REDUCE_POOL_SUM);
check_device_constant(reduce_path, "kRedPoolMax", FT_TT_OP_REDUCE_POOL_MAX);
check_device_constant(reduce_path, "kRedMapNone", FT_TT_OP_REDUCE_MAP_NONE);
check_device_constant(reduce_path, "kRedMapSquareSelf", FT_TT_OP_REDUCE_MAP_SQUARE_SELF);
check_device_constant(reduce_path, "kRedMapSubExp", FT_TT_OP_REDUCE_MAP_SUB_EXP);
check_device_constant(reduce_path, "kRedMapSubSquare", FT_TT_OP_REDUCE_MAP_SUB_SQUARE);
check_device_constant(reduce_path, "kRedVerbNone", FT_TT_OP_REDUCE_VERB_NONE);
check_device_constant(reduce_path, "kRedVerbRecip", FT_TT_OP_REDUCE_VERB_RECIP);
check_device_constant(reduce_path, "kRedVerbRsqrt", FT_TT_OP_REDUCE_VERB_RSQRT);
check_device_constant(reduce_path, "kRedSourceIn", FT_TT_OP_REDUCE_SOURCE_IN);
check_device_constant(reduce_path, "kRedSourceMid", FT_TT_OP_REDUCE_SOURCE_MID);
check_device_constant(reduce_path, "kRedChainCenter", FT_TT_OP_REDUCE_CHAIN_CENTER);
check_device_constant(reduce_path, "kRedChainGamma", FT_TT_OP_REDUCE_CHAIN_GAMMA);
check_device_constant(reduce_path, "kRedChainScale", FT_TT_OP_REDUCE_CHAIN_SCALE);
check_device_constant(reduce_path, "kRedChainBeta", FT_TT_OP_REDUCE_CHAIN_BETA);
check_device_constant(reduce_path, "kRedConstScalerTile", FT_TT_OP_REDUCE_CONST_SCALER_TILE);
check_device_constant(reduce_path, "kRedConstEpsTile", FT_TT_OP_REDUCE_CONST_EPS_TILE);
check_device_constant(reduce_path, "kRedConstStreamTile", FT_TT_OP_REDUCE_CONST_STREAM_TILE);
/* The parameter block and the queue's slot machinery are the same sixteen words; if
* they ever diverge, a block written by the host is read past its end by the kernel. */
ft_tt_test_check_fmt("the vector block fits a queue parameter slot",
(uint32_t)FT_TT_OP_VECTOR_WORDS == FT_TT_QUEUE_PARAM_WORDS,
"vector %u, queue slot %u", (uint32_t)FT_TT_OP_VECTOR_WORDS,
FT_TT_QUEUE_PARAM_WORDS);
}
/* ================================================================
* Arity and block depth
* ================================================================ */
/**
* The KERNEL's block-depth rule, transliterated from ftv_block_depth() in
* resident_vector_protocol.h.
*
* The two rules are deliberately different: the host SHRINKS a request to the largest
* divisor, the kernel ACCEPTS a divisor or falls back to 1. That is not a disagreement, it
* is a host that computes and a kernel that refuses to guess — but it is only safe if the
* host's answer always survives the kernel's check, which is what the sweep below asserts.
*/
static uint32_t kernel_block_depth(uint32_t run, uint32_t requested)
{
return (requested > 0u && run > 0u && run % requested == 0u) ? requested : 1u;
}
static void test_block_depth(void)
{
static const uint32_t runs[] = { 1u, 2u, 3u, 8u, 12u, 48u, 96u, 144u, 1000u };
unsigned run_index;
unsigned mismatches = 0;
unsigned non_divisors = 0;
ft_tt_test_step("block depth: the host's answer must survive the kernel's check");
for (run_index = 0; run_index < sizeof(runs) / sizeof(runs[0]); run_index++) {
const uint32_t run = runs[run_index];
uint32_t requested;
for (requested = 0; requested <= run + 4u; requested++) {
const uint32_t host = ft_tt_op_block_depth(run, requested);
if (host == 0u || run % host != 0u)
non_divisors++;
if (kernel_block_depth(run, host) != host)
mismatches++;
}
}
ft_tt_test_check_fmt("every host depth divides its run", non_divisors == 0, "%u violations",
non_divisors);
ft_tt_test_check_fmt("the kernel accepts every host depth", mismatches == 0, "%u rejected",
mismatches);
ft_tt_test_check_fmt("depth 0 becomes 1", ft_tt_op_block_depth(48u, 0u) == 1u, "%u",
ft_tt_op_block_depth(48u, 0u));
ft_tt_test_check_fmt("depth past the run is clamped to the run",
ft_tt_op_block_depth(48u, 4096u) == 48u, "%u",
ft_tt_op_block_depth(48u, 4096u));
ft_tt_test_check_fmt("a non-divisor shrinks rather than clamps",
ft_tt_op_block_depth(48u, 32u) == 24u, "%u",
ft_tt_op_block_depth(48u, 32u));
ft_tt_test_check_fmt("a prime run collapses to 1", ft_tt_op_block_depth(97u, 48u) == 1u, "%u",
ft_tt_op_block_depth(97u, 48u));
/* The matmul's named entry point is now this function; keeping the two answers equal is
* what makes collapsing them a refactor rather than a behaviour change. */
ft_tt_test_check_fmt("ft_tt_op_matmul_prefetch_depth still agrees",
ft_tt_op_matmul_prefetch_depth(144u, 64u) ==
ft_tt_op_block_depth(144u, 64u),
"%u vs %u", ft_tt_op_matmul_prefetch_depth(144u, 64u),
ft_tt_op_block_depth(144u, 64u));
}
static void test_arity(void)
{
ft_tt_test_step("arity: derived from the function, sent nowhere");
ft_tt_test_check("SILU is unary",
!ft_tt_op_vector_function_is_binary(FT_TT_OP_VECTOR_FN_SILU), "");
ft_tt_test_check("SIGMOID is unary",
!ft_tt_op_vector_function_is_binary(FT_TT_OP_VECTOR_FN_SIGMOID), "");
ft_tt_test_check("ADD is binary",
ft_tt_op_vector_function_is_binary(FT_TT_OP_VECTOR_FN_ADD), "");
ft_tt_test_check("MUL is binary",
ft_tt_op_vector_function_is_binary(FT_TT_OP_VECTOR_FN_MUL), "");
ft_tt_test_check("SUB is binary",
ft_tt_op_vector_function_is_binary(FT_TT_OP_VECTOR_FN_SUB), "");
ft_tt_test_check("SILU_MUL is binary",
ft_tt_op_vector_function_is_binary(FT_TT_OP_VECTOR_FN_SILU_MUL), "");
}
/* ================================================================
* Parameter blocks
* ================================================================ */
static ft_tt_op_operand make_operand(uint16_t x, uint16_t y, uint32_t address)
{
ft_tt_op_operand operand;
operand.x = x;
operand.y = y;
operand.address = address;
operand.tile_bytes = FT_TT_OP_TILE_BYTES_BF16;
return operand;
}
static void test_eltwise_parameters(void)
{
ft_tt_op_eltwise_request request;
uint32_t words[FT_TT_OP_VECTOR_WORDS];
int rc;
ft_tt_test_step("elementwise parameter block");
memset(&request, 0, sizeof(request));
request.function = FT_TT_OP_VECTOR_FN_MUL;
request.tile_count = 48u;
request.prefetch_tiles = 32u; /* not a divisor of 48 — must shrink to 24, not clamp */
request.input_a = make_operand(3u, 4u, 0x100000u);
request.input_b = make_operand(5u, 6u, 0x200000u);
request.output = make_operand(7u, 8u, 0x300000u);
rc = ft_tt_op_eltwise_parameters(&request, words);
ft_tt_test_check_fmt("a well-formed request encodes", rc == FT_TT_OK, "rc %d", rc);
ft_tt_test_check_fmt("function lands in word 0",
words[FT_TT_OP_VECTOR_FUNCTION] == FT_TT_OP_VECTOR_FN_MUL, "%u",
words[FT_TT_OP_VECTOR_FUNCTION]);
ft_tt_test_check_fmt("tile count lands in word 1", words[FT_TT_OP_VECTOR_TILE_COUNT] == 48u,
"%u", words[FT_TT_OP_VECTOR_TILE_COUNT]);
ft_tt_test_check_fmt("tile_cols is 0 for elementwise", words[FT_TT_OP_VECTOR_TILE_COLS] == 0u,
"%u", words[FT_TT_OP_VECTOR_TILE_COLS]);
ft_tt_test_check_fmt("depth is shrunk to a divisor", words[FT_TT_OP_VECTOR_DEPTH] == 24u, "%u",
words[FT_TT_OP_VECTOR_DEPTH]);
request.row0 = 7u; /* any nonzero */
rc = ft_tt_op_eltwise_parameters(&request, words);
ft_tt_test_check_fmt("row0 sets exactly the word-2 row-0 flag",
rc == FT_TT_OK && words[FT_TT_OP_VECTOR_TILE_COLS] ==
FT_TT_OP_ELTWISE_FLAG_ROW0,
"rc %d word2 %u", rc, words[FT_TT_OP_VECTOR_TILE_COLS]);
request.row0 = 0u;
rc = ft_tt_op_eltwise_parameters(&request, words);
ft_tt_test_check_fmt("A operand round-trips",
words[FT_TT_OP_VECTOR_A_X] == 3u && words[FT_TT_OP_VECTOR_A_Y] == 4u &&
words[FT_TT_OP_VECTOR_A_BASE] == 0x100000u,
"%u,%u,0x%X", words[FT_TT_OP_VECTOR_A_X], words[FT_TT_OP_VECTOR_A_Y],
words[FT_TT_OP_VECTOR_A_BASE]);
ft_tt_test_check_fmt("B operand round-trips",
words[FT_TT_OP_VECTOR_B_X] == 5u && words[FT_TT_OP_VECTOR_B_Y] == 6u &&
words[FT_TT_OP_VECTOR_B_BASE] == 0x200000u,
"%u,%u,0x%X", words[FT_TT_OP_VECTOR_B_X], words[FT_TT_OP_VECTOR_B_Y],
words[FT_TT_OP_VECTOR_B_BASE]);
ft_tt_test_check_fmt("C operand round-trips",
words[FT_TT_OP_VECTOR_C_X] == 7u && words[FT_TT_OP_VECTOR_C_Y] == 8u &&
words[FT_TT_OP_VECTOR_C_BASE] == 0x300000u,
"%u,%u,0x%X", words[FT_TT_OP_VECTOR_C_X], words[FT_TT_OP_VECTOR_C_Y],
words[FT_TT_OP_VECTOR_C_BASE]);
ft_tt_test_check_fmt("the reserved tail is zeroed",
words[13] == 0u && words[14] == 0u && words[15] == 0u, "%u,%u,%u",
words[13], words[14], words[15]);
/* A unary request must encode without a B operand at all — that is the whole point of
* the kernel deriving arity. */
request.function = FT_TT_OP_VECTOR_FN_SILU;
memset(&request.input_b, 0, sizeof(request.input_b));
rc = ft_tt_op_eltwise_parameters(&request, words);
ft_tt_test_check_fmt("a unary request needs no B operand", rc == FT_TT_OK, "rc %d", rc);
/* …and a BINARY one must be refused without it, because the reader would otherwise
* fetch tiles from address 0 and produce a plausible wrong answer. */
request.function = FT_TT_OP_VECTOR_FN_ADD;
rc = ft_tt_op_eltwise_parameters(&request, words);
ft_tt_test_check_fmt("a binary request without B is refused", rc == FT_TT_EINVAL, "rc %d", rc);
request.function = (ft_tt_op_vector_function)99;
request.input_b = make_operand(5u, 6u, 0x200000u);
rc = ft_tt_op_eltwise_parameters(&request, words);
ft_tt_test_check_fmt("an unknown function is refused", rc == FT_TT_EINVAL, "rc %d", rc);
request.function = FT_TT_OP_VECTOR_FN_ADD;
request.tile_count = 0u;
rc = ft_tt_op_eltwise_parameters(&request, words);
ft_tt_test_check_fmt("a zero tile count is refused", rc == FT_TT_EINVAL, "rc %d", rc);
}
/**
* The four members' PROGRAM WORDS, pinned as LITERALS.
*
* Deliberately not derived. A pin computed from the same table the encoder reads re-derives
* any mistake in that table and passes — which is exactly how eleven self-consistent asserts
* on ft_tt_mailbox.h missed a 16-byte insertion (dev notes §3). These are the hex words that
* have driven silicon; changing one is a rebuild of the reduce kernel and a re-run of the
* on-card acceptance, not a header edit.
*
* Read a word as four bytes, low to high:
* a pass = pool, map, verb, add_eps
* final = pass count, chain source, chain flags, 0
*/
static void test_reduce_programs(void)
{
static const struct {
ft_tt_op_reduce_function function;
uint32_t pass0;
uint32_t pass1;
uint32_t final_word;
} expected[] = {
/* softmax: MAX/none/none/no then SUM/sub-exp/recip/no ; scale the MID stream */
{ FT_TT_OP_REDUCE_FN_SOFTMAX, 0x00000002u, 0x00010201u, 0x00040102u },
/* rms_norm: SUM/x*x/rsqrt/eps ; gamma then scale on IN */
{ FT_TT_OP_REDUCE_FN_RMS_NORM, 0x01020101u, 0x00000000u, 0x00060001u },
/* layer_norm: SUM/none/none/no then SUM/sub-square/rsqrt/eps ; centre+gamma+scale+beta */
{ FT_TT_OP_REDUCE_FN_LAYER_NORM, 0x00000001u, 0x01020301u, 0x000F0002u },
/* router: SUM/none/recip/no ; scale on IN */
{ FT_TT_OP_REDUCE_FN_ROUTER_NORMALISE, 0x00010001u, 0x00000000u, 0x00040001u },
/* l2_norm: SUM/x*x/rsqrt/eps ; scale on IN, no gamma.
* RMS norm's PASS word beside the router's FINAL word — which is the whole of the
* claim that a fifth member is a table row: not one new bit reaches the wire. */
{ FT_TT_OP_REDUCE_FN_L2_NORM, 0x01020101u, 0x00000000u, 0x00040001u }
};
unsigned index;
ft_tt_test_step("the reduce family's five programs, pinned as literals");
for (index = 0; index < sizeof(expected) / sizeof(expected[0]); index++) {
uint32_t pass0 = 0u;
uint32_t pass1 = 0u;
uint32_t final_word = 0u;
const int rc = ft_tt_op_reduce_program(expected[index].function, &pass0, &pass1,
&final_word);
char label[96];
snprintf(label, sizeof(label), "%s compiles to its pinned program",
ft_tt_op_reduce_function_name(expected[index].function));
ft_tt_test_check_fmt(label,
rc == FT_TT_OK && pass0 == expected[index].pass0 &&
pass1 == expected[index].pass1 &&
final_word == expected[index].final_word,
"rc %d, got 0x%08X 0x%08X 0x%08X, want 0x%08X 0x%08X 0x%08X", rc,
pass0, pass1, final_word, expected[index].pass0,
expected[index].pass1, expected[index].final_word);
}
{
uint32_t pass0 = 0u;
uint32_t pass1 = 0u;
uint32_t final_word = 0u;
const int rc = ft_tt_op_reduce_program((ft_tt_op_reduce_function)99, &pass0, &pass1,
&final_word);
ft_tt_test_check_fmt("an unknown member is refused rather than encoded",
rc == FT_TT_EINVAL, "rc %d", rc);
}
/* The derived facts, checked against the definitions rather than restated: gamma and
* beta are what the CHAIN says, eps is what a PASS says, and the pass count is what the
* final word's low byte says. Two spellings of one fact is the shape of bug this file
* exists to catch. */
ft_tt_test_check("only the two norms use gamma",
!ft_tt_op_reduce_uses_gamma(FT_TT_OP_REDUCE_FN_SOFTMAX) &&
ft_tt_op_reduce_uses_gamma(FT_TT_OP_REDUCE_FN_RMS_NORM) &&
ft_tt_op_reduce_uses_gamma(FT_TT_OP_REDUCE_FN_LAYER_NORM) &&
!ft_tt_op_reduce_uses_gamma(FT_TT_OP_REDUCE_FN_ROUTER_NORMALISE), "");
ft_tt_test_check("only layer norm uses beta",
ft_tt_op_reduce_uses_beta(FT_TT_OP_REDUCE_FN_LAYER_NORM) &&
!ft_tt_op_reduce_uses_beta(FT_TT_OP_REDUCE_FN_RMS_NORM), "");
ft_tt_test_check("only the two norms use eps",
ft_tt_op_reduce_uses_eps(FT_TT_OP_REDUCE_FN_RMS_NORM) &&
ft_tt_op_reduce_uses_eps(FT_TT_OP_REDUCE_FN_LAYER_NORM) &&
!ft_tt_op_reduce_uses_eps(FT_TT_OP_REDUCE_FN_SOFTMAX) &&
!ft_tt_op_reduce_uses_eps(FT_TT_OP_REDUCE_FN_ROUTER_NORMALISE), "");
/* The scaler is 1/W exactly when a pass wants a MEAN. Softmax's and the router's reduces
* are a max and a plain sum, so theirs is 1.0 — one tile, two meanings, one slot. */
ft_tt_test_check("only the two norms take a 1/W scaler",
ft_tt_op_reduce_scaler_is_mean(FT_TT_OP_REDUCE_FN_RMS_NORM) &&
ft_tt_op_reduce_scaler_is_mean(FT_TT_OP_REDUCE_FN_LAYER_NORM) &&
!ft_tt_op_reduce_scaler_is_mean(FT_TT_OP_REDUCE_FN_SOFTMAX) &&
!ft_tt_op_reduce_scaler_is_mean(FT_TT_OP_REDUCE_FN_ROUTER_NORMALISE),
"");
ft_tt_test_check("softmax and layer norm are two passes, the others one",
ft_tt_op_reduce_pass_count(FT_TT_OP_REDUCE_FN_SOFTMAX) == 2u &&
ft_tt_op_reduce_pass_count(FT_TT_OP_REDUCE_FN_LAYER_NORM) == 2u &&
ft_tt_op_reduce_pass_count(FT_TT_OP_REDUCE_FN_RMS_NORM) == 1u &&
ft_tt_op_reduce_pass_count(FT_TT_OP_REDUCE_FN_ROUTER_NORMALISE) == 1u,
"");
/* L2 norm, stated where its neighbours are, because the two cells it differs from RMS
* norm in are exactly the two a copy-paste of that row would keep. */
ft_tt_test_check("L2 norm takes no gamma, no beta, one pass, eps, and a 1.0 scaler",
!ft_tt_op_reduce_uses_gamma(FT_TT_OP_REDUCE_FN_L2_NORM) &&
!ft_tt_op_reduce_uses_beta(FT_TT_OP_REDUCE_FN_L2_NORM) &&
ft_tt_op_reduce_uses_eps(FT_TT_OP_REDUCE_FN_L2_NORM) &&
!ft_tt_op_reduce_scaler_is_mean(FT_TT_OP_REDUCE_FN_L2_NORM) &&
ft_tt_op_reduce_pass_count(FT_TT_OP_REDUCE_FN_L2_NORM) == 1u,
"");
}
/** `pn_qwen35moe_l2_norm()` in Pantheon, spelled here so the two cannot drift: a double
* sum of squares, and a CLAMP at eps rather than an epsilon under the root. */
static void oracle_l2_norm_rows(const float *x, float eps, float *out, uint32_t rows,
uint32_t cols)
{
uint32_t row;
for (row = 0; row < rows; row++) {
const float *xr = x + (size_t)row * cols;
float *outr = out + (size_t)row * cols;
double sumsq = 0.0;
float inv;
uint32_t col;
for (col = 0; col < cols; col++)
sumsq += (double)xr[col] * (double)xr[col];
inv = 1.0f / fmaxf((float)sqrt(sumsq), eps);
for (col = 0; col < cols; col++)
outr[col] = xr[col] * inv;
}
}
/** Max-norm relative error of one row, folded into a running worst. The score
* `PN_TT_GDN_NORMCHECK` prints on the card, spelled here so the two are comparable. */
static double row_max_norm_relative(const float *want, const float *got, uint32_t cols,
double worst)
{
double max_abs = 0.0;
double max_want = 0.0;
uint32_t col;
for (col = 0; col < cols; col++) {
const double diff = fabs((double)got[col] - (double)want[col]);
const double magnitude = fabs((double)want[col]);
if (diff > max_abs)
max_abs = diff;
if (magnitude > max_want)
max_want = magnitude;
}
if (max_want > 0.0 && max_abs / max_want > worst)
worst = max_abs / max_want;
return worst;
}
/**
* THE L2 MEMBER AGAINST THE ORACLE IT EXISTS TO REPRODUCE — and against the RMS norm it is
* one table row away from.
*
* The shape is the GDN's, not the model's: 16 rows of 128, which is `[k_heads, S]` at
* Ornith's shape and the ONE reduce descriptor the q/k head norm compiles to. The red arm
* runs the same data through RMS_NORM's program and requires the score to COLLAPSE: an L2
* norm and an RMS norm over the same row differ by exactly sqrt(W), so a test that cannot
* separate them is measuring nothing.
*/
static void test_l2_norm_against_the_oracle(void)
{
const uint32_t rows = 16u;
const uint32_t cols = 128u;
const size_t count = (size_t)rows * cols;
const float eps = 1e-6f;
float *x = malloc(count * sizeof(float));
float *want = malloc(count * sizeof(float));
float *got = malloc(count * sizeof(float));
uint32_t pass0 = 0u;
uint32_t pass1 = 0u;
uint32_t final_word = 0u;
size_t element;
ft_tt_test_step("the L2 member reproduces pn_qwen35moe_l2_norm at the GDN's head shape");
if (!x || !want || !got) {
ft_tt_test_check("allocation", false, "out of memory");
goto done;
}
ft_tt_vector_random_seed(0x1220E7ULL);
for (element = 0; element < count; element++)
x[element] = ft_float_from_bf16(ft_bf16_from_float(ft_tt_vector_random_value()));
oracle_l2_norm_rows(x, eps, want, rows, cols);
/* eps*eps, because the oracle clamps the MAGNITUDE at eps and this folds into the
* SQUARE. eps_tile is that divided by 32 — the value build_constants writes. */
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_L2_NORM, &pass0, &pass1, &final_word);
ft_tt_vector_model_reduce_program(pass0, pass1, final_word, x, NULL, NULL, 1.0f,
ft_float_from_bf16(ft_bf16_from_float(
eps * eps / (float)FT_TT_OP_TILE_DIM)),
got, rows, cols);
{
const double pcc = ft_tt_vector_pearson(want, got, count);
const double max_abs = ft_tt_vector_max_abs_difference(want, got, count);
ft_tt_test_check_fmt("PCC against the fp64 oracle is at least 0.9999",
pcc >= 0.9999, "PCC %.9f, max abs %.6g", pcc, max_abs);
/* bf16 through the circular buffers is ~2^-8 a value, and the modelled norm scales
* a whole row by one number, so the bar is the FORMAT and not the arithmetic. */
ft_tt_test_check_fmt("max abs is inside the bf16 budget", max_abs < 0.01,
"max abs %.6g", max_abs);
}
/* RED ARM: RMS norm's program on the same data. Same pass, same verb — only the scaler
* and the gamma step differ, and that is a factor of sqrt(128) = 11.3 on every element. */
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_RMS_NORM, &pass0, &pass1, &final_word);
{
float *gamma = malloc(cols * sizeof(float));
double max_abs;
uint32_t index;
if (!gamma) {
ft_tt_test_check("red-arm allocation", false, "out of memory");
goto done;
}
for (index = 0; index < cols; index++)
gamma[index] = 1.0f;
ft_tt_vector_model_reduce_program(pass0, pass1, final_word, x, gamma, NULL,
1.0f / (float)cols,
ft_float_from_bf16(ft_bf16_from_float(
eps * (float)cols / (float)FT_TT_OP_TILE_DIM)),
got, rows, cols);
max_abs = ft_tt_vector_max_abs_difference(want, got, count);
ft_tt_test_check_fmt("RED: the RMS member fails the same bar by sqrt(W)",
max_abs > 0.1, "max abs %.6g (want > 0.1)", max_abs);
free(gamma);
}
/* THE OPERAND'S FORMAT, PRICED SEPARATELY FROM THE REDUCE'S — because on silicon the two
* are quoted as one number and the lever is not the same.
*
* Everything above is bf16-EXACT input: `x` was rounded before the oracle saw it, so the
* only error measured is the reduce's own. A real operand is not bf16-exact — the GDN's
* `conv_out` and `y` are fp32 — and a bf16 activation strip rounds it on the way in. This
* arm gives the ORACLE the fp32 values and the CARD MODEL the bf16 rendering of them,
* which is exactly the comparison `PN_TT_GDN_NORMCHECK` makes on the card. Scored the
* same way the probe scores: max-norm relative, PER ROW. */
{
float *fp32 = malloc(count * sizeof(float));
double worst_reduce = 0.0;
double worst_storage = 0.0;
uint32_t row;
if (!fp32) {
ft_tt_test_check("format-floor allocation", false, "out of memory");
goto done;
}
ft_tt_vector_random_seed(0x1220E8ULL);
for (element = 0; element < count; element++)
fp32[element] = ft_tt_vector_random_value();
oracle_l2_norm_rows(fp32, eps, want, rows, cols);
for (element = 0; element < count; element++)
x[element] = ft_float_from_bf16(ft_bf16_from_float(fp32[element]));
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_L2_NORM, &pass0, &pass1, &final_word);
ft_tt_vector_model_reduce_program(pass0, pass1, final_word, x, NULL, NULL, 1.0f,
ft_float_from_bf16(ft_bf16_from_float(
eps * eps / (float)FT_TT_OP_TILE_DIM)),
got, rows, cols);
for (row = 0; row < rows; row++)
worst_storage = row_max_norm_relative(want + (size_t)row * cols,
got + (size_t)row * cols, cols,
worst_storage);
/* And the same reduce over the bf16-exact operand, which is the control: whatever is
* left there is the reduce, and the difference between the two is the FORMAT. */
oracle_l2_norm_rows(x, eps, want, rows, cols);
for (row = 0; row < rows; row++)
worst_reduce = row_max_norm_relative(want + (size_t)row * cols,
got + (size_t)row * cols, cols, worst_reduce);
/* AND THE SPLIT IS NOT WHERE IT LOOKED. The operand's own bf16 rendering is the
* SMALLER term: the REDUCE's format is what puts a narrow norm past the gate, so an
* fp32 activation strip in front of a bf16 reduce would buy almost nothing.
* Measured on silicon 2026-08-19 by PN_TT_GDN_NORMCHECK on Ornith's real conv_out:
* q/k L2 worst 8.599e-03, gated worst 1.283e-02 — this model lands within 20% of
* the first, which is what licenses using it to price the alternative. */
ft_tt_test_check_fmt("the bf16 REDUCE alone is past the 1e-3 gate", worst_reduce > 1e-3,
"%.3e per-row max-norm relative", worst_reduce);
ft_tt_test_check_fmt("and the operand's own bf16 storage adds LESS than the reduce",
worst_storage - worst_reduce < worst_reduce,
"storage %.3e, reduce %.3e — the CB's format is the lever, not "
"the strip's", worst_storage, worst_reduce);
free(fp32);
}
done:
free(x);
free(want);
free(got);
}
/**
* THE Float32 `reduce` PROGRAM AGAINST THE bf16 ONE, ON THE GDN HEAD SHAPE, OFF-HARDWARE.
*
* The question this answers before any card time: a Float32 CB table costs a doubled page
* and a second program in the blob, so what does it BUY, and is what it buys enough?
*
* Both models run the SAME program words over the SAME data against the SAME fp64 oracle.
* The only difference is the CB table, which is two roundings (ft_tt_vector_reference.c):
* bf16 rounds on the way into L1 and is exact on the way out; Float32 is exact on the way
* in and TRUNCATES TO Tf32 — 11 mantissa bits, toward zero — on the way out. That second
* one is a floor no table can move, so the honest question is not "does Float32 help" but
* "does Tf32 clear 1e-3 at this shape".
*
* Scored per row, max-norm relative, which is exactly what `PN_TT_GDN_NORMCHECK` prints per
* head on the card. 16 rows of 128 is `[k_heads, S]` at Ornith's shape.
*/
static void test_float32_reduce_at_the_head_shape(void)
{
const uint32_t rows = 16u;
const uint32_t cols = 128u;
const size_t count = (size_t)rows * cols;
const float eps = 1e-6f;
float *fp32 = malloc(count * sizeof(float));
float *stored_bf16 = malloc(count * sizeof(float));
float *gamma = malloc(cols * sizeof(float));
float *want = malloc(count * sizeof(float));
float *got = malloc(count * sizeof(float));
double l2_bf16 = 0.0;
double l2_float32 = 0.0;
double rms_bf16 = 0.0;
double rms_float32 = 0.0;
uint32_t pass0 = 0u;
uint32_t pass1 = 0u;
uint32_t final_word = 0u;
uint32_t row;
size_t element;
ft_tt_test_step("the Float32 reduce program against the bf16 one, at the GDN head shape");
if (!fp32 || !stored_bf16 || !gamma || !want || !got) {
ft_tt_test_check("allocation", false, "out of memory");
goto done;
}
ft_tt_vector_random_seed(0x1220E8ULL);
for (element = 0; element < count; element++) {
fp32[element] = ft_tt_vector_random_value();
stored_bf16[element] = ft_float_from_bf16(ft_bf16_from_float(fp32[element]));
}
for (element = 0; element < cols; element++)
gamma[element] = 0.5f + ft_tt_vector_random_value() * 0.25f;
/* ---- the q/k arm: L2 norm, no gamma, scaler 1.0, eps as eps*eps/32 ---- */
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_L2_NORM, &pass0, &pass1, &final_word);
oracle_l2_norm_rows(fp32, eps, want, rows, cols);
ft_tt_vector_model_reduce_program(pass0, pass1, final_word, stored_bf16, NULL, NULL, 1.0f,
ft_float_from_bf16(ft_bf16_from_float(
eps * eps / (float)FT_TT_OP_TILE_DIM)),
got, rows, cols);
for (row = 0; row < rows; row++)
l2_bf16 = row_max_norm_relative(want + (size_t)row * cols, got + (size_t)row * cols,
cols, l2_bf16);
/* The Float32 strip stores the fp32 values as given — that is the whole point of it — so
* the operand this model reduces is `fp32` and not the bf16 rendering of it. */
ft_tt_vector_model_reduce_program_float32(pass0, pass1, final_word, fp32, NULL, NULL, 1.0f,
eps * eps / (float)FT_TT_OP_TILE_DIM, got, rows,
cols);
for (row = 0; row < rows; row++)
l2_float32 = row_max_norm_relative(want + (size_t)row * cols, got + (size_t)row * cols,
cols, l2_float32);
/* ---- the gated arm's reduce half: RMS norm with a real gamma, scaler 1/W ---- */
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_RMS_NORM, &pass0, &pass1, &final_word);
ft_tt_vector_reference_rms_norm(fp32, gamma, eps, want, rows, cols);
ft_tt_vector_model_reduce_program(pass0, pass1, final_word, stored_bf16, gamma, NULL,
1.0f / (float)cols,
ft_float_from_bf16(ft_bf16_from_float(
eps * (float)cols / (float)FT_TT_OP_TILE_DIM)),
got, rows, cols);
for (row = 0; row < rows; row++)
rms_bf16 = row_max_norm_relative(want + (size_t)row * cols, got + (size_t)row * cols,
cols, rms_bf16);
ft_tt_vector_model_reduce_program_float32(pass0, pass1, final_word, fp32, gamma, NULL,
1.0f / (float)cols,
eps * (float)cols / (float)FT_TT_OP_TILE_DIM,
got, rows, cols);
for (row = 0; row < rows; row++)
rms_float32 = row_max_norm_relative(want + (size_t)row * cols, got + (size_t)row * cols,
cols, rms_float32);
ft_tt_test_check_fmt("the bf16 program misses the 1e-3 gate on BOTH members",
l2_bf16 > 1e-3 && rms_bf16 > 1e-3,
"L2 %.3e, RMS %.3e per-row max-norm relative", l2_bf16, rms_bf16);
ft_tt_test_check_fmt("the Float32 program is at least 4x better on both",
l2_float32 * 4.0 < l2_bf16 && rms_float32 * 4.0 < rms_bf16,
"L2 %.3e -> %.3e (%.1fx), RMS %.3e -> %.3e (%.1fx)", l2_bf16,
l2_float32, l2_bf16 / l2_float32, rms_bf16, rms_float32,
rms_bf16 / rms_float32);
/* AND THE TWO MEMBERS LAND ON OPPOSITE SIDES OF THE GATE, which is the result. The L2
* member's chain is ONE step; the RMS member's is TWO (gamma, then scale) and every step
* is a CB round trip, so it pays two more Tf32 unpacks on the value path. */
ft_tt_test_check_fmt("the L2 member CLEARS 1e-3 at Float32", l2_float32 < 1e-3,
"%.3e against 1e-3", l2_float32);
ft_tt_test_check_fmt("the RMS member does NOT, and it is inside the Tf32 budget of 2e-3",
rms_float32 > 1e-3 && rms_float32 < 2e-3,
"%.3e — over the gate and under twice it", rms_float32);
/* THE ATTRIBUTION, and it is the whole finding: run the SAME program with an fp32 unpack
* the hardware does not have. If the residue collapses, every bit of what is left at
* Float32 is Tf32 TRUNCATION and no CB table can touch it — the next lever is the chain's
* step count, i.e. kernel source, which this round does not open. */
{
double l2_exact = 0.0;
double rms_exact = 0.0;
ft_tt_vector_model_reduce_program_exact(pass0, pass1, final_word, fp32, gamma, NULL,
1.0f / (float)cols,
eps * (float)cols / (float)FT_TT_OP_TILE_DIM,
got, rows, cols);
for (row = 0; row < rows; row++)
rms_exact = row_max_norm_relative(want + (size_t)row * cols,
got + (size_t)row * cols, cols, rms_exact);
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_L2_NORM, &pass0, &pass1, &final_word);
oracle_l2_norm_rows(fp32, eps, want, rows, cols);
ft_tt_vector_model_reduce_program_exact(pass0, pass1, final_word, fp32, NULL, NULL, 1.0f,
eps * eps / (float)FT_TT_OP_TILE_DIM, got, rows,
cols);
for (row = 0; row < rows; row++)
l2_exact = row_max_norm_relative(want + (size_t)row * cols,
got + (size_t)row * cols, cols, l2_exact);
ft_tt_test_check_fmt("an fp32 unpack would clear the gate by 100x on BOTH — so the "
"whole Float32 residue is Tf32 TRUNCATION, not the pass structure",
l2_exact * 100.0 < l2_float32 && rms_exact * 100.0 < rms_float32,
"counterfactual L2 %.3e RMS %.3e against Tf32's %.3e and %.3e",
l2_exact, rms_exact, l2_float32, rms_float32);
}
done:
free(fp32);
free(stored_bf16);
free(gamma);
free(want);
free(got);
}
/* ---------------------------------------------------------------------------
* THE THREE WALLS UNDER THE Float32 HEAD NORMS, PRICED APART
*
* On silicon the two GDN members score 1.737e-03 (L2) and 3.165e-03 (RMS) against a 1e-3
* gate, and the model above says 8.406e-04 and 1.566e-03 — the card is 2.07x and 2.02x
* ABOVE it, the SAME factor on both members. Three things were named for that gap and none
* had been measured apart:
*
* 1. the SFPU's rsqrt polynomial, which the model does not have (it uses libm);
* 2. the RMS member's chain STEP COUNT, two steps against the L2 member's one;
* 3. the sample size — the card takes the worst of 48 layers x 32 heads, the model of 16
* rows in one draw.
*
* Each is an arm here. The rsqrt one is the important one to run FIRST, because if it is
* real then the chain-step work cannot reach the gate on its own and is not worth grinding.
* --------------------------------------------------------------------------- */
static void test_the_three_walls_priced_apart(void)
{
const uint32_t rows = 1536u; /* 48 SSM layers x 32 heads — what the card's worst is over */
const uint32_t cols = 128u;
const size_t count = (size_t)rows * cols;
const float eps = 1e-6f;
float *x = malloc(count * sizeof(float));
float *gamma = malloc(cols * sizeof(float));
/* The "gamma folded into a downstream weight" arm's oracle is the same RMS norm with
* gamma = 1, which is a gamma vector rather than a second reference function. */
float *unit_gamma = malloc(cols * sizeof(float));
float *want = malloc(cols * sizeof(float));
float *got = malloc(cols * sizeof(float));
float *control = malloc((size_t)16u * cols * sizeof(float));
uint32_t l2_pass0 = 0u;
uint32_t l2_pass1 = 0u;
uint32_t l2_final = 0u;
uint32_t rms_pass0 = 0u;
uint32_t rms_pass1 = 0u;
uint32_t rms_final = 0u;
size_t element;
/* Every arm is scored the same way: worst per-row max-norm relative over `rows`, which is
* exactly `normcheck_score()` per head on the card. */
struct arm_result {
double l2;
double rms;
double rms_no_gamma;
};
ft_tt_test_step("the three walls under the Float32 head norms, priced apart");
if (!x || !gamma || !unit_gamma || !want || !got || !control) {
ft_tt_test_check("allocation", false, "out of memory");
goto done;
}
ft_tt_vector_random_seed(0x1220E8ULL);
for (element = 0; element < count; element++)
x[element] = ft_tt_vector_random_value();
for (element = 0; element < cols; element++) {
gamma[element] = 0.5f + ft_tt_vector_random_value() * 0.25f;
unit_gamma[element] = 1.0f;
}
/* THE STREAM, PINNED AS LITERALS. The card-side probe that settles the model-vs-silicon
* gap (`PN_TT_RED=head_norm_synthetic`, Pantheon `qwen35moe_gdn_normcheck_tt.c`) cannot
* link this file, so it spells the same xorshift64* itself and checks it against exactly
* these eight words. Two spellings of one stream is a thing that must agree; this is what
* makes a disagreement a refusal instead of an incomparable number. */
{
static const uint32_t pinned[8] = { 0xBF508D2Au, 0x3EF4CC04u, 0x3EE46400u, 0xBDF7F450u,
0xBE494EE8u, 0xBF4FF826u, 0x3E88AB9Cu,
0xBF4CD48Cu };
bool matches = true;
size_t index;
for (index = 0; index < 8u; index++) {
uint32_t bits;
memcpy(&bits, &x[index], sizeof(bits));
if (bits != pinned[index])
matches = false;
}
ft_tt_test_check("the synthetic stream at seed 0x1220E8 is pinned as literals", matches,
"the card-side probe checks the same eight words");
}
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_L2_NORM, &l2_pass0, &l2_pass1, &l2_final);
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_RMS_NORM, &rms_pass0, &rms_pass1,
&rms_final);
/* One arm, both members plus the gamma-free RMS the "fold gamma downstream" item would run. */
#define ARM(name, arms, row_count) \
do { \
uint32_t row; \
(name).l2 = 0.0; \
(name).rms = 0.0; \
(name).rms_no_gamma = 0.0; \
for (row = 0; row < (row_count); row++) { \
const float *x_row = x + (size_t)row * cols; \
oracle_l2_norm_rows(x_row, eps, want, 1u, cols); \
ft_tt_vector_model_head_norm_float32( \
l2_pass0, l2_pass1, l2_final, x_row, NULL, 1.0f, \
eps *eps / (float)FT_TT_OP_TILE_DIM, got, 1u, cols, (arms)); \
(name).l2 = row_max_norm_relative(want, got, cols, (name).l2); \
ft_tt_vector_reference_rms_norm(x_row, gamma, eps, want, 1u, cols); \
ft_tt_vector_model_head_norm_float32( \
rms_pass0, rms_pass1, rms_final, x_row, gamma, 1.0f / (float)cols, \
eps * (float)cols / (float)FT_TT_OP_TILE_DIM, got, 1u, cols, (arms)); \
(name).rms = row_max_norm_relative(want, got, cols, (name).rms); \
ft_tt_vector_model_head_norm_float32( \
rms_pass0, rms_pass1, rms_final, x_row, NULL, 1.0f / (float)cols, \
eps * (float)cols / (float)FT_TT_OP_TILE_DIM, got, 1u, cols, \
(arms) | FT_TT_REDUCE_ARM_NO_GAMMA); \
ft_tt_vector_reference_rms_norm(x_row, unit_gamma, eps, want, 1u, cols); \
(name).rms_no_gamma = \
row_max_norm_relative(want, got, cols, (name).rms_no_gamma); \
} \
} while (0)
/* THE CONTROL THAT LICENSES EVERY ARM: at arms = 0 the switchable model must be the
* shipped Float32 model BIT FOR BIT. Without this the arms below measure a second
* program that merely resembles the first. */
{
bool identical = true;
bool armed_differs = false;
uint32_t row;
ft_tt_vector_model_reduce_program_float32(rms_pass0, rms_pass1, rms_final, x, gamma,
NULL, 1.0f / (float)cols,
eps * (float)cols / (float)FT_TT_OP_TILE_DIM,
control, 16u, cols);
for (row = 0; row < 16u; row++) {
const size_t offset = (size_t)row * cols;
ft_tt_vector_model_head_norm_float32(
rms_pass0, rms_pass1, rms_final, x + offset, gamma, 1.0f / (float)cols,
eps * (float)cols / (float)FT_TT_OP_TILE_DIM, got, 1u, cols, 0u);
if (memcmp(got, control + offset, (size_t)cols * sizeof(float)) != 0)
identical = false;
/* The same comparison with ONE arm on must DIFFER, or the check above is a
* memcmp of two buffers that were never going to disagree. */
ft_tt_vector_model_head_norm_float32(
rms_pass0, rms_pass1, rms_final, x + offset, gamma, 1.0f / (float)cols,
eps * (float)cols / (float)FT_TT_OP_TILE_DIM, got, 1u, cols,
FT_TT_REDUCE_ARM_ROUND_NEAREST);
if (memcmp(got, control + offset, (size_t)cols * sizeof(float)) != 0)
armed_differs = true;
}
ft_tt_test_check("the switchable model IS the shipped Float32 model at arms = 0",
identical, "bit-for-bit over 16 rows of the RMS member");
ft_tt_test_check("RED: one arm on and the same comparison DIFFERS", armed_differs,
"FT_TT_REDUCE_ARM_ROUND_NEAREST against the same 16 rows");
}
/* A program this arm does not model must be REFUSED, not approximated — softmax through
* it is all-NaN, which is the red proof that the shape guard is not decoration. */
{
uint32_t soft0 = 0u;
uint32_t soft1 = 0u;
uint32_t soft_final = 0u;
bool all_nan = true;
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_SOFTMAX, &soft0, &soft1, &soft_final);
ft_tt_vector_model_head_norm_float32(soft0, soft1, soft_final, x, NULL, 1.0f, 0.0f, got,
1u, cols, 0u);
for (element = 0; element < cols; element++) {
if (!isnan(got[element]))
all_nan = false;
}
ft_tt_test_check_fmt(
"RED: softmax through the head-norm arm is refused, not approximated", all_nan,
"all %u outputs NaN", cols);
}
{
struct arm_result shipped;
struct arm_result sfpu;
struct arm_result perturbed;
struct arm_result premultiply;
struct arm_result nearest;
struct arm_result nearest_host;
struct arm_result small;
ARM(shipped, 0u, rows);
ARM(small, 0u, 16u);
ARM(sfpu, FT_TT_REDUCE_ARM_SFPU_RSQRT, rows);
ARM(perturbed, FT_TT_REDUCE_ARM_RSQRT_PERTURB, rows);
ARM(premultiply, FT_TT_REDUCE_ARM_PREMULTIPLY, rows);
ARM(nearest, FT_TT_REDUCE_ARM_ROUND_NEAREST, rows);
ARM(nearest_host,
FT_TT_REDUCE_ARM_ROUND_NEAREST | FT_TT_REDUCE_ARM_HOST_ROUND, rows);
/* WALL 1: the SFPU rsqrt. Its own accuracy first, so the null below is a number and
* not only an absence — swept against fp64 across the binades a sum of 128 squares
* plus eps can land in. */
{
double worst = 0.0;
int exponent;
for (exponent = -20; exponent <= 20; exponent++) {
uint32_t step;
for (step = 0; step < 4096u; step++) {
const float value =
ldexpf(1.0f + (float)step / 4096.0f, exponent);
const double reference = 1.0 / sqrt((double)value);
const double relative =
fabs((double)ft_tt_vector_sfpu_rsqrt(value) - reference) / reference;
if (relative > worst)
worst = relative;
}
}
ft_tt_test_check_fmt("the SFPU rsqrt polynomial is 4 orders BELOW the residue it "
"was nominated for",
worst < 1e-6, "%.3e worst relative over 2^-20..2^21, against "
"a residue of 8.4e-04",
worst);
}
/* And in the program, where it is a NULL — the perturbed arm below is what says the
* score could have seen it. */
ft_tt_test_check_fmt(
"the SFPU rsqrt polynomial moves NEITHER member — the 2x candidate is refuted",
fabs(sfpu.l2 - shipped.l2) < shipped.l2 * 0.01 &&
fabs(sfpu.rms - shipped.rms) < shipped.rms * 0.01,
"libm L2 %.3e RMS %.3e -> SFPU %.3e / %.3e", shipped.l2, shipped.rms, sfpu.l2,
sfpu.rms);
/* THE RED ARM, and its DIRECTION is a second result. A +1e-3 rsqrt moves the L2
* member UP by 1.7x and the RMS member DOWN by 1.5x — because the RMS residue is a
* downward-biased scale error that an upward perturbation partly cancels. That is the
* same signature the GDN value path carries (`card/want` 0.9955-0.9977, below 1 on
* 768 of 768 head-layers), measured here on the reduce instead of asserted. So the
* check is that a 1e-3 rsqrt MOVES the score, not that it raises it. */
ft_tt_test_check_fmt(
"RED: an rsqrt off by 1e-3 relative moves BOTH members by >30% — so the null above "
"means something",
fabs(perturbed.l2 - shipped.l2) > shipped.l2 * 0.3 &&
fabs(perturbed.rms - shipped.rms) > shipped.rms * 0.3,
"L2 %.3e -> %.3e (up), RMS %.3e -> %.3e (DOWN — the residue is biased low)",
shipped.l2, perturbed.l2, shipped.rms, perturbed.rms);
/* WALL 2: the chain step count. Reordering it is a null — two FPU multiplies through
* circular buffers cost four Tf32 unpacks whichever operand pair goes first — and the
* whole of the RMS member's excess is gamma plus the scratch round trip. */
ft_tt_test_check_fmt(
"reordering the chain is a NULL: the unpack count, not the order, is what costs",
fabs(premultiply.rms - shipped.rms) < shipped.rms * 0.15,
"as shipped %.3e, premultiplied %.3e", shipped.rms, premultiply.rms);
ft_tt_test_check_fmt(
"and DROPPING gamma is the whole of the RMS member's excess over L2",
shipped.rms_no_gamma < shipped.rms * 0.5 &&
shipped.rms_no_gamma < shipped.l2 * 1.2,
"RMS %.3e -> %.3e with a one-step chain, against the L2 member's %.3e",
shipped.rms, shipped.rms_no_gamma, shipped.l2);
/* AND THAT IS THE RESULT THAT PRICES THE WHOLE ITEM: the L2 member's chain is ALREADY
* one step and it is 1.737e-03 on the card. A perfect chain-step fix lands the RMS
* member on the L2 member's number, which is itself 1.7x past the gate. */
ft_tt_test_check_fmt(
"so a PERFECT chain-step fix lands RMS on L2's figure — which still misses 1e-3 "
"on silicon",
shipped.rms_no_gamma > 1e-3 * 0.5,
"modelled one-step RMS %.3e; the card's one-step member measures 1.737e-03",
shipped.rms_no_gamma);
/* WALL 3: the sample size. It is real and it is small — and it is on the RMS member
* only, because the L2 member's residue is a common-mode scale error that every row
* carries equally. */
ft_tt_test_check_fmt("the card's 48x32 sample costs the RMS member a little and the "
"L2 member nothing",
small.l2 == shipped.l2 && shipped.rms > small.rms,
"16 rows: L2 %.3e RMS %.3e; 1536 rows: L2 %.3e RMS %.3e", small.l2,
small.rms, shipped.l2, shipped.rms);
/* The remaining kernel-source lever, priced: an SFPU pre-round to the NEAREST Tf32
* before every pack. Worth ~1.3x on RMS, and it makes the L2 member WORSE, because
* the truncation biases of the map and the chain partly CANCEL. */
ft_tt_test_check_fmt(
"rounding to nearest before the pack is worth ~1.3x on RMS and is NOT free on L2",
nearest.rms < shipped.rms && nearest.l2 > shipped.l2 * 0.9,
"RMS %.3e -> %.3e, L2 %.3e -> %.3e (host pre-round too: %.3e / %.3e)", shipped.rms,
nearest.rms, shipped.l2, nearest.l2, nearest_host.l2, nearest_host.rms);
/* WHAT IS LEFT OF THE 2x, AND IT IS ONE MANTISSA BIT. "E8M10" is written down two
* ways — ten stored plus a hidden one, or ten of significand of which nine are
* stored — and the difference is exactly a factor of two on a truncating unpack. The
* nine-bit reading reproduces the card's q/k L2 figure to four significant figures on
* uniform data, where the ten-bit reading is 2.07x under it. It is a HYPOTHESIS with
* one strong prediction behind it; `PN_TT_RED=head_norm_synthetic` settles it on
* silicon by removing the other difference, the data. */
{
struct arm_result nine;
struct arm_result nine_best;
ARM(nine, FT_TT_REDUCE_ARM_TF32_NINE_BITS, rows);
ft_tt_test_check_fmt("a NINE-bit Tf32 unpack reproduces the card's L2 member, and "
"the ten-bit one is 2.07x under it",
nine.l2 > 1.6e-3 && nine.l2 < 1.9e-3,
"ten bits %.3e, nine bits %.3e, silicon 1.737e-03 (RMS %.3e "
"/ %.3e against silicon's 3.165e-03)",
shipped.l2, nine.l2, shipped.rms, nine.rms);
/* AND THE CONSEQUENCE, which is why the bit matters at all: at nine bits every
* lever this family has, composed, still misses the gate. */
{
struct arm_result nine_kernel_rne;
ARM(nine_best,
FT_TT_REDUCE_ARM_TF32_NINE_BITS | FT_TT_REDUCE_ARM_ROUND_NEAREST |
FT_TT_REDUCE_ARM_HOST_ROUND,
rows);
ARM(nine_kernel_rne,
FT_TT_REDUCE_ARM_TF32_NINE_BITS | FT_TT_REDUCE_ARM_ROUND_NEAREST, rows);
ft_tt_test_check_fmt(
"at nine bits EVERY lever composed still misses 1e-3 — the gate is not "
"reachable in this family at Wt = 4",
nine_best.l2 > 1e-3 && nine_best.rms_no_gamma > 1e-3 &&
nine_kernel_rne.l2 > 1e-3 && nine_kernel_rne.rms_no_gamma > 1e-3,
"one-step chain, round-to-nearest on the kernel packs: L2 %.3e RMS %.3e; "
"and with the host operands too: L2 %.3e RMS %.3e",
nine_kernel_rne.l2, nine_kernel_rne.rms_no_gamma, nine_best.l2,
nine_best.rms_no_gamma);
}
}
}
/* The per-stage attribution, REPORTED rather than gated: which unpack spends the budget.
* Removing a stage can make the score WORSE, which is the evidence that the truncation
* biases partly cancel and that "fewer stages" is not automatically "less error". */
{
static const struct {
const char *name;
uint32_t arm;
} stages[] = {
{ "the MAP's x unpack", FT_TT_REDUCE_ARM_EXACT_MAP },
{ "the reduce's mid unpack", FT_TT_REDUCE_ARM_EXACT_MID },
{ "the chain's x unpack", FT_TT_REDUCE_ARM_EXACT_CHAIN_X },
{ "the rsqrt column's unpack", FT_TT_REDUCE_ARM_EXACT_COLUMN },
{ "gamma's unpack", FT_TT_REDUCE_ARM_EXACT_GAMMA },
{ "the chain's scratch round trip", FT_TT_REDUCE_ARM_EXACT_STAGE },
};
size_t index;
for (index = 0; index < sizeof(stages) / sizeof(stages[0]); index++) {
struct arm_result without;
char label[160];
ARM(without, stages[index].arm, rows);
snprintf(label, sizeof(label), "REPORTED: with %s made exact", stages[index].name);
ft_tt_test_check_fmt(label, true, "L2 %.3e, RMS %.3e", without.l2, without.rms);
}
}
#undef ARM
done:
free(x);
free(gamma);
free(unit_gamma);
free(want);
free(got);
free(control);
}
/* ---------------------------------------------------------------------------
* `gated` IS BOUND BY THE bf16 BRIDGE, NOT BY THE REDUCE
*
* The GDN's output gated norm is TWO descriptors on TWO residencies at TWO formats:
* `FT_TT_OP_REDUCE_FN_RMS_NORM` on the Float32 `reduce_fp32` core, and then
* `pn_tt_silu_mul(z, normed)` on the bf16 ELEMENTWISE residency. So the fp32 answer is
* RENDERED INTO A bf16 STRIP before the gate ever sees it.
*
* On silicon the Float32 program took the reduce alone from 8.599e-03 to 3.165e-03 (2.7x)
* and moved `gated` only 1.283e-02 -> 1.023e-02 (1.25x). That is the shape of a term the
* reduce does not own, and this prices it: the same two steps with the bridge and without.
* --------------------------------------------------------------------------- */
static void test_gated_is_bound_by_the_bf16_bridge(void)
{
/* FT_TT_OP_VECTOR_FN_SILU_MUL models a whole tile at a time, so the block is 1024
* elements = 8 heads of 128. */
const uint32_t cols = 128u;
const uint32_t rows = 128u;
const uint32_t block_rows = 8u;
const size_t count = (size_t)rows * cols;
const float eps = 1e-6f;
float *y = malloc(count * sizeof(float));
float *z = malloc(count * sizeof(float));
float *gamma = malloc(cols * sizeof(float));
float *normed = malloc((size_t)block_rows * cols * sizeof(float));
float *want = malloc((size_t)block_rows * cols * sizeof(float));
float *bridged = malloc((size_t)block_rows * cols * sizeof(float));
double reduce_alone = 0.0;
double gated_bridged = 0.0;
double gated_no_bridge = 0.0;
uint32_t pass0 = 0u;
uint32_t pass1 = 0u;
uint32_t final_word = 0u;
uint32_t block;
size_t element;
ft_tt_test_step("`gated`: the fp32 reduce against the bf16 bridge it crosses");
if (!y || !z || !gamma || !normed || !want || !bridged) {
ft_tt_test_check("allocation", false, "out of memory");
goto done;
}
ft_tt_vector_random_seed(0x1220E8ULL);
for (element = 0; element < count; element++)
y[element] = ft_tt_vector_random_value();
for (element = 0; element < count; element++)
z[element] = ft_tt_vector_random_value();
for (element = 0; element < cols; element++)
gamma[element] = 0.5f + ft_tt_vector_random_value() * 0.25f;
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_RMS_NORM, &pass0, &pass1, &final_word);
for (block = 0; block < rows / block_rows; block++) {
const size_t base = (size_t)block * block_rows * cols;
uint32_t row;
/* Step one: the Float32 reduce, exactly as it ships. */
ft_tt_vector_model_head_norm_float32(pass0, pass1, final_word, y + base, gamma,
1.0f / (float)cols,
eps * (float)cols / (float)FT_TT_OP_TILE_DIM,
normed, block_rows, cols, 0u);
ft_tt_vector_reference_rms_norm(y + base, gamma, eps, want, block_rows, cols);
for (row = 0; row < block_rows; row++)
reduce_alone = row_max_norm_relative(want + (size_t)row * cols,
normed + (size_t)row * cols, cols,
reduce_alone);
/* Step two AS SHIPPED: that answer rendered into a bf16 strip and gated on the bf16
* ELEMENTWISE residency. `pn_tt_silu_mul(z, normed)` is silu(a) * b with a = z. */
ft_tt_vector_model_eltwise(FT_TT_OP_VECTOR_FN_SILU_MUL, z + base, normed, bridged,
(size_t)block_rows * cols);
for (element = 0; element < (size_t)block_rows * cols; element++)
want[element] = (float)((double)want[element] *
((double)z[base + element] /
(1.0 + exp(-(double)z[base + element]))));
for (row = 0; row < block_rows; row++)
gated_bridged = row_max_norm_relative(want + (size_t)row * cols,
bridged + (size_t)row * cols, cols,
gated_bridged);
/* THE COUNTERFACTUAL: the same gate with no render in front of it. Not a thing the
* card can do today — that is the qkv/z strip bridge — and it exists to attribute. */
for (element = 0; element < (size_t)block_rows * cols; element++) {
const float gate = z[base + element] / (1.0f + expf(-z[base + element]));
bridged[element] = normed[element] * gate;
}
for (row = 0; row < block_rows; row++)
gated_no_bridge = row_max_norm_relative(want + (size_t)row * cols,
bridged + (size_t)row * cols, cols,
gated_no_bridge);
}
ft_tt_test_check_fmt("the bf16 gate costs MORE than the whole Float32 reduce does",
gated_bridged > reduce_alone * 2.0,
"reduce alone %.3e, then gated %.3e", reduce_alone, gated_bridged);
ft_tt_test_check_fmt("and removing the render puts `gated` back at the reduce's own figure",
gated_no_bridge < gated_bridged * 0.5,
"with the bf16 bridge %.3e, without it %.3e — a %.1fx term the "
"reduce does not own",
gated_bridged, gated_no_bridge, gated_bridged / gated_no_bridge);
ft_tt_test_check_fmt("so `gated` cannot reach 1e-3 while it crosses into bf16, whatever "
"the reduce does",
gated_bridged > 1e-3, "%.3e against a 1e-3 gate", gated_bridged);
done:
free(y);
free(z);
free(gamma);
free(normed);
free(want);
free(bridged);
}
static void test_reduce_parameters(void)
{
ft_tt_op_reduce_request request;
ft_tt_op_reduce_residency residency;
ft_tt_op_reduce_function softmax = FT_TT_OP_REDUCE_FN_SOFTMAX;
uint32_t words[FT_TT_OP_VECTOR_WORDS];
uint32_t pass0 = 0u;
uint32_t pass1 = 0u;
uint32_t final_word = 0u;
uint32_t ceiling;
int rc;
ft_tt_test_step("reduce parameter block");
memset(&request, 0, sizeof(request));
request.function = FT_TT_OP_REDUCE_FN_SOFTMAX;
request.row_blocks = 2u;
request.tile_cols = 48u;
request.prefetch_tiles = 32u;
request.input = make_operand(3u, 4u, 0x100000u);
request.constants = make_operand(5u, 6u, 0x200000u);
request.output = make_operand(7u, 8u, 0x300000u);
rc = ft_tt_op_reduce_parameters(&request, words);
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_SOFTMAX, &pass0, &pass1, &final_word);
ft_tt_test_check_fmt("a well-formed request encodes", rc == FT_TT_OK, "rc %d", rc);
ft_tt_test_check_fmt("tile count is row_blocks * tile_cols",
words[FT_TT_OP_VECTOR_TILE_COUNT] == 96u, "%u",
words[FT_TT_OP_VECTOR_TILE_COUNT]);
ft_tt_test_check_fmt("tile_cols lands in word 2", words[FT_TT_OP_VECTOR_TILE_COLS] == 48u,
"%u", words[FT_TT_OP_VECTOR_TILE_COLS]);
/* The run a reduce block may not span is Wt, not the total: a block that crossed a row
* boundary would hand the compute thread half of two different rows. */
ft_tt_test_check_fmt("depth divides Wt, not the total",
words[FT_TT_OP_VECTOR_DEPTH] == 24u, "%u", words[FT_TT_OP_VECTOR_DEPTH]);
ft_tt_test_check_fmt("the program lands in words 13, 14 and 15",
words[FT_TT_OP_REDUCE_PASS0] == pass0 &&
words[FT_TT_OP_REDUCE_PASS1] == pass1 &&
words[FT_TT_OP_REDUCE_FINAL] == final_word,
"0x%08X 0x%08X 0x%08X", words[FT_TT_OP_REDUCE_PASS0],
words[FT_TT_OP_REDUCE_PASS1], words[FT_TT_OP_REDUCE_FINAL]);
/* The one word the family must NOT use, because it means something else to the
* elementwise binary that shares this block layout. */
ft_tt_test_check_fmt("word 0 stays 0, so it cannot be read as an eltwise function",
words[FT_TT_OP_VECTOR_FUNCTION] == 0u, "%u",
words[FT_TT_OP_VECTOR_FUNCTION]);
memset(&residency, 0, sizeof(residency));
residency.max_tile_cols = 1u;
residency.tile_bytes = FT_TT_OP_TILE_BYTES_BF16;
ceiling = ft_tt_op_reduce_max_tile_cols(&residency);
ft_tt_test_check_fmt("a softmax residency's Wt ceiling is the arena's", ceiling >= 300u,
"Wt <= %u, i.e. W <= %u", ceiling, ceiling * FT_TT_OP_TILE_DIM);
request.tile_cols = ceiling;
rc = ft_tt_op_reduce_parameters(&request, words);
ft_tt_test_check_fmt("the ceiling itself is accepted", rc == FT_TT_OK, "rc %d at Wt %u", rc,
ceiling);
request.tile_cols = ceiling + 1u;
rc = ft_tt_op_reduce_parameters(&request, words);
ft_tt_test_check_fmt("one past the ceiling is refused", rc == FT_TT_EINVAL, "rc %d at Wt %u",
rc, ceiling + 1u);
/* 32k of attention context is Wt = 1024, and it does not fit. This assertion is the
* capacity argument for flash-decode attention, written down where it can go red. */
ft_tt_test_check_fmt("a 32k attention row does NOT fit a standalone softmax",
ceiling < 1024u, "Wt ceiling %u vs 1024 needed", ceiling);
/* A residency that also carries gamma and beta holds FOUR rows, not two, so its ceiling
* is half. Naming both is what stops "the softmax number" being quoted for a norm. */
{
static const ft_tt_op_reduce_function all[] = {
FT_TT_OP_REDUCE_FN_SOFTMAX, FT_TT_OP_REDUCE_FN_RMS_NORM,
FT_TT_OP_REDUCE_FN_LAYER_NORM, FT_TT_OP_REDUCE_FN_ROUTER_NORMALISE
};
ft_tt_op_reduce_residency full;
uint32_t full_ceiling;
rc = ft_tt_op_reduce_residency_for(all, sizeof(all) / sizeof(all[0]), 48u,
FT_TT_OP_TILE_BYTES_BF16, &full);
full_ceiling = ft_tt_op_reduce_max_tile_cols(&full);
ft_tt_test_check_fmt("a residency for all four carries gamma and beta",
rc == FT_TT_OK && full.carries_gamma && full.carries_beta, "rc %d",
rc);
ft_tt_test_check_fmt("and its ceiling is about half the softmax-only one",
full_ceiling * 2u <= ceiling + 4u && full_ceiling * 2u + 8u >= ceiling,
"four rows Wt <= %u against two rows Wt <= %u", full_ceiling,
ceiling);
rc = ft_tt_op_reduce_residency_for(all, sizeof(all) / sizeof(all[0]), full_ceiling + 1u,
FT_TT_OP_TILE_BYTES_BF16, &full);
ft_tt_test_check_fmt("one past THAT ceiling is refused at residency time",
rc == FT_TT_ENOMEM, "rc %d", rc);
}
request.tile_cols = 48u;
request.row_blocks = 0u;
rc = ft_tt_op_reduce_parameters(&request, words);
ft_tt_test_check_fmt("a zero row-block count is refused", rc == FT_TT_EINVAL, "rc %d", rc);
request.row_blocks = 2u;
request.function = (ft_tt_op_reduce_function)0;
rc = ft_tt_op_reduce_parameters(&request, words);
ft_tt_test_check_fmt("an unknown member is refused", rc == FT_TT_EINVAL, "rc %d", rc);
(void)softmax;
}
/* ================================================================
* Circular-buffer placement
* ================================================================ */
/** Every placed CB must lie in the arena, be 64-byte aligned and overlap nothing. */
static void check_placement(const char *label, const ft_tt_launch_cb_entry *entries,
unsigned count)
{
unsigned index;
unsigned misaligned = 0;
unsigned outside = 0;
unsigned overlapping = 0;
for (index = 0; index < count; index++) {
const uint32_t base = entries[index].address;
const uint32_t bytes = entries[index].size_bytes;
unsigned other;
if ((base & 63u) != 0u)
misaligned++;
if (base < FT_TT_OP_CB_ARENA_BASE || base + bytes > FT_TT_OP_CB_ARENA_END)
outside++;
for (other = 0; other < index; other++) {
const uint32_t other_base = entries[other].address;
const uint32_t other_bytes =
entries[other].size_bytes;
if (base < other_base + other_bytes && other_base < base + bytes)
overlapping++;
}
}
ft_tt_test_check_fmt(label, misaligned == 0 && outside == 0 && overlapping == 0,
"%u misaligned, %u outside the arena, %u overlapping", misaligned,
outside, overlapping);
}
static void test_eltwise_placement(void)
{
ft_tt_op_eltwise_request request;
ft_tt_launch_cb_entry entries[FT_TT_OP_ELTWISE_CB_COUNT];
uint64_t mask = 0;
int rc;
ft_tt_test_step("elementwise circular buffers");
memset(&request, 0, sizeof(request));
request.function = FT_TT_OP_VECTOR_FN_SILU_MUL;
request.tile_count = 96u;
request.prefetch_tiles = 48u;
request.input_a = make_operand(3u, 4u, 0x100000u);
request.input_b = make_operand(5u, 6u, 0x200000u);
request.output = make_operand(7u, 8u, 0x300000u);
rc = ft_tt_op_eltwise_place_cbs(&request, entries, g_cb_buffer, sizeof(g_cb_buffer), &mask);
ft_tt_test_check_fmt("four CBs place", rc == FT_TT_OK, "rc %d", rc);
check_placement("they are aligned, inside the arena and disjoint", entries,
FT_TT_OP_ELTWISE_CB_COUNT);
ft_tt_test_check_fmt("both inputs hold two blocks",
entries[0].page_count == 96u && entries[1].page_count == 96u, "%u, %u",
entries[0].page_count, entries[1].page_count);
ft_tt_test_check_fmt("the mask names exactly the four CBs used",
mask == ((1ull << FT_TT_OP_ELTWISE_CB_IN0) |
(1ull << FT_TT_OP_ELTWISE_CB_IN1) |
(1ull << FT_TT_OP_ELTWISE_CB_SCRATCH) |
(1ull << FT_TT_OP_ELTWISE_CB_OUT)),
"0x%llX", (unsigned long long)mask);
/* A unary function still places cb_in1, so the KERNEL alone decides arity and the host
* never has a table that can disagree with it. */
request.function = FT_TT_OP_VECTOR_FN_SILU;
memset(&request.input_b, 0, sizeof(request.input_b));
rc = ft_tt_op_eltwise_place_cbs(&request, entries, g_cb_buffer, sizeof(g_cb_buffer), &mask);
ft_tt_test_check_fmt("a unary request still places cb_in1",
rc == FT_TT_OK && entries[1].page_size_bytes == FT_TT_OP_TILE_BYTES_BF16,
"rc %d, page %u", rc, entries[1].page_size_bytes);
/* Past the arena it must REFUSE, not truncate: a truncated CB is a kernel writing over
* the queue region at the top of L1. */
request.function = FT_TT_OP_VECTOR_FN_ADD;
request.input_b = make_operand(5u, 6u, 0x200000u);
request.tile_count = 4096u;
request.prefetch_tiles = 4096u;
rc = ft_tt_op_eltwise_place_cbs(&request, entries, g_cb_buffer, sizeof(g_cb_buffer), &mask);
ft_tt_test_check_fmt("a depth past the arena is refused", rc == FT_TT_ENOMEM, "rc %d", rc);
}
static void test_reduce_placement(void)
{
static const ft_tt_op_reduce_function all[] = {
FT_TT_OP_REDUCE_FN_SOFTMAX, FT_TT_OP_REDUCE_FN_RMS_NORM,
FT_TT_OP_REDUCE_FN_LAYER_NORM, FT_TT_OP_REDUCE_FN_ROUTER_NORMALISE
};
ft_tt_op_reduce_residency residency;
ft_tt_launch_cb_entry entries[FT_TT_OP_REDUCE_CB_COUNT];
uint64_t mask = 0;
uint32_t ceiling;
int rc;
ft_tt_test_step("reduce circular buffers");
rc = ft_tt_op_reduce_residency_for(all, sizeof(all) / sizeof(all[0]), 48u,
FT_TT_OP_TILE_BYTES_BF16, &residency);
if (rc == FT_TT_OK)
rc = ft_tt_op_reduce_place_cbs(&residency, entries, g_cb_buffer, sizeof(g_cb_buffer),
&mask);
ft_tt_test_check_fmt("eleven CBs place", rc == FT_TT_OK, "rc %d", rc);
check_placement("they are aligned, inside the arena and disjoint", entries,
FT_TT_OP_REDUCE_CB_COUNT);
ft_tt_test_check_fmt("cb_in, cb_mid, gamma and beta are each a whole row deep",
entries[0].page_count == 48u && entries[4].page_count == 48u &&
entries[6].page_count == 48u && entries[7].page_count == 48u,
"%u, %u, %u, %u", entries[0].page_count, entries[4].page_count,
entries[6].page_count, entries[7].page_count);
/* A softmax-only residency must still PLACE gamma and beta, at one page. An unplaced CB
* a descriptor then asks for is a NoC write to an address nobody chose (spec §7.3); a
* one-page CB is a cb_reserve_back that blocks and is retired by its bound. */
{
ft_tt_op_reduce_function softmax = FT_TT_OP_REDUCE_FN_SOFTMAX;
rc = ft_tt_op_reduce_residency_for(&softmax, 1u, 48u, FT_TT_OP_TILE_BYTES_BF16,
&residency);
if (rc == FT_TT_OK)
rc = ft_tt_op_reduce_place_cbs(&residency, entries, g_cb_buffer, sizeof(g_cb_buffer),
&mask);
ft_tt_test_check_fmt("a softmax-only residency still places gamma and beta, at one page",
rc == FT_TT_OK && entries[6].page_count == 1u &&
entries[7].page_count == 1u,
"rc %d, gamma %u pages, beta %u pages", rc, entries[6].page_count,
entries[7].page_count);
ft_tt_test_check_fmt("the mask names all eleven",
mask == ((1ull << FT_TT_OP_REDUCE_CB_IN) |
(1ull << FT_TT_OP_REDUCE_CB_SCALER) |
(1ull << FT_TT_OP_REDUCE_CB_COL0) |
(1ull << FT_TT_OP_REDUCE_CB_COL1) |
(1ull << FT_TT_OP_REDUCE_CB_MID) |
(1ull << FT_TT_OP_REDUCE_CB_EPS) |
(1ull << FT_TT_OP_REDUCE_CB_GAMMA) |
(1ull << FT_TT_OP_REDUCE_CB_BETA) |
(1ull << FT_TT_OP_REDUCE_CB_STAGE0) |
(1ull << FT_TT_OP_REDUCE_CB_STAGE1) |
(1ull << FT_TT_OP_REDUCE_CB_OUT)),
"0x%llX", (unsigned long long)mask);
}
/* The documented ceiling has to be the REAL one. A ceiling that is merely conservative is
* a number nobody can plan against, and one that is optimistic is an ENOMEM on the card. */
ceiling = ft_tt_op_reduce_max_tile_cols(&residency);
residency.max_tile_cols = ceiling;
rc = ft_tt_op_reduce_place_cbs(&residency, entries, g_cb_buffer, sizeof(g_cb_buffer), &mask);
ft_tt_test_check_fmt("the ceiling places", rc == FT_TT_OK, "rc %d at Wt %u", rc, ceiling);
residency.max_tile_cols = ceiling + 1u;
rc = ft_tt_op_reduce_place_cbs(&residency, entries, g_cb_buffer, sizeof(g_cb_buffer), &mask);
ft_tt_test_check_fmt("one past the ceiling does not place", rc == FT_TT_ENOMEM,
"rc %d at Wt %u", rc, ceiling + 1u);
}
/* ================================================================
* The constants buffer
* ================================================================ */
/** Untilize one constant tile and return its first element, plus a count of the elements
* that disagree with it — a constant tile that is not constant is the interesting failure. */
static float constant_tile_value(const unsigned char *tile, unsigned *out_wrong)
{
uint16_t plain[FT_TT_OP_TILE_DIM * FT_TT_OP_TILE_DIM];
float first;
size_t index;
*out_wrong = 0u;
if (ft_tt_untilize_strip(tile, sizeof(uint16_t), FT_TT_OP_TILE_DIM, FT_TT_OP_TILE_DIM,
FT_TT_OP_TILE_DIM * sizeof(uint16_t), plain) != 0) {
*out_wrong = 1u;
return 0.0f;
}
first = ft_float_from_bf16(plain[0]);
for (index = 0; index < FT_TT_OP_TILE_DIM * FT_TT_OP_TILE_DIM; index++) {
if (ft_float_from_bf16(plain[index]) != first)
(*out_wrong)++;
}
return first;
}
/** `constant_tile_value()` for a Float32 constants buffer: 4-byte elements, and the value is
* compared EXACTLY because an fp32 tile has nothing to round it. */
static float constant_tile_value_float32(const unsigned char *tile, unsigned *out_wrong)
{
float plain[FT_TT_OP_TILE_DIM * FT_TT_OP_TILE_DIM];
float first;
size_t index;
*out_wrong = 0u;
if (ft_tt_untilize_strip(tile, sizeof(float), FT_TT_OP_TILE_DIM, FT_TT_OP_TILE_DIM,
FT_TT_OP_TILE_DIM * sizeof(float), plain) != 0) {
*out_wrong = 1u;
return 0.0f;
}
first = plain[0];
for (index = 0; index < FT_TT_OP_TILE_DIM * FT_TT_OP_TILE_DIM; index++) {
if (plain[index] != first)
(*out_wrong)++;
}
return first;
}
/**
* THE SAME CONSTANTS BUFFER AT Float32, WHICH IS THE ONE HOST PIECE `reduce_float32.cbtable`
* NEEDS AND THE ONE THAT CANNOT FAIL LOUDLY.
*
* A constants buffer built at 2048 under a program placed at 4096 is not refused by anything
* on the card: the reader issues 4096-byte reads, there is no descriptor header on a
* data-movement core, and the result is a scaler tile made of half a tile and whatever
* followed it — a smoothly wrong norm. So the page size is a parameter of the builder and
* this is what pins it.
*
* The GDN head width is 128, which is what the two per-head norms run at.
*/
static void test_reduce_constants_float32(void)
{
const uint32_t width = 128u;
const uint32_t tile_cols = width / FT_TT_OP_TILE_DIM;
const float eps = 1e-6f;
const size_t bf16_bytes =
ft_tt_op_reduce_constants_bytes(FT_TT_OP_REDUCE_FN_RMS_NORM, tile_cols,
FT_TT_OP_TILE_BYTES_BF16);
const size_t bytes = ft_tt_op_reduce_constants_bytes(FT_TT_OP_REDUCE_FN_RMS_NORM, tile_cols,
FT_TT_OP_TILE_BYTES_FP32);
float *gamma = malloc(width * sizeof(float));
unsigned char *buffer = malloc(bytes);
unsigned wrong = 0u;
uint32_t index;
int rc;
ft_tt_test_step("the constants buffer at Float32 — the host half of reduce_float32");
if (!gamma || !buffer) {
ft_tt_test_check("allocation", false, "out of memory");
goto done;
}
ft_tt_vector_random_seed(0x1220E9ULL);
for (index = 0; index < width; index++)
gamma[index] = 0.5f + ft_tt_vector_random_value() * 0.25f;
ft_tt_test_check_fmt("an fp32 constants buffer is exactly twice a bf16 one",
bytes == 2u * bf16_bytes &&
bytes == (size_t)(2u + tile_cols) * FT_TT_OP_TILE_BYTES_FP32,
"%zu vs %zu bytes at Wt=%u", bytes, bf16_bytes, tile_cols);
rc = ft_tt_op_reduce_build_constants(FT_TT_OP_REDUCE_FN_RMS_NORM, width, eps, gamma, NULL,
FT_TT_OP_TILE_BYTES_FP32, buffer, bytes);
ft_tt_test_check_fmt("it builds at Float32", rc == FT_TT_OK, "rc %d", rc);
if (rc != FT_TT_OK)
goto done;
/* EXACT equality, not a bf16 round trip — that IS the difference this table buys, and a
* builder that still went through bf16 would fail here and pass every bf16 check. */
ft_tt_test_check_fmt("slot 0 is 1/W to the bit, with no bf16 rounding in it",
constant_tile_value_float32(buffer, &wrong) == 1.0f / (float)width &&
wrong == 0u,
"%.9g against %.9g, %u elements disagreeing",
(double)constant_tile_value_float32(buffer, &wrong),
(double)(1.0f / (float)width), wrong);
ft_tt_test_check_fmt("slot 1 is eps*W/32 to the bit",
constant_tile_value_float32(buffer + FT_TT_OP_TILE_BYTES_FP32,
&wrong) ==
eps * (float)width / (float)FT_TT_OP_TILE_DIM &&
wrong == 0u,
"%.9g",
(double)constant_tile_value_float32(buffer + FT_TT_OP_TILE_BYTES_FP32,
&wrong));
/* gamma, ROW-REPLICATED at the fp32 stride. A builder that kept the bf16 tile stride
* would put tile 1 half a tile early and this is what sees it. */
{
float plain[FT_TT_OP_TILE_DIM * FT_TT_OP_TILE_DIM];
unsigned bad = 0u;
uint32_t tile;
for (tile = 0; tile < tile_cols; tile++) {
const unsigned char *source =
buffer + (size_t)(2u + tile) * FT_TT_OP_TILE_BYTES_FP32;
uint32_t row;
uint32_t column;
(void)ft_tt_untilize_strip(source, sizeof(float), FT_TT_OP_TILE_DIM,
FT_TT_OP_TILE_DIM, FT_TT_OP_TILE_DIM * sizeof(float),
plain);
for (row = 0; row < FT_TT_OP_TILE_DIM; row++) {
for (column = 0; column < FT_TT_OP_TILE_DIM; column++) {
if (plain[row * FT_TT_OP_TILE_DIM + column] !=
gamma[tile * FT_TT_OP_TILE_DIM + column])
bad++;
}
}
}
ft_tt_test_check_fmt("gamma is row-replicated at the fp32 tile stride, bit-exact",
bad == 0u, "%u of %u elements wrong", bad,
tile_cols * FT_TT_OP_TILE_DIM * FT_TT_OP_TILE_DIM);
}
/* The L2 member, which is the q/k arm and the one whose eps FOLLOWS THE SCALER: it sums
* rather than means, so the eps tile is eps/32 and not eps*W/32. */
rc = ft_tt_op_reduce_build_constants(FT_TT_OP_REDUCE_FN_L2_NORM, width, eps * eps, NULL,
NULL, FT_TT_OP_TILE_BYTES_FP32, buffer, bytes);
ft_tt_test_check_fmt("the L2 member builds at Float32 with scaler 1.0 and eps/32",
rc == FT_TT_OK &&
constant_tile_value_float32(buffer, &wrong) == 1.0f &&
constant_tile_value_float32(buffer + FT_TT_OP_TILE_BYTES_FP32,
&wrong) ==
eps * eps / (float)FT_TT_OP_TILE_DIM,
"rc %d, scaler %.9g, eps tile %.9g", rc,
(double)constant_tile_value_float32(buffer, &wrong),
(double)constant_tile_value_float32(buffer + FT_TT_OP_TILE_BYTES_FP32,
&wrong));
/* THE TWO REFUSALS THAT MATTER, because both are the silent-wrong-answer shape. */
rc = ft_tt_op_reduce_build_constants(FT_TT_OP_REDUCE_FN_RMS_NORM, width, eps, gamma, NULL,
FT_TT_OP_TILE_BYTES_FP32, buffer, bf16_bytes);
ft_tt_test_check_fmt("a buffer SIZED at bf16 and BUILT at fp32 is refused, not overrun",
rc == FT_TT_EINVAL, "rc %d", rc);
rc = ft_tt_op_reduce_build_constants(FT_TT_OP_REDUCE_FN_RMS_NORM, width, eps, gamma, NULL,
1024u, buffer, bytes);
ft_tt_test_check_fmt("a page size that is neither bf16 nor fp32 is refused",
rc == FT_TT_EINVAL, "rc %d", rc);
ft_tt_test_check_fmt("and so is sizing one",
ft_tt_op_reduce_constants_bytes(FT_TT_OP_REDUCE_FN_RMS_NORM, tile_cols,
0u) == 0u,
"0 bytes at page size 0, Wt %u", tile_cols);
done:
free(gamma);
free(buffer);
}
static void test_reduce_constants(void)
{
const uint32_t width = 1536u;
const uint32_t tile_cols = width / FT_TT_OP_TILE_DIM;
const float eps = 1e-5f;
float *gamma = malloc(width * sizeof(float));
float *beta = malloc(width * sizeof(float));
unsigned char *buffer;
size_t bytes;
unsigned wrong = 0u;
uint32_t index;
int rc;
ft_tt_test_step("the reduce constants buffer");
bytes = ft_tt_op_reduce_constants_bytes(FT_TT_OP_REDUCE_FN_LAYER_NORM, tile_cols,
FT_TT_OP_TILE_BYTES_BF16);
buffer = malloc(bytes);
if (!gamma || !beta || !buffer) {
ft_tt_test_check("host buffers allocate", false, "out of memory");
goto done;
}
for (index = 0; index < width; index++) {
gamma[index] = 0.5f + (float)index * 0.001f;
beta[index] = -0.25f + (float)index * 0.0005f;
}
ft_tt_test_check_fmt("layer norm asks for 2 + 2*Wt tiles",
bytes == (size_t)(2u + 2u * tile_cols) * FT_TT_OP_TILE_BYTES_BF16,
"%zu bytes for Wt %u", bytes, tile_cols);
ft_tt_test_check_fmt("softmax asks for the two constant tiles and no stream",
ft_tt_op_reduce_constants_bytes(FT_TT_OP_REDUCE_FN_SOFTMAX, tile_cols,
FT_TT_OP_TILE_BYTES_BF16) ==
2u * FT_TT_OP_TILE_BYTES_BF16,
"%zu",
ft_tt_op_reduce_constants_bytes(FT_TT_OP_REDUCE_FN_SOFTMAX, tile_cols,
FT_TT_OP_TILE_BYTES_BF16));
rc = ft_tt_op_reduce_build_constants(FT_TT_OP_REDUCE_FN_LAYER_NORM, width, eps, gamma, beta,
FT_TT_OP_TILE_BYTES_BF16, buffer, bytes);
ft_tt_test_check_fmt("it builds", rc == FT_TT_OK, "rc %d", rc);
/* Slot 0: the scaler. 1/W for a member that wants a MEAN. */
ft_tt_test_check_fmt("slot 0 is the 1/W scaler",
constant_tile_value(buffer, &wrong) ==
ft_float_from_bf16(ft_bf16_from_float(1.0f / (float)width)) &&
wrong == 0u,
"%g with %u elements disagreeing",
(double)constant_tile_value(buffer, &wrong), wrong);
/* Slot 1: eps*W/32, which is the whole trick — each row of that tile has 32 columns, so
* 32 * (eps*W/32) * (1/W) = eps, and eps costs one extra reduce_tile instead of a
* broadcast add and a CB round trip. */
ft_tt_test_check_fmt("slot 1 is eps*W/32, so one reduce_tile adds exactly eps",
constant_tile_value(buffer + FT_TT_OP_TILE_BYTES_BF16, &wrong) ==
ft_float_from_bf16(ft_bf16_from_float(
eps * (float)width / (float)FT_TT_OP_TILE_DIM)) &&
wrong == 0u,
"%g",
(double)constant_tile_value(buffer + FT_TT_OP_TILE_BYTES_BF16, &wrong));
/* The gamma stream: each tile's every ROW must repeat that tile's 32 gamma values, which
* is what turns the multiply into a plain mul_tiles rather than a broadcast. */
{
uint16_t plain[FT_TT_OP_TILE_DIM * FT_TT_OP_TILE_DIM];
unsigned bad_columns = 0u;
unsigned bad_rows = 0u;
uint32_t tile;
for (tile = 0; tile < tile_cols; tile++) {
const unsigned char *source =
buffer + (size_t)(2u + tile) * FT_TT_OP_TILE_BYTES_BF16;
uint32_t row;
uint32_t column;
(void)ft_tt_untilize_strip(source, sizeof(uint16_t), FT_TT_OP_TILE_DIM,
FT_TT_OP_TILE_DIM, FT_TT_OP_TILE_DIM * sizeof(uint16_t),
plain);
for (column = 0; column < FT_TT_OP_TILE_DIM; column++) {
const float want =
ft_float_from_bf16(ft_bf16_from_float(gamma[tile * FT_TT_OP_TILE_DIM +
column]));
if (ft_float_from_bf16(plain[column]) != want)
bad_columns++;
for (row = 1; row < FT_TT_OP_TILE_DIM; row++) {
if (ft_float_from_bf16(plain[row * FT_TT_OP_TILE_DIM + column]) != want)
bad_rows++;
}
}
}
ft_tt_test_check_fmt("gamma expands to full tiles, row-replicated",
bad_columns == 0u && bad_rows == 0u,
"%u wrong columns, %u wrong replications", bad_columns, bad_rows);
}
rc = ft_tt_op_reduce_build_constants(FT_TT_OP_REDUCE_FN_LAYER_NORM, width, eps, gamma, NULL,
FT_TT_OP_TILE_BYTES_BF16, buffer, bytes);
ft_tt_test_check_fmt("layer norm without a beta is refused, not silently zeroed",
rc == FT_TT_EINVAL, "rc %d", rc);
rc = ft_tt_op_reduce_build_constants(FT_TT_OP_REDUCE_FN_LAYER_NORM, width, eps, gamma, beta,
FT_TT_OP_TILE_BYTES_BF16, buffer, 8u);
ft_tt_test_check_fmt("a short buffer is refused", rc == FT_TT_EINVAL, "rc %d", rc);
done:
free(gamma);
free(beta);
free(buffer);
}
/* ================================================================
* The model against the reference — the PCC prediction
* ================================================================ */
/** Score one array pair the way the hardware pass will, and print both metrics. */
static void score(const char *label, const float *expected, const float *actual, size_t count)
{
char census[192];
const size_t non_finite =
ft_tt_vector_count_non_finite(expected, actual, count, census, sizeof(census));
double pcc;
double worst;
if (non_finite != 0u) {
ft_tt_test_check_fmt(label, false, "NON-FINITE: %s", census);
return;
}
pcc = ft_tt_vector_pearson(expected, actual, count);
worst = ft_tt_vector_max_abs_difference(expected, actual, count);
ft_tt_test_check_fmt(label, pcc >= PCC_ACCEPT, "PCC %.9f, max abs %.6g", pcc, worst);
}
/**
* THE EPS TILE FOLLOWS THE SCALER, and a member that SUMS needs a different value from one
* that MEANS.
*
* The eps trick is one more accumulated row reduce, so the pass contributes
* `32 * tile_value * scaler`. At scaler 1/W that wants `eps*W/32`; at scaler 1.0 it wants
* `eps/32`. The unconditional `eps*W/32` that shipped before L2_NORM existed is wrong by a
* factor of W for any summing member — 128x at the GDN's head width — and nothing on the
* card can see it, because an eps that is too large is a smoothly wrong norm.
*/
static void test_eps_tile_follows_the_scaler(void)
{
const uint32_t width = 128u;
const uint32_t tile_cols = width / FT_TT_OP_TILE_DIM;
const float eps = 1e-5f;
unsigned char *buffer = NULL;
size_t bytes;
unsigned wrong = 0u;
int rc;
ft_tt_test_step("the eps tile is scaled by the member's own reduce scaler");
bytes = ft_tt_op_reduce_constants_bytes(FT_TT_OP_REDUCE_FN_L2_NORM, tile_cols,
FT_TT_OP_TILE_BYTES_BF16);
buffer = malloc(bytes);
if (!buffer) {
ft_tt_test_check("host buffer allocates", false, "out of memory");
return;
}
ft_tt_test_check_fmt("L2 norm asks for the two constant tiles and no stream",
bytes == 2u * FT_TT_OP_TILE_BYTES_BF16, "%zu bytes", bytes);
rc = ft_tt_op_reduce_build_constants(FT_TT_OP_REDUCE_FN_L2_NORM, width, eps, NULL, NULL,
FT_TT_OP_TILE_BYTES_BF16, buffer, bytes);
ft_tt_test_check_fmt("it builds with no gamma and no beta", rc == FT_TT_OK, "rc %d", rc);
ft_tt_test_check_fmt("slot 0 is 1.0, not 1/W — the reduce is a SUM",
constant_tile_value(buffer, &wrong) == 1.0f && wrong == 0u,
"%g with %u elements disagreeing",
(double)constant_tile_value(buffer, &wrong), wrong);
ft_tt_test_check_fmt("slot 1 is eps/32, not eps*W/32",
constant_tile_value(buffer + FT_TT_OP_TILE_BYTES_BF16, &wrong) ==
ft_float_from_bf16(ft_bf16_from_float(
eps / (float)FT_TT_OP_TILE_DIM)) &&
wrong == 0u,
"%g with %u elements disagreeing",
(double)constant_tile_value(buffer + FT_TT_OP_TILE_BYTES_BF16, &wrong),
wrong);
/* The two members that already shipped are UNMOVED: their scaler is a mean, so the
* value is the one they have always carried. */
{
float gamma[128];
unsigned char *rms;
uint32_t index;
for (index = 0; index < width; index++)
gamma[index] = 0.5f + (float)index * 0.001f;
bytes = ft_tt_op_reduce_constants_bytes(FT_TT_OP_REDUCE_FN_RMS_NORM, tile_cols,
FT_TT_OP_TILE_BYTES_BF16);
rms = malloc(bytes);
if (!rms) {
ft_tt_test_check("host buffer allocates", false, "out of memory");
free(buffer);
return;
}
rc = ft_tt_op_reduce_build_constants(FT_TT_OP_REDUCE_FN_RMS_NORM, width, eps, gamma,
NULL, FT_TT_OP_TILE_BYTES_BF16, rms, bytes);
ft_tt_test_check_fmt("RMS norm's eps tile is still eps*W/32",
rc == FT_TT_OK &&
constant_tile_value(rms + FT_TT_OP_TILE_BYTES_BF16, &wrong) ==
ft_float_from_bf16(ft_bf16_from_float(
eps * (float)width / (float)FT_TT_OP_TILE_DIM)),
"rc %d, %g", rc,
(double)constant_tile_value(rms + FT_TT_OP_TILE_BYTES_BF16,
&wrong));
free(rms);
}
free(buffer);
}
static void test_eltwise_model(void)
{
static const ft_tt_op_vector_function functions[] = {
FT_TT_OP_VECTOR_FN_SILU, FT_TT_OP_VECTOR_FN_SIGMOID, FT_TT_OP_VECTOR_FN_ADD,
FT_TT_OP_VECTOR_FN_MUL, FT_TT_OP_VECTOR_FN_SUB, FT_TT_OP_VECTOR_FN_SILU_MUL
};
const size_t count = 48u * FT_TT_OP_TILE_DIM * FT_TT_OP_TILE_DIM;
float *a = malloc(count * sizeof(float));
float *b = malloc(count * sizeof(float));
float *expected = malloc(count * sizeof(float));
float *actual = malloc(count * sizeof(float));
unsigned index;
ft_tt_test_step("elementwise: the tile-space model against the fp32 reference");
if (!a || !b || !expected || !actual) {
ft_tt_test_check("allocation", false, "out of memory");
free(a);
free(b);
free(expected);
free(actual);
return;
}
for (index = 0; index < sizeof(functions) / sizeof(functions[0]); index++) {
const ft_tt_op_vector_function function = functions[index];
const bool binary = ft_tt_op_vector_function_is_binary(function);
size_t element;
char label[96];
ft_tt_vector_random_seed(0x51EDULL + index);
for (element = 0; element < count; element++) {
a[element] = ft_tt_vector_random_value();
b[element] = ft_tt_vector_random_value();
}
/* The reference consumes the values the CARD will see — bf16-rounded — so the score
* is about the OP and not about a rounding the kernel is not responsible for. */
for (element = 0; element < count; element++) {
a[element] = ft_float_from_bf16(ft_bf16_from_float(a[element]));
b[element] = ft_float_from_bf16(ft_bf16_from_float(b[element]));
}
ft_tt_vector_reference_eltwise(function, a, binary ? b : NULL, expected, count);
ft_tt_vector_model_eltwise(function, a, binary ? b : NULL, actual, count);
snprintf(label, sizeof(label), "%s over %u tiles",
ft_tt_op_vector_function_name(function), 48u);
score(label, expected, actual, count);
}
free(a);
free(b);
free(expected);
free(actual);
}
static void test_softmax_model(void)
{
static const uint32_t widths[] = { 32u, 64u, 1536u, 4096u };
const uint32_t rows = 64u;
unsigned index;
ft_tt_test_step("softmax: the tile-space model against the fp32 reference");
for (index = 0; index < sizeof(widths) / sizeof(widths[0]); index++) {
const uint32_t cols = widths[index];
const size_t count = (size_t)rows * cols;
float *x = malloc(count * sizeof(float));
float *expected = malloc(count * sizeof(float));
float *actual = malloc(count * sizeof(float));
size_t element;
char label[96];
if (!x || !expected || !actual) {
ft_tt_test_check("allocation", false, "out of memory");
free(x);
free(expected);
free(actual);
return;
}
ft_tt_vector_random_seed(0x50F7ULL + index);
for (element = 0; element < count; element++)
x[element] = ft_float_from_bf16(ft_bf16_from_float(ft_tt_vector_random_value()));
ft_tt_vector_reference_softmax(x, expected, rows, cols);
ft_tt_vector_model_softmax(x, actual, rows, cols);
snprintf(label, sizeof(label), "%u x %u (Wt = %u)", rows, cols,
cols / FT_TT_OP_TILE_DIM);
score(label, expected, actual, count);
free(x);
free(expected);
free(actual);
}
}
/**
* The max-subtraction pass, proved load-bearing by the only data that can prove it.
*
* At the [-1, 1) range every other test uses, a softmax with NO max subtraction scores
* identically — exp(1) is 2.7 and nothing overflows. So a PCC gate on random small
* operands cannot see the difference, and a kernel that dropped the pass would ship green.
* At a range where exp overflows, the same arrangement is the difference between a result
* and a page of infinities.
*/
static void test_softmax_dynamic_range(void)
{
const uint32_t rows = 32u;
const uint32_t cols = 128u;
const size_t count = (size_t)rows * cols;
float *x = malloc(count * sizeof(float));
float *expected = malloc(count * sizeof(float));
float *actual = malloc(count * sizeof(float));
size_t element;
unsigned naive_non_finite = 0;
ft_tt_test_step("softmax: the range where the max pass stops being cosmetic");
if (!x || !expected || !actual) {
ft_tt_test_check("allocation", false, "out of memory");
free(x);
free(expected);
free(actual);
return;
}
ft_tt_vector_random_seed(0xBADFULL);
for (element = 0; element < count; element++)
x[element] = ft_float_from_bf16(ft_bf16_from_float(
ft_tt_vector_random_value_scaled(120.0f)));
/* What a max-free implementation would produce, computed here rather than assumed. */
for (element = 0; element < count; element++) {
if (!isfinite(expf(x[element])))
naive_non_finite++;
}
ft_tt_test_check_fmt("exp(x) alone overflows on this data", naive_non_finite > 0u,
"%u of %zu elements", naive_non_finite, count);
ft_tt_vector_reference_softmax(x, expected, rows, cols);
ft_tt_vector_model_softmax(x, actual, rows, cols);
score("with the max pass, 32 x 128 at range +/-120", expected, actual, count);
free(x);
free(expected);
free(actual);
}
/**
* The max must be taken over the WHOLE ROW, not over the first tile — and this is the only
* test in the file that can tell.
*
* FOUND BY A MUTATION THAT CAME BACK GREEN. Reducing the model's max over one tile instead
* of all Wt fails nothing above, and the reason is mathematics rather than a weak
* assertion: softmax(x - c) = softmax(x) for ANY constant c, so subtracting the wrong
* maximum changes nothing at all as long as no exponential overflows. Every PCC check in
* this file is therefore structurally blind to a partial-row max, and so is the on-card
* acceptance, and so would a reviewer be.
*
* What is not blind to it is a row whose largest element is NOT in the first tile and is
* more than ~88 above it — then a partial max leaves exp() overflowing and the answer is a
* page of infinities instead of a slightly different constant. That is this test: a plain
* [-1, 1) row with ONE outlier of +200 planted in the LAST tile.
*
* The general lesson is dev notes §3's, one op further on: a check with a mathematical
* invariance in it is a check that cannot see whatever the invariance absorbs.
*/
static void test_softmax_max_is_over_the_whole_row(void)
{
const uint32_t rows = 32u;
const uint32_t cols = 256u; /* Wt = 8, so "the first tile" is an eighth of the row */
const size_t count = (size_t)rows * cols;
float *x = malloc(count * sizeof(float));
float *expected = malloc(count * sizeof(float));
float *actual = malloc(count * sizeof(float));
size_t element;
uint32_t row;
ft_tt_test_step("softmax: the max is over the WHOLE row, not the first tile");
if (!x || !expected || !actual) {
ft_tt_test_check("allocation", false, "out of memory");
free(x);
free(expected);
free(actual);
return;
}
ft_tt_vector_random_seed(0x0177ULL);
for (element = 0; element < count; element++)
x[element] = ft_float_from_bf16(ft_bf16_from_float(ft_tt_vector_random_value()));
/* One outlier per row, in the LAST tile. 200 is well past the ~88 where exp overflows
* fp32, so a max taken over any earlier tile cannot rescue it. */
for (row = 0; row < rows; row++)
x[(size_t)row * cols + (cols - 3u)] = 200.0f;
ft_tt_vector_reference_softmax(x, expected, rows, cols);
ft_tt_vector_model_softmax(x, actual, rows, cols);
score("an outlier of +200 in the last tile, 32 x 256", expected, actual, count);
free(x);
free(expected);
free(actual);
}
/**
* The three new members' tile-space models against their fp32 references.
*
* Same purpose as the softmax model test: predict the on-card PCC before spending a core on
* it. §22 recorded that the model called silicon to ~6 decimals for the two ops it had, so
* a prediction here is worth making and worth checking against the hardware pass afterwards.
*/
static void test_reduce_models(void)
{
static const uint32_t widths[] = { 32u, 1536u };
const uint32_t rows = 64u;
const float eps = 1e-5f;
unsigned index;
ft_tt_test_step("RMS norm, layer norm and the router: model against reference");
for (index = 0; index < sizeof(widths) / sizeof(widths[0]); index++) {
const uint32_t cols = widths[index];
const size_t count = (size_t)rows * cols;
float *x = malloc(count * sizeof(float));
float *gamma = malloc(cols * sizeof(float));
float *beta = malloc(cols * sizeof(float));
float *expected = malloc(count * sizeof(float));
float *actual = malloc(count * sizeof(float));
size_t element;
char label[96];
if (!x || !gamma || !beta || !expected || !actual) {
ft_tt_test_check("allocation", false, "out of memory");
goto next;
}
ft_tt_vector_random_seed(0x4EDCE0ULL + index);
for (element = 0; element < count; element++)
x[element] = ft_float_from_bf16(ft_bf16_from_float(ft_tt_vector_random_value()));
for (element = 0; element < cols; element++) {
gamma[element] =
ft_float_from_bf16(ft_bf16_from_float(0.5f + ft_tt_vector_random_value() * 0.25f));
beta[element] =
ft_float_from_bf16(ft_bf16_from_float(ft_tt_vector_random_value() * 0.1f));
}
ft_tt_vector_reference_rms_norm(x, gamma, eps, expected, rows, cols);
ft_tt_vector_model_rms_norm(x, gamma, eps, actual, rows, cols);
snprintf(label, sizeof(label), "RMS norm %u x %u (Wt = %u)", rows, cols,
cols / FT_TT_OP_TILE_DIM);
score(label, expected, actual, count);
ft_tt_vector_reference_layer_norm(x, gamma, beta, eps, expected, rows, cols);
ft_tt_vector_model_layer_norm(x, gamma, beta, eps, actual, rows, cols);
snprintf(label, sizeof(label), "layer norm %u x %u (Wt = %u)", rows, cols,
cols / FT_TT_OP_TILE_DIM);
score(label, expected, actual, count);
/* Positive gates: x/sum(x) on signed noise divides by something near zero, which is
* a property of the TEST DATA and not of the op. */
for (element = 0; element < count; element++)
x[element] = ft_float_from_bf16(ft_bf16_from_float(0.05f + fabsf(x[element])));
ft_tt_vector_reference_router_normalise(x, expected, rows, cols);
ft_tt_vector_model_router_normalise(x, actual, rows, cols);
snprintf(label, sizeof(label), "router normalise %u x %u (Wt = %u)", rows, cols,
cols / FT_TT_OP_TILE_DIM);
score(label, expected, actual, count);
next:
free(x);
free(gamma);
free(beta);
free(expected);
free(actual);
}
}
/**
* PCC IS BLIND TO A GLOBAL SCALE, AND THREE OF THE FOUR MEMBERS ARE SCALE-SHAPED.
*
* This is §22.2's lesson in its second form. Softmax hides a wrong row maximum behind
* shift-invariance; RMS norm, layer norm and the router hide a wrong SCALE behind the fact
* that a correlation is invariant under multiplying one side by a constant. A reduce that
* summed the row twice, a scaler tile off by two, an rsqrt where a reciprocal belongs — all
* of them are exactly that, and every PCC gate in this file and in the on-card acceptance
* would pass them.
*
* So this test does the mutation itself, in the model, and asserts BOTH things: PCC does not
* move, and max-abs does. That is the evidence for scoring the family on a relative max-abs
* budget as well as on PCC, and it is what the on-card kernel mutation then confirms.
*/
static void test_pcc_is_blind_to_scale(void)
{
const uint32_t rows = 32u;
const uint32_t cols = 1536u;
const size_t count = (size_t)rows * cols;
float *x = malloc(count * sizeof(float));
float *gamma = malloc(cols * sizeof(float));
float *reference = malloc(count * sizeof(float));
float *scaled = malloc(count * sizeof(float));
size_t element;
double pcc;
double worst;
double peak = 0.0;
ft_tt_test_step("PCC cannot see a global scale — which is why max-abs is a CHECK here");
if (!x || !gamma || !reference || !scaled) {
ft_tt_test_check("allocation", false, "out of memory");
goto done;
}
ft_tt_vector_random_seed(0x5CA1EULL);
for (element = 0; element < count; element++)
x[element] = ft_float_from_bf16(ft_bf16_from_float(ft_tt_vector_random_value()));
for (element = 0; element < cols; element++)
gamma[element] = 1.0f;
ft_tt_vector_reference_rms_norm(x, gamma, 1e-5f, reference, rows, cols);
/* A reduce that accumulated each tile TWICE gives a mean square 2x too large, hence an
* output 1/sqrt(2) too small. That is a real mutation of the kernel's inner loop, and
* this is what it does to the answer. */
for (element = 0; element < count; element++)
scaled[element] = reference[element] * (float)(1.0 / sqrt(2.0));
for (element = 0; element < count; element++) {
if (fabs((double)reference[element]) > peak)
peak = fabs((double)reference[element]);
}
pcc = ft_tt_vector_pearson(reference, scaled, count);
worst = ft_tt_vector_max_abs_difference(reference, scaled, count);
ft_tt_test_check_fmt("a 29% scale error keeps PCC at 1.0 — the gate does not see it",
pcc >= 0.999999, "PCC %.9f", pcc);
ft_tt_test_check_fmt("and max-abs sees it at 100x the 5% budget",
worst > 0.05 * peak, "max abs %.6g against a %.6g budget", worst,
0.05 * peak);
done:
free(x);
free(gamma);
free(reference);
free(scaled);
}
/* ================================================================
* A RAGGED W, SERVED BY PADDING — and the one member it cannot serve
* ================================================================
*
* The reduce triad has no mask tile: it reduces over `tile_cols * 32` columns
* unconditionally, and a ragged W has no wire representation at all. What closes that for
* three of the four members is a caller that PADS — pad value from the member's own passes,
* DIVISOR from the real W — and what these checks are for is that the padded pipeline lands
* on the true-W reference, not merely near it.
*
* THE MODEL IS NOT TOLD HOW THE PADDING WAS DONE. It is handed the padded activation, the
* scaler and eps values UNTILIZED OUT OF the constants buffer the host built, the gamma row
* read back the same way, and the program words — i.e. only what the card would get. A model
* that recomputed 1/W itself would agree with a wrong builder and prove nothing (dev notes
* §3).
*
* AND LAYER NORM IS MEASURED, NOT ASSERTED. Its second pass squares (x - row mean), so a
* padded lane contributes (pad - mean)^2 and vanishes only at pad == the row's own mean. The
* last stage sweeps constant pads across rows with deliberately DIFFERENT means and shows
* every one of them wrong — which is why the builder refuses it instead of shipping it with
* a caveat.
*/
/** Widest padded row any stage below builds, for the fixed-size scratch the sweep uses. */
#define RAGGED_MAX_PADDED_COLS 1536u
/** Read a gamma/beta stream back out of a constants buffer, the way the card will index it:
* row 0 of each 32x32 tile, `tile_cols` tiles. Reading the BYTES rather than the caller's
* array is what makes the padded tail an observation instead of an assumption. */
static void read_broadcast_row(const unsigned char *tiles, uint32_t tile_cols, float *out)
{
uint32_t tile;
for (tile = 0; tile < tile_cols; tile++) {
uint16_t plain[FT_TT_OP_TILE_DIM * FT_TT_OP_TILE_DIM];
uint32_t column;
(void)ft_tt_untilize_strip(tiles + (size_t)tile * FT_TT_OP_TILE_BYTES_BF16,
sizeof(uint16_t), FT_TT_OP_TILE_DIM, FT_TT_OP_TILE_DIM,
FT_TT_OP_TILE_DIM * sizeof(uint16_t), plain);
for (column = 0; column < FT_TT_OP_TILE_DIM; column++)
out[tile * FT_TT_OP_TILE_DIM + column] = ft_float_from_bf16(plain[column]);
}
}
/** Test data shaped for the member: the router divides by a row sum, so it needs positive
* gates; softmax gets an ALL-NEGATIVE row, which is the arm a zero pad gets wrong twice
* over (a max clamped at 0, and a denominator with exp(0 - max) in it). */
static void fill_member_input(ft_tt_op_reduce_function function, float *out, size_t count)
{
size_t index;
for (index = 0; index < count; index++) {
const float value = ft_tt_vector_random_value();
if (function == FT_TT_OP_REDUCE_FN_ROUTER_NORMALISE)
out[index] = ft_float_from_bf16(ft_bf16_from_float(0.05f + fabsf(value)));
else if (function == FT_TT_OP_REDUCE_FN_SOFTMAX)
out[index] = ft_float_from_bf16(ft_bf16_from_float(value - 4.0f));
else
out[index] = ft_float_from_bf16(ft_bf16_from_float(value));
}
}
static void reference_for(ft_tt_op_reduce_function function, const float *x, const float *gamma,
float eps, float *out, uint32_t rows, uint32_t cols)
{
if (function == FT_TT_OP_REDUCE_FN_SOFTMAX)
ft_tt_vector_reference_softmax(x, out, rows, cols);
else if (function == FT_TT_OP_REDUCE_FN_RMS_NORM)
ft_tt_vector_reference_rms_norm(x, gamma, eps, out, rows, cols);
else
ft_tt_vector_reference_router_normalise(x, out, rows, cols);
}
/**
* One member at one W through the padding caller, scored against the true-W reference, with
* an exact-W control at the PADDED width as the rounding floor.
*
* The control is what turns the verdict into a comparison instead of a magic constant: a
* padded lane contributes the pool's identity, so padding must cost nothing beyond the bf16
* rounding the same shape already pays.
*
* @return false only if the run could not be made (allocation); the checks report themselves
*/
static bool score_padded_member(ft_tt_op_reduce_function function, uint32_t width, float eps,
unsigned seed)
{
const uint32_t tile_cols = ft_tt_op_reduce_padded_tile_cols(width);
const uint32_t padded = tile_cols * FT_TT_OP_TILE_DIM;
const uint32_t rows = 32u;
const size_t padded_count = (size_t)rows * padded;
float *x = malloc((size_t)rows * width * sizeof(float));
float *x_padded = malloc(padded_count * sizeof(float));
float *gamma = malloc(padded * sizeof(float));
float *gamma_wire = malloc(padded * sizeof(float));
float *expected = malloc(padded_count * sizeof(float));
float *modelled = malloc(padded_count * sizeof(float));
float *sliced = malloc(padded_count * sizeof(float));
unsigned char *constants = NULL;
size_t constants_bytes =
ft_tt_op_reduce_constants_bytes(function, tile_cols, FT_TT_OP_TILE_BYTES_BF16);
double ragged_worst = 0.0;
double control_worst = 0.0;
double ragged_pcc = 0.0;
uint32_t pass0 = 0u;
uint32_t pass1 = 0u;
uint32_t final_word = 0u;
float scaler = 0.0f;
float eps_tile = 0.0f;
unsigned wrong = 0u;
uint32_t row;
size_t element;
char label[128];
bool made = false;
int rc;
constants = malloc(constants_bytes);
if (!x || !x_padded || !gamma || !gamma_wire || !expected || !modelled || !sliced ||
!constants)
goto done;
ft_tt_vector_random_seed(0x5AD9E0ULL + seed);
fill_member_input(function, x, (size_t)rows * width);
for (element = 0; element < padded; element++)
gamma[element] =
ft_float_from_bf16(ft_bf16_from_float(0.5f + ft_tt_vector_random_value() * 0.25f));
/* ---- the ragged arm: everything the card sees comes from the caller ---- */
rc = ft_tt_op_reduce_pad_rows(function, x, rows, width, x_padded, padded_count);
snprintf(label, sizeof(label), "%s W=%u: the row pads to Wt=%u",
ft_tt_op_reduce_function_name(function), width, tile_cols);
ft_tt_test_check_fmt(label, rc == FT_TT_OK, "rc %d", rc);
rc = ft_tt_op_reduce_build_constants_ragged(function, width, eps, gamma, NULL,
FT_TT_OP_TILE_BYTES_BF16, constants,
constants_bytes);
snprintf(label, sizeof(label), "%s W=%u: the constants build at the real W",
ft_tt_op_reduce_function_name(function), width);
ft_tt_test_check_fmt(label, rc == FT_TT_OK, "rc %d", rc);
if (rc != FT_TT_OK)
goto done;
scaler = constant_tile_value(constants, &wrong);
eps_tile = constant_tile_value(constants + FT_TT_OP_TILE_BYTES_BF16, &wrong);
if (ft_tt_op_reduce_uses_gamma(function))
read_broadcast_row(constants + 2u * FT_TT_OP_TILE_BYTES_BF16, tile_cols, gamma_wire);
else
memset(gamma_wire, 0, padded * sizeof(float));
(void)ft_tt_op_reduce_program(function, &pass0, &pass1, &final_word);
ft_tt_vector_model_reduce_program(pass0, pass1, final_word, x_padded, gamma_wire, NULL,
scaler, eps_tile, modelled, rows, padded);
/* Only the real columns are the answer; the padded tail is scratch by construction. */
for (row = 0; row < rows; row++)
memcpy(sliced + (size_t)row * width, modelled + (size_t)row * padded,
width * sizeof(float));
reference_for(function, x, gamma, eps, expected, rows, width);
ragged_worst = ft_tt_vector_max_abs_difference(expected, sliced, (size_t)rows * width);
ragged_pcc = ft_tt_vector_pearson(expected, sliced, (size_t)rows * width);
/* ---- the control: the same shape at an exact W, which needs no padding at all ---- */
fill_member_input(function, x_padded, padded_count);
rc = ft_tt_op_reduce_build_constants(function, padded, eps, gamma, NULL,
FT_TT_OP_TILE_BYTES_BF16, constants, constants_bytes);
if (rc != FT_TT_OK) {
ft_tt_test_check_fmt("the exact-width control builds", false, "rc %d", rc);
goto done;
}
scaler = constant_tile_value(constants, &wrong);
eps_tile = constant_tile_value(constants + FT_TT_OP_TILE_BYTES_BF16, &wrong);
if (ft_tt_op_reduce_uses_gamma(function))
read_broadcast_row(constants + 2u * FT_TT_OP_TILE_BYTES_BF16, tile_cols, gamma_wire);
ft_tt_vector_model_reduce_program(pass0, pass1, final_word, x_padded, gamma_wire, NULL,
scaler, eps_tile, modelled, rows, padded);
reference_for(function, x_padded, gamma, eps, expected, rows, padded);
control_worst = ft_tt_vector_max_abs_difference(expected, modelled, padded_count);
snprintf(label, sizeof(label), "%s W=%u: padding costs no more than the bf16 floor",
ft_tt_op_reduce_function_name(function), width);
ft_tt_test_check_fmt(label,
ragged_pcc >= PCC_ACCEPT &&
ragged_worst <= 4.0 * control_worst + 1e-9,
"max abs %.6g against an exact-W floor of %.6g, PCC %.9f",
ragged_worst, control_worst, ragged_pcc);
made = true;
done:
if (!made && !constants)
ft_tt_test_check("allocation", false, "out of memory");
free(x);
free(x_padded);
free(gamma);
free(gamma_wire);
free(expected);
free(modelled);
free(sliced);
free(constants);
return made;
}
/** The emulator against the four models it has to agree with, at an exact W. A model driven
* by the program words is only a fair instrument if it reproduces the hand-written ones
* where both apply — and it has to be BIT-exact, because both apply the same rounding at
* the same places and anything else would be an unexplained difference. */
static void test_program_model_matches_the_member_models(void)
{
const uint32_t rows = 32u;
const uint32_t cols = 1536u;
const uint32_t tile_cols = cols / FT_TT_OP_TILE_DIM;
const size_t count = (size_t)rows * cols;
const float eps = 1e-5f;
float *x = malloc(count * sizeof(float));
float *gamma = malloc(cols * sizeof(float));
float *beta = malloc(cols * sizeof(float));
float *from_member = malloc(count * sizeof(float));
float *from_program = malloc(count * sizeof(float));
const float scaler_mean = ft_float_from_bf16(ft_bf16_from_float(1.0f / (float)cols));
const float eps_tile = ft_float_from_bf16(
ft_bf16_from_float(eps * (float)cols / (float)FT_TT_OP_TILE_DIM));
uint32_t pass0 = 0u;
uint32_t pass1 = 0u;
uint32_t final_word = 0u;
size_t element;
(void)tile_cols;
ft_tt_test_step("the program-driven model reproduces the four member models exactly");
if (!x || !gamma || !beta || !from_member || !from_program) {
ft_tt_test_check("allocation", false, "out of memory");
goto done;
}
ft_tt_vector_random_seed(0x9C0DEFULL);
for (element = 0; element < count; element++)
x[element] = ft_float_from_bf16(ft_bf16_from_float(ft_tt_vector_random_value()));
for (element = 0; element < cols; element++) {
gamma[element] =
ft_float_from_bf16(ft_bf16_from_float(0.5f + ft_tt_vector_random_value() * 0.25f));
beta[element] = ft_float_from_bf16(ft_bf16_from_float(ft_tt_vector_random_value() * 0.1f));
}
ft_tt_vector_model_rms_norm(x, gamma, eps, from_member, rows, cols);
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_RMS_NORM, &pass0, &pass1, &final_word);
ft_tt_vector_model_reduce_program(pass0, pass1, final_word, x, gamma, beta, scaler_mean,
eps_tile, from_program, rows, cols);
ft_tt_test_check_fmt("RMS norm", ft_tt_vector_max_abs_difference(from_member, from_program,
count) == 0.0,
"max abs %.6g",
ft_tt_vector_max_abs_difference(from_member, from_program, count));
ft_tt_vector_model_layer_norm(x, gamma, beta, eps, from_member, rows, cols);
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_LAYER_NORM, &pass0, &pass1, &final_word);
ft_tt_vector_model_reduce_program(pass0, pass1, final_word, x, gamma, beta, scaler_mean,
eps_tile, from_program, rows, cols);
ft_tt_test_check_fmt("layer norm", ft_tt_vector_max_abs_difference(from_member, from_program,
count) == 0.0,
"max abs %.6g",
ft_tt_vector_max_abs_difference(from_member, from_program, count));
ft_tt_vector_model_softmax(x, from_member, rows, cols);
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_SOFTMAX, &pass0, &pass1, &final_word);
ft_tt_vector_model_reduce_program(pass0, pass1, final_word, x, gamma, beta, 1.0f, 0.0f,
from_program, rows, cols);
ft_tt_test_check_fmt("softmax",
ft_tt_vector_max_abs_difference(from_member, from_program, count) == 0.0,
"max abs %.6g",
ft_tt_vector_max_abs_difference(from_member, from_program, count));
for (element = 0; element < count; element++)
x[element] = ft_float_from_bf16(ft_bf16_from_float(0.05f + fabsf(x[element])));
ft_tt_vector_model_router_normalise(x, from_member, rows, cols);
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_ROUTER_NORMALISE, &pass0, &pass1,
&final_word);
ft_tt_vector_model_reduce_program(pass0, pass1, final_word, x, gamma, beta, 1.0f, 0.0f,
from_program, rows, cols);
ft_tt_test_check_fmt("router normalise",
ft_tt_vector_max_abs_difference(from_member, from_program, count) == 0.0,
"max abs %.6g",
ft_tt_vector_max_abs_difference(from_member, from_program, count));
done:
free(x);
free(gamma);
free(beta);
free(from_member);
free(from_program);
}
/** The derivation itself: which member takes which pad, and what ceil(W/32) is. */
static void test_ragged_padding_contract(void)
{
float value = 0.0f;
int rc;
ft_tt_test_step("a ragged W: the pad value each member's own passes ask for");
ft_tt_test_check_fmt("Wt is ceil(W/32)",
ft_tt_op_reduce_padded_tile_cols(1500u) == 47u &&
ft_tt_op_reduce_padded_tile_cols(1536u) == 48u &&
ft_tt_op_reduce_padded_tile_cols(1u) == 1u &&
ft_tt_op_reduce_padded_tile_cols(0u) == 0u,
"1500 -> %u, 1536 -> %u", ft_tt_op_reduce_padded_tile_cols(1500u),
ft_tt_op_reduce_padded_tile_cols(1536u));
/* Asserted as the PROPERTY the pad has to have — far below any activation, and finite so
* the subtraction cannot overflow — rather than against the macro, which would make the
* check agree with whatever the macro says (dev notes §3). */
rc = ft_tt_op_reduce_pad_value(FT_TT_OP_REDUCE_FN_SOFTMAX, &value);
ft_tt_test_check_fmt("softmax pads far below any activation, not with 0 — its sum would "
"pick up exp(0 - max) per pad lane",
rc == FT_TT_OK && value <= -1.0e20f && value > -HUGE_VALF, "rc %d, %g",
rc, (double)value);
rc = ft_tt_op_reduce_pad_value(FT_TT_OP_REDUCE_FN_RMS_NORM, &value);
ft_tt_test_check_fmt("RMS norm pads with 0 — a zero lane squares to zero",
rc == FT_TT_OK && value == 0.0f, "rc %d, %g", rc, (double)value);
rc = ft_tt_op_reduce_pad_value(FT_TT_OP_REDUCE_FN_ROUTER_NORMALISE, &value);
ft_tt_test_check_fmt("the router pads with 0 — a zero lane adds nothing to the row sum",
rc == FT_TT_OK && value == 0.0f, "rc %d, %g", rc, (double)value);
rc = ft_tt_op_reduce_pad_value(FT_TT_OP_REDUCE_FN_LAYER_NORM, &value);
ft_tt_test_check_fmt("layer norm has NO constant pad value, and says so",
rc == FT_TT_EINVAL &&
!ft_tt_op_reduce_padding_is_exact(FT_TT_OP_REDUCE_FN_LAYER_NORM),
"rc %d", rc);
ft_tt_test_check("the other three are exact under padding",
ft_tt_op_reduce_padding_is_exact(FT_TT_OP_REDUCE_FN_SOFTMAX) &&
ft_tt_op_reduce_padding_is_exact(FT_TT_OP_REDUCE_FN_RMS_NORM) &&
ft_tt_op_reduce_padding_is_exact(FT_TT_OP_REDUCE_FN_ROUTER_NORMALISE),
NULL);
{
/* Six tiles: scaler, eps, and TWO tiles each of gamma and beta at Wt = 2. Sizing it
* to what layer norm actually asks for is what keeps the refusals below about the
* ragged W rather than about a short buffer — two grounds for one failure is a check
* that tests whichever is cheaper (dev notes §3). */
unsigned char scratch[6u * FT_TT_OP_TILE_BYTES_BF16];
static float gamma[64];
unsigned index;
for (index = 0; index < 64u; index++)
gamma[index] = 1.0f;
rc = ft_tt_op_reduce_build_constants_ragged(FT_TT_OP_REDUCE_FN_LAYER_NORM, 33u, 1e-5f,
gamma, gamma, FT_TT_OP_TILE_BYTES_BF16,
scratch, sizeof(scratch));
ft_tt_test_check_fmt("a RAGGED layer norm is refused rather than served wrong",
rc == FT_TT_EINVAL, "rc %d", rc);
rc = ft_tt_op_reduce_build_constants_ragged(FT_TT_OP_REDUCE_FN_LAYER_NORM, 64u, 1e-5f,
gamma, gamma, FT_TT_OP_TILE_BYTES_BF16,
scratch, sizeof(scratch));
ft_tt_test_check_fmt("an EXACT layer norm still builds — the refusal is about "
"raggedness, not the member",
rc == FT_TT_OK, "rc %d", rc);
}
}
/** The divisor, checked as bytes: the scaler and eps tiles must carry the REAL W. This is
* the mutation PCC cannot see, so it is asserted directly and not only through a score. */
static void test_ragged_divisor_is_the_real_width(void)
{
const uint32_t width = 1057u;
const uint32_t tile_cols = ft_tt_op_reduce_padded_tile_cols(width);
const uint32_t padded = tile_cols * FT_TT_OP_TILE_DIM;
const float eps = 1e-5f;
const float want_scaler = ft_float_from_bf16(ft_bf16_from_float(1.0f / (float)width));
const float padded_scaler = ft_float_from_bf16(ft_bf16_from_float(1.0f / (float)padded));
const float want_eps =
ft_float_from_bf16(ft_bf16_from_float(eps * (float)width / (float)FT_TT_OP_TILE_DIM));
const float padded_eps = ft_float_from_bf16(
ft_bf16_from_float(eps * (float)padded / (float)FT_TT_OP_TILE_DIM));
size_t bytes = ft_tt_op_reduce_constants_bytes(FT_TT_OP_REDUCE_FN_RMS_NORM, tile_cols,
FT_TT_OP_TILE_BYTES_BF16);
unsigned char *constants = malloc(bytes);
float *gamma = malloc(width * sizeof(float));
unsigned wrong = 0u;
uint32_t index;
int rc;
ft_tt_test_step("a ragged W: the reduce divisor stays the REAL W");
if (!constants || !gamma) {
ft_tt_test_check("allocation", false, "out of memory");
goto done;
}
for (index = 0; index < width; index++)
gamma[index] = 1.0f;
/* Non-vacuity FIRST: at this W the two candidate divisors are different bf16 values, so
* the checks below can tell them apart. At a W where they round together they could
* not, and a green would mean nothing. */
ft_tt_test_check_fmt("1/W and 1/padded-W are distinct bf16 values at this W",
want_scaler != padded_scaler && want_eps != padded_eps,
"%g vs %g", (double)want_scaler, (double)padded_scaler);
rc = ft_tt_op_reduce_build_constants_ragged(FT_TT_OP_REDUCE_FN_RMS_NORM, width, eps, gamma,
NULL, FT_TT_OP_TILE_BYTES_BF16, constants,
bytes);
ft_tt_test_check_fmt("it builds at W=1057 into Wt=34", rc == FT_TT_OK && tile_cols == 34u,
"rc %d, Wt %u", rc, tile_cols);
if (rc != FT_TT_OK)
goto done;
ft_tt_test_check_fmt("the scaler tile is 1/1057, not 1/1088",
constant_tile_value(constants, &wrong) == want_scaler && wrong == 0u,
"%g", (double)constant_tile_value(constants, &wrong));
ft_tt_test_check_fmt("the eps tile is eps*1057/32, not eps*1088/32",
constant_tile_value(constants + FT_TT_OP_TILE_BYTES_BF16, &wrong) ==
want_eps &&
wrong == 0u,
"%g",
(double)constant_tile_value(constants + FT_TT_OP_TILE_BYTES_BF16,
&wrong));
/* The gamma tail is the other thing a padded width invites: reading 31 floats past the
* caller's array. It has to be a written zero, not whatever was next in memory. */
{
float *wire = malloc(padded * sizeof(float));
unsigned bad = 0u;
if (wire) {
read_broadcast_row(constants + 2u * FT_TT_OP_TILE_BYTES_BF16, tile_cols, wire);
for (index = 0; index < padded; index++) {
const float want = (index < width) ? 1.0f : 0.0f;
if (wire[index] != want)
bad++;
}
ft_tt_test_check_fmt("gamma's padded tail is a written zero, not read past the "
"caller's array",
bad == 0u, "%u of %u columns wrong", bad, padded);
free(wire);
} else {
ft_tt_test_check("allocation", false, "out of memory");
}
}
done:
free(constants);
free(gamma);
}
/** The three paddable members, end to end, at three ragged widths. */
static void test_ragged_padded_pipeline(void)
{
static const uint32_t widths[] = { 33u, 1057u, 1500u };
static const ft_tt_op_reduce_function members[] = { FT_TT_OP_REDUCE_FN_SOFTMAX,
FT_TT_OP_REDUCE_FN_RMS_NORM,
FT_TT_OP_REDUCE_FN_ROUTER_NORMALISE };
unsigned member;
unsigned index;
ft_tt_test_step("a ragged W: the padded pipeline against the true-W reference");
for (member = 0; member < sizeof(members) / sizeof(members[0]); member++) {
for (index = 0; index < sizeof(widths) / sizeof(widths[0]); index++)
(void)score_padded_member(members[member], widths[index], 1e-5f,
member * 8u + index);
}
}
/**
* WHY LAYER NORM IS REFUSED, MEASURED.
*
* Its variance pass reduces (x - row mean)^2, so a padded lane contributes (pad - mean)^2 —
* zero only where the pad equals THAT ROW's mean. The rows here are given deliberately
* different means (row r is offset by r), which is the input that makes the claim
* discriminating: on zero-centred data the same error is ~1e-5 relative and would let a
* broken padding through, and that is exactly the "vacuous because the input never
* exercises it" trap in dev notes §3. Both regimes are reported.
*/
static void test_layer_norm_cannot_be_padded(void)
{
static const float pads[] = { 0.0f, 8.0f, 16.0f, 31.0f, -1.0e30f };
const uint32_t width = 1057u;
const uint32_t tile_cols = ft_tt_op_reduce_padded_tile_cols(width);
const uint32_t padded = tile_cols * FT_TT_OP_TILE_DIM;
const uint32_t rows = 32u;
const float eps = 1e-5f;
const float scaler = ft_float_from_bf16(ft_bf16_from_float(1.0f / (float)width));
const float eps_tile =
ft_float_from_bf16(ft_bf16_from_float(eps * (float)width / (float)FT_TT_OP_TILE_DIM));
float *x = malloc((size_t)rows * width * sizeof(float));
float *x_padded = malloc((size_t)rows * padded * sizeof(float));
float *gamma = malloc(padded * sizeof(float));
float *beta = malloc(padded * sizeof(float));
float *expected = malloc((size_t)rows * width * sizeof(float));
float *modelled = malloc((size_t)rows * padded * sizeof(float));
/* padded, not width: the exact-W control at the end scores a whole padded row through
* this same buffer. */
float *sliced = malloc((size_t)rows * padded * sizeof(float));
uint32_t pass0 = 0u;
uint32_t pass1 = 0u;
uint32_t final_word = 0u;
double best = 0.0;
double floor_worst = 0.0;
double broken = 0.0;
unsigned failures_seen = 0u;
unsigned arm;
uint32_t row;
uint32_t column;
ft_tt_test_step("layer norm under padding: measured wrong for EVERY constant pad");
if (!x || !x_padded || !gamma || !beta || !expected || !modelled || !sliced) {
ft_tt_test_check("allocation", false, "out of memory");
goto done;
}
ft_tt_vector_random_seed(0x1A4E70ULL);
for (column = 0; column < padded; column++) {
gamma[column] = 1.0f;
beta[column] = 0.0f;
}
(void)ft_tt_op_reduce_program(FT_TT_OP_REDUCE_FN_LAYER_NORM, &pass0, &pass1, &final_word);
/* THE FLOOR FIRST, AND IT IS NOT A GUESS. The same member, the same generator, the same
* model, at an EXACT W where no padding happens at all — so the bar every arm below has
* to clear is four times what this arrangement's bf16 rounding already costs, rather
* than a constant somebody picked. On this deliberately offset data the floor is large
* (the CENTER step subtracts two numbers near 31 in bf16), which is exactly why a fixed
* threshold would have been wrong. */
for (row = 0; row < rows; row++) {
for (column = 0; column < padded; column++)
x_padded[(size_t)row * padded + column] = ft_float_from_bf16(
ft_bf16_from_float((float)row + ft_tt_vector_random_value()));
}
ft_tt_vector_reference_layer_norm(x_padded, gamma, beta, eps, modelled, rows, padded);
ft_tt_vector_model_reduce_program(
pass0, pass1, final_word, x_padded, gamma, beta,
ft_float_from_bf16(ft_bf16_from_float(1.0f / (float)padded)),
ft_float_from_bf16(ft_bf16_from_float(eps * (float)padded / (float)FT_TT_OP_TILE_DIM)),
sliced, rows, padded);
floor_worst = ft_tt_vector_max_abs_difference(modelled, sliced, (size_t)rows * padded);
broken = 4.0 * floor_worst;
ft_tt_test_check_fmt("CONTROL: at an EXACT W the same layer norm needs no padding and "
"lands on the reference — this is the floor the arms below clear",
floor_worst > 0.0 && floor_worst < 0.25, "max abs %.6g, so the bar "
"is %.6g", floor_worst, broken);
for (column = 0; column < padded; column++)
gamma[column] = (column < width) ? 1.0f : 0.0f;
/* Row r is centred on r, so no single constant can sit near every row's mean. */
for (row = 0; row < rows; row++) {
for (column = 0; column < width; column++)
x[(size_t)row * width + column] = ft_float_from_bf16(
ft_bf16_from_float((float)row + ft_tt_vector_random_value()));
}
ft_tt_vector_reference_layer_norm(x, gamma, beta, eps, expected, rows, width);
for (arm = 0; arm < sizeof(pads) / sizeof(pads[0]); arm++) {
double worst;
for (row = 0; row < rows; row++) {
for (column = 0; column < padded; column++)
x_padded[(size_t)row * padded + column] =
(column < width) ? x[(size_t)row * width + column] : pads[arm];
}
ft_tt_vector_model_reduce_program(pass0, pass1, final_word, x_padded, gamma, beta,
scaler, eps_tile, modelled, rows, padded);
for (row = 0; row < rows; row++)
memcpy(sliced + (size_t)row * width, modelled + (size_t)row * padded,
width * sizeof(float));
worst = ft_tt_vector_max_abs_difference(expected, sliced, (size_t)rows * width);
if (arm == 0u || worst < best)
best = worst;
if (worst > broken)
failures_seen++;
ft_tt_test_check_fmt("a constant pad does not save layer norm", worst > broken,
"pad %g: max abs %.6g against a floor of %.6g", (double)pads[arm],
worst, floor_worst);
}
ft_tt_test_check_fmt("the BEST constant pad is still wrong",
failures_seen == sizeof(pads) / sizeof(pads[0]) && best > broken,
"best of %u pads: max abs %.6g, %.1fx the floor", failures_seen, best,
best / floor_worst);
/* AND A PER-ROW PAD DOES NOT RESCUE IT EITHER, which is the stronger form of the finding
* and was not obvious until it was run. The row's own mean makes pass 1's (pad - mean)^2
* vanish — and CORRUPTS pass 0, which is a plain SUM over the padded row with a 1/W_true
* scaler, so the "mean" it produces is m*(padded/W). The two passes want different
* padding of the SAME buffer. Nothing a caller writes into the input satisfies both. */
{
double worst;
for (row = 0; row < rows; row++) {
double mean = 0.0;
for (column = 0; column < width; column++)
mean += (double)x[(size_t)row * width + column];
mean /= (double)width;
for (column = 0; column < padded; column++)
x_padded[(size_t)row * padded + column] =
(column < width) ? x[(size_t)row * width + column] : (float)mean;
}
ft_tt_vector_model_reduce_program(pass0, pass1, final_word, x_padded, gamma, beta,
scaler, eps_tile, modelled, rows, padded);
for (row = 0; row < rows; row++)
memcpy(sliced + (size_t)row * width, modelled + (size_t)row * padded,
width * sizeof(float));
worst = ft_tt_vector_max_abs_difference(expected, sliced, (size_t)rows * width);
ft_tt_test_check_fmt("nor does a PER-ROW pad — pass 0 wants 0 and pass 1 wants the "
"row mean, and there is one buffer",
worst > broken, "row-mean pad: max abs %.6g, %.1fx the floor",
worst, worst / floor_worst);
}
/* The honest nuance, reported rather than asserted: on a zero-centred row the same hole
* is invisible, which is why "it scored fine on our data" is not evidence here. */
for (row = 0; row < rows; row++) {
for (column = 0; column < width; column++)
x[(size_t)row * width + column] =
ft_float_from_bf16(ft_bf16_from_float(ft_tt_vector_random_value()));
for (column = 0; column < padded; column++)
x_padded[(size_t)row * padded + column] =
(column < width) ? x[(size_t)row * width + column] : 0.0f;
}
ft_tt_vector_reference_layer_norm(x, gamma, beta, eps, expected, rows, width);
ft_tt_vector_model_reduce_program(pass0, pass1, final_word, x_padded, gamma, beta, scaler,
eps_tile, modelled, rows, padded);
for (row = 0; row < rows; row++)
memcpy(sliced + (size_t)row * width, modelled + (size_t)row * padded,
width * sizeof(float));
ft_tt_test_check_fmt("REPORTED, not a gate: on zero-centred rows the same hole hides",
true, "zero pad, zero-mean data: max abs %.6g",
ft_tt_vector_max_abs_difference(expected, sliced, (size_t)rows * width));
done:
free(x);
free(x_padded);
free(gamma);
free(beta);
free(expected);
free(modelled);
free(sliced);
}
/* ================================================================ */
int main(void)
{
ft_tt_test_step("Phase 6 vector ops — OFF-HARDWARE gate (no card touched)");
test_wire_constants_agree();
test_arity();
test_block_depth();
test_eltwise_parameters();
test_reduce_programs();
test_reduce_parameters();
test_eltwise_placement();
test_reduce_placement();
test_reduce_constants();
test_reduce_constants_float32();
test_eps_tile_follows_the_scaler();
test_l2_norm_against_the_oracle();
test_float32_reduce_at_the_head_shape();
test_the_three_walls_priced_apart();
test_gated_is_bound_by_the_bf16_bridge();
test_eltwise_model();
test_softmax_model();
test_reduce_models();
test_pcc_is_blind_to_scale();
test_softmax_dynamic_range();
test_softmax_max_is_over_the_whole_row();
test_program_model_matches_the_member_models();
test_ragged_padding_contract();
test_ragged_divisor_is_the_real_width();
test_ragged_padded_pipeline();
test_layer_norm_cannot_be_padded();
return ft_tt_test_finish();
}