Download code/hamer/kernels/addln/compute.cpp from changh95/hamer-p150: direct link, hf CLI and curl.
- Browser
- Download file 13.7 kB
-
https://huggingface.co/changh95/hamer-p150/resolve/main/code/hamer/kernels/addln/compute.cpp
- Command line
-
hf download hf://changh95/hamer-p150/code/hamer/kernels/addln/compute.cpp
-
curl -L -o compute.cpp https://huggingface.co/changh95/hamer-p150/resolve/main/code/hamer/kernels/addln/compute.cpp
13.7 kB
| // SPDX-FileCopyrightText: © 2026 Tenstorrent Inc. | |
| // SPDX-License-Identifier: Apache-2.0 | |
| // Fused residual add + LayerNorm over a block-sharded [32*NY, 32*NT*NX] stream, one tile row per core | |
| // (block_h = 1, NT <= 4 so every pass is ONE DST acquire with fp32 accumulation): | |
| // s = x (+ y) -> c_s (the new residual stream shard, HAS_Y only) | |
| // p1 = transpose(rowsum(s)) -> c_p1: this core's per-token partial sums as a ROW vector | |
| // (the writer sends that 128-byte row to row `col` of a 1-tile gather buffer on each row peer) | |
| // mean = transpose(colsum(G1)) / W (column vector, per token) | |
| // d = s - mean -> c_xmm (fp32) | |
| // p2 = transpose(rowsum(d*d)) -> c_p2, gathered the same way | |
| // rstd = rsqrt(transpose(colsum(G2)) / W + eps) | |
| // out = (d * rstd) * gamma + beta -> c_out (gamma / beta are full 32-row tiles; dest reuse) | |
| // Round 2's version of this kernel set hung chip 7: the writer (NOC_1) got an unswapped multicast | |
| // rectangle. This version has no multicast at all (two 64-byte unicast writes per peer and round). | |
| // compile-time: NT, NX, inv_w bits, eps bits | |
| // round 9 (ADDLN_SFPU_C): the per-token statistics are a COLUMN vector after transpose_dest (column 0 = faces 0, 2), so | |
| // their SFPU scalings / rsqrt only need VectorMode::C (half the tile); the other faces are never read | |
| template <uint32_t NT> | |
| FORCE_INLINE void row_partial(uint32_t c_src, uint32_t c_scal, uint32_t c_dst) { | |
| // REDUCE_ROW SUM swaps operands (scaler -> SrcA, data -> SrcB): reconfig(scaler, data) | |
| reconfig_data_format(c_scal, c_src); | |
| pack_reconfig_data_format(c_dst); | |
| reduce_init<PoolType::SUM, ReduceDim::REDUCE_ROW>(c_src, c_scal, c_dst); | |
| cb_reserve_back(c_dst, 1); | |
| tile_regs_acquire(); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| reduce_tile<PoolType::SUM, ReduceDim::REDUCE_ROW>(c_src, c_scal, i, 0, 0); | |
| } | |
| reduce_uninit(); | |
| transpose_dest_init<true, true>(); | |
| transpose_dest<true, true>(0); | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| pack_tile(0, c_dst); | |
| tile_regs_release(); | |
| cb_push_back(c_dst, 1); | |
| } | |
| // column vector (per token) of: colsum(G) * inv_w [+ eps -> rsqrt] | |
| template <bool RSTD> | |
| FORCE_INLINE void combine(uint32_t c_g, uint32_t c_scal, uint32_t c_dst, uint32_t inv_w, uint32_t eps) { | |
| cb_wait_front(c_g, 1); | |
| reconfig_data_format(c_g, c_scal); | |
| pack_reconfig_data_format(c_dst); | |
| reduce_init<PoolType::SUM, ReduceDim::REDUCE_COL>(c_g, c_scal, c_dst); | |
| cb_reserve_back(c_dst, 1); | |
| tile_regs_acquire(); | |
| reduce_tile<PoolType::SUM, ReduceDim::REDUCE_COL>(c_g, c_scal, 0, 0, 0); | |
| reduce_uninit(); | |
| transpose_dest_init<true, true>(); | |
| transpose_dest<true, true>(0); | |
| binop_with_scalar_tile_init(); | |
| COL_MUL(0, inv_w); | |
| if constexpr (RSTD) { | |
| COL_ADD(0, eps); | |
| rsqrt_tile_init(); | |
| COL_RSQRT(0); | |
| } | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| pack_tile(0, c_dst); | |
| tile_regs_release(); | |
| cb_push_back(c_dst, 1); | |
| cb_pop_front(c_g, 1); | |
| } | |
| ADDLN_KERNEL_MAIN { | |
| constexpr uint32_t NT = get_compile_time_arg_val(ADDLN_CT0 + 0); | |
| constexpr uint32_t NX = get_compile_time_arg_val(ADDLN_CT0 + 1); | |
| constexpr uint32_t INV_W_BITS = get_compile_time_arg_val(ADDLN_CT0 + 2); | |
| constexpr uint32_t EPS_BITS = get_compile_time_arg_val(ADDLN_CT0 + 3); | |
| static_assert(NT <= 4, "one fp32 DST half per pass"); | |
| constexpr uint32_t c_x = ADDLN_C_X, c_y = ADDLN_C_Y, c_scal = ADDLN_C_SCAL, c_gam = ADDLN_C_GAM, c_bet = ADDLN_C_BET; | |
| constexpr uint32_t c_g1 = ADDLN_C_G1, c_g2 = ADDLN_C_G2; | |
| constexpr uint32_t c_s = ADDLN_C_S, c_out = ADDLN_C_OUT; | |
| constexpr uint32_t c_p1 = ADDLN_C_P1, c_mean = 25, c_xmm = 26, c_sq = 27, c_p2 = ADDLN_C_P2, c_rstd = 29; | |
| constexpr uint32_t c_in = c_s; | |
| reconfig_data_format(c_x, c_y); | |
| pack_reconfig_data_format(c_s); | |
| compute_kernel_hw_startup(c_x, c_y, c_s); | |
| {ZONE("A-add"); | |
| cb_wait_front(c_x, NT); | |
| cb_wait_front(c_y, NT); | |
| add_init(c_x, c_y); | |
| cb_reserve_back(c_s, NT); | |
| tile_regs_acquire(); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| add_tiles(c_x, c_y, i, i, i); | |
| } | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| pack_tile(i, c_s); | |
| } | |
| tile_regs_release(); | |
| cb_push_back(c_s, NT); | |
| cb_wait_front(c_s, NT); | |
| } | |
| constexpr uint32_t c_in = c_x; | |
| compute_kernel_hw_startup(c_scal, c_x, c_p1); | |
| cb_wait_front(c_x, NT); | |
| cb_wait_front(c_scal, 1); | |
| // round 6: ONE gather round -- the per-token partials of s and s^2 travel together, var = E[s^2] - mean^2 | |
| // (mean^2 / var <= 2.2 on the real stream, so the fp32 cancellation is harmless) | |
| constexpr uint32_t c_es2 = 30, c_msq = 31; | |
| {ZONE("B-sq"); | |
| reconfig_data_format(c_in, c_in); | |
| pack_reconfig_data_format(c_sq); | |
| mul_init(c_in, c_in); | |
| cb_reserve_back(c_sq, NT); | |
| tile_regs_acquire(); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| mul_tiles(c_in, c_in, i, i, i); | |
| } | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| pack_tile(i, c_sq); | |
| } | |
| tile_regs_release(); | |
| cb_push_back(c_sq, NT); | |
| cb_wait_front(c_sq, NT); | |
| } | |
| {ZONE("B-p1"); row_partial<NT>(c_in, c_scal, c_p1);} | |
| // round 9: the unpacker no longer waits for the s^2 pack before the sum partial (it reads c_in only) | |
| cb_wait_front(c_sq, NT); | |
| {ZONE("F-p2"); row_partial<NT>(c_sq, c_scal, c_p2);} | |
| cb_pop_front(c_sq, NT); | |
| {ZONE("C-g1wait"); cb_wait_front(c_g1, 1);} | |
| {ZONE("D-mean"); combine<false>(c_g1, c_scal, c_mean, INV_W_BITS, EPS_BITS);} | |
| {ZONE("G-g2wait"); cb_wait_front(c_g2, 1);} | |
| {ZONE("H-es2"); combine<false>(c_g2, c_scal, c_es2, INV_W_BITS, EPS_BITS);} | |
| // round 9: mean^2 after the E[s^2] combine (its mean round trip hidden) and d = s - mean between mean^2 and | |
| // rstd (hides the mean^2 round trip); only the rstd -> output round trip stays exposed | |
| {ZONE("H-msq"); | |
| // mean^2 | |
| cb_wait_front(c_mean, 1); | |
| reconfig_data_format(c_mean, c_mean); | |
| pack_reconfig_data_format(c_msq); | |
| mul_init(c_mean, c_mean); | |
| cb_reserve_back(c_msq, 1); | |
| tile_regs_acquire(); | |
| mul_tiles(c_mean, c_mean, 0, 0, 0); | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| pack_tile(0, c_msq); | |
| tile_regs_release(); | |
| cb_push_back(c_msq, 1); | |
| } | |
| {ZONE("E-d"); | |
| // d = s - mean | |
| reconfig_data_format(c_in, c_mean); | |
| pack_reconfig_data_format(c_xmm); | |
| sub_bcast_cols_init(c_in, c_mean); | |
| cb_reserve_back(c_xmm, NT); | |
| tile_regs_acquire(); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| sub_tiles_bcast_cols(c_in, c_mean, i, 0, i); | |
| } | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| pack_tile(i, c_xmm); | |
| } | |
| tile_regs_release(); | |
| cb_push_back(c_xmm, NT); | |
| cb_pop_front(c_mean, 1); | |
| } | |
| {ZONE("H-rstd"); | |
| // rstd = rsqrt(E[s^2] - mean^2 + eps) | |
| cb_wait_front(c_es2, 1); | |
| cb_wait_front(c_msq, 1); | |
| reconfig_data_format(c_es2, c_msq); | |
| pack_reconfig_data_format(c_rstd); | |
| sub_init(c_es2, c_msq); | |
| cb_reserve_back(c_rstd, 1); | |
| tile_regs_acquire(); | |
| sub_tiles(c_es2, c_msq, 0, 0, 0); | |
| binop_with_scalar_tile_init(); | |
| COL_ADD(0, EPS_BITS); | |
| rsqrt_tile_init(); | |
| COL_RSQRT(0); | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| pack_tile(0, c_rstd); | |
| tile_regs_release(); | |
| cb_push_back(c_rstd, 1); | |
| cb_pop_front(c_es2, 1); | |
| cb_pop_front(c_msq, 1); | |
| } | |
| cb_wait_front(c_xmm, NT); | |
| {ZONE("H-rstd"); | |
| // mean^2 | |
| cb_wait_front(c_mean, 1); | |
| reconfig_data_format(c_mean, c_mean); | |
| pack_reconfig_data_format(c_msq); | |
| mul_init(c_mean, c_mean); | |
| cb_reserve_back(c_msq, 1); | |
| tile_regs_acquire(); | |
| mul_tiles(c_mean, c_mean, 0, 0, 0); | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| pack_tile(0, c_msq); | |
| tile_regs_release(); | |
| cb_push_back(c_msq, 1); | |
| // rstd = rsqrt(E[s^2] - mean^2 + eps) | |
| cb_wait_front(c_es2, 1); | |
| cb_wait_front(c_msq, 1); | |
| reconfig_data_format(c_es2, c_msq); | |
| pack_reconfig_data_format(c_rstd); | |
| sub_init(c_es2, c_msq); | |
| cb_reserve_back(c_rstd, 1); | |
| tile_regs_acquire(); | |
| sub_tiles(c_es2, c_msq, 0, 0, 0); | |
| binop_with_scalar_tile_init(); | |
| COL_ADD(0, EPS_BITS); | |
| rsqrt_tile_init(); | |
| COL_RSQRT(0); | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| pack_tile(0, c_rstd); | |
| tile_regs_release(); | |
| cb_push_back(c_rstd, 1); | |
| cb_pop_front(c_es2, 1); | |
| cb_pop_front(c_msq, 1); | |
| } | |
| {ZONE("E-d"); | |
| // d = s - mean | |
| reconfig_data_format(c_in, c_mean); | |
| pack_reconfig_data_format(c_xmm); | |
| sub_bcast_cols_init(c_in, c_mean); | |
| cb_reserve_back(c_xmm, NT); | |
| tile_regs_acquire(); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| sub_tiles_bcast_cols(c_in, c_mean, i, 0, i); | |
| } | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| pack_tile(i, c_xmm); | |
| } | |
| tile_regs_release(); | |
| cb_push_back(c_xmm, NT); | |
| cb_pop_front(c_mean, 1); | |
| cb_wait_front(c_xmm, NT); | |
| } | |
| {ZONE("B-p1"); row_partial<NT>(c_in, c_scal, c_p1);} | |
| {ZONE("C-g1wait"); cb_wait_front(c_g1, 1);} | |
| {ZONE("D-mean"); combine<false>(c_g1, c_scal, c_mean, INV_W_BITS, EPS_BITS);} | |
| {ZONE("E-d-sq"); | |
| // d = s - mean | |
| cb_wait_front(c_mean, 1); | |
| reconfig_data_format(c_in, c_mean); | |
| pack_reconfig_data_format(c_xmm); | |
| sub_bcast_cols_init(c_in, c_mean); | |
| cb_reserve_back(c_xmm, NT); | |
| tile_regs_acquire(); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| sub_tiles_bcast_cols(c_in, c_mean, i, 0, i); | |
| } | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| pack_tile(i, c_xmm); | |
| } | |
| tile_regs_release(); | |
| cb_push_back(c_xmm, NT); | |
| cb_pop_front(c_mean, 1); | |
| // d*d | |
| cb_wait_front(c_xmm, NT); | |
| reconfig_data_format(c_xmm, c_xmm); | |
| pack_reconfig_data_format(c_sq); | |
| mul_init(c_xmm, c_xmm); | |
| cb_reserve_back(c_sq, NT); | |
| tile_regs_acquire(); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| mul_tiles(c_xmm, c_xmm, i, i, i); | |
| } | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| pack_tile(i, c_sq); | |
| } | |
| tile_regs_release(); | |
| cb_push_back(c_sq, NT); | |
| cb_wait_front(c_sq, NT); | |
| } | |
| {ZONE("F-p2"); row_partial<NT>(c_sq, c_scal, c_p2);} | |
| cb_pop_front(c_sq, NT); | |
| {ZONE("G-g2wait"); cb_wait_front(c_g2, 1);} | |
| {ZONE("H-rstd"); combine<true>(c_g2, c_scal, c_rstd, INV_W_BITS, EPS_BITS);} | |
| {ZONE("I-out"); | |
| // out = d * rstd * gamma + beta (ADDLN_NOAFF: out = d * rstd, the affine is folded into the next matmul) | |
| cb_wait_front(c_rstd, 1); | |
| cb_wait_front(c_gam, NT); | |
| cb_wait_front(c_bet, NT); | |
| reconfig_data_format(c_xmm, c_rstd); | |
| pack_reconfig_data_format(c_out); | |
| mul_bcast_cols_init(c_xmm, c_rstd); | |
| cb_reserve_back(c_out, NT); | |
| tile_regs_acquire(); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| mul_tiles_bcast_cols(c_xmm, c_rstd, i, 0, i); | |
| } | |
| reconfig_data_format_srcb(c_rstd, c_gam); | |
| mul_reuse_dest_init<EltwiseBinaryReuseDestType::DEST_TO_SRCA>(c_gam); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| mul_reuse_dest_tiles<EltwiseBinaryReuseDestType::DEST_TO_SRCA>(c_gam, i, i); | |
| } | |
| reconfig_data_format_srcb(c_gam, c_bet); | |
| add_reuse_dest_init<EltwiseBinaryReuseDestType::DEST_TO_SRCA>(c_bet); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| add_reuse_dest_tiles<EltwiseBinaryReuseDestType::DEST_TO_SRCA>(c_bet, i, i); | |
| } | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| for (uint32_t i = 0; i < NT; ++i) { | |
| pack_tile(i, c_out); | |
| } | |
| tile_regs_release(); | |
| cb_push_back(c_out, NT); | |
| } | |
| cb_pop_front(c_rstd, 1); | |
| cb_pop_front(c_xmm, NT); | |
| cb_pop_front(c_gam, NT); | |
| cb_pop_front(c_bet, NT); | |
| cb_pop_front(c_in, NT); | |
| cb_pop_front(c_x, NT); | |
| cb_pop_front(c_y, NT); | |
| cb_pop_front(c_scal, 1); | |
| } | |