Download code/hamer/kernels/hattn2/compute.cpp from changh95/hamer-p150: direct link, hf CLI and curl.
- Browser
- Download file 5.67 kB
-
https://huggingface.co/changh95/hamer-p150/resolve/main/code/hamer/kernels/hattn2/compute.cpp
- Command line
-
hf download hf://changh95/hamer-p150/code/hamer/kernels/hattn2/compute.cpp
-
curl -L -o compute.cpp https://huggingface.co/changh95/hamer-p150/resolve/main/code/hamer/kernels/hattn2/compute.cpp
5.67 kB
| // SPDX-FileCopyrightText: © 2026 Tenstorrent Inc. | |
| // SPDX-License-Identifier: Apache-2.0 | |
| // hattn2 compute, round 15 (D5): 1-query attention of one head with a DENSE score layout (round 6's hattn exp'd six | |
| // row-form score tiles; here the 192 scores are the first 192 elements = face 0, rows 0..11 of ONE fp32 tile): | |
| // s_j = q @ K_j^T six [1, 32] tiny fp32 tiles (q: two [1, 32] tiny tiles, K tiles transposed in the matmul), | |
| // packed back to back into c_st = the start of the dense tile c_sd (the reader pre-filled the | |
| // rest of c_sd with a large negative pad, so the whole-tile max sees only the scores) | |
| // m = max(c_sd) (REDUCE_SCALAR) | |
| // e = exp((s - m) * scale) on face 0 only (VectorMode::None), packed fp32 -> c_e; its first 192 elements are six | |
| // [1, 32] tiny fp32 tiles (alias c_et); the other faces are never read | |
| // o_d = sum_j e_j @ V_{j,d}, z = sum_j e_j @ ONES (one DST acquire; z = sum(e) in every column) | |
| // o_d *= 1 / z (SFPU in DST: recip of the tiny z tile, then two tiny multiplies) -> two [1, 32] bf16 -> c_out | |
| // compile-time: scale bits (fp32; exact as bf16 for 1/8) | |
| void kernel_main() { | |
| constexpr uint32_t SCALE_BITS = get_compile_time_arg_val(0); | |
| constexpr uint16_t SCALE_BF16 = (uint16_t)(SCALE_BITS >> 16); | |
| static_assert((SCALE_BITS & 0xFFFFu) == 0, "the exp scale must be exact in bf16"); | |
| constexpr uint32_t MT = 6; | |
| constexpr uint32_t c_qt = 0, c_k = 1, c_v = 2, c_scal = 3, c_st = 4, c_sd = 5, c_one = 6, c_et = 7, c_out = 16; | |
| constexpr uint32_t c_m = 24, c_e = 25; | |
| compute_kernel_hw_startup(c_qt, c_k, c_st); | |
| {PZ("WAIT"); | |
| cb_wait_front(c_qt, 2); | |
| cb_wait_front(c_k, 2 * MT);} // (V arrives separately, waited for before the PV phase) | |
| // scores: six tiny tiles | |
| {PZ("S"); | |
| reconfig_full_operand(c_k, c_qt); // srcA = in1 = K, srcB = in0 = q | |
| pack_reconfig_data_format<true>(c_st); | |
| matmul_init(c_qt, c_k, 1); | |
| cb_reserve_back(c_st, MT); | |
| for (uint32_t j = 0; j < MT; ++j) { | |
| tile_regs_acquire(); | |
| matmul_tiles(c_qt, c_k, 0, j * 2, 0); | |
| matmul_tiles(c_qt, c_k, 1, j * 2 + 1, 0); | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| pack_tile(0, c_st); | |
| tile_regs_release(); | |
| } | |
| cb_push_back(c_st, MT); | |
| // the same memory as one dense fp32 tile | |
| cb_reserve_back(c_sd, 1); | |
| cb_push_back(c_sd, 1); | |
| } | |
| cb_wait_front(c_scal, 1); | |
| // m = max over the dense tile | |
| {PZ("MAX"); | |
| reconfig_full_operand(c_sd, c_scal); // REDUCE_SCALAR: data -> SrcA, scaler -> SrcB | |
| pack_reconfig_data_format<true>(c_m); | |
| reduce_init<PoolType::MAX, ReduceDim::REDUCE_SCALAR>(c_sd, c_scal, c_m); | |
| cb_wait_front(c_sd, 1); | |
| cb_reserve_back(c_m, 1); | |
| tile_regs_acquire(); | |
| reduce_tile<PoolType::MAX, ReduceDim::REDUCE_SCALAR>(c_sd, c_scal, 0, 0, 0); | |
| reduce_uninit(); | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| pack_tile(0, c_m); | |
| tile_regs_release(); | |
| cb_push_back(c_m, 1);} | |
| // e = exp((s - m) * scale), face 0 only | |
| {PZ("EXP"); | |
| cb_wait_front(c_m, 1); | |
| reconfig_data_format(c_sd, c_m); | |
| pack_reconfig_data_format(c_e); | |
| sub_bcast_scalar_init(c_sd, c_m); | |
| cb_reserve_back(c_e, 1); | |
| tile_regs_acquire(); | |
| sub_tiles_bcast_scalar(c_sd, c_m, 0, 0, 0); | |
| exp_tile_init<false>(); | |
| exp_tile<false, true>(0, VectorMode::None, SCALE_BF16); | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| pack_tile(0, c_e); | |
| tile_regs_release(); | |
| cb_push_back(c_e, 1); | |
| cb_pop_front(c_m, 1); | |
| cb_reserve_back(c_et, MT); | |
| cb_push_back(c_et, MT);} | |
| // o = (e @ V) / (e @ ONES) | |
| {PZ("PV"); | |
| cb_wait_front(c_v, 2 * MT); | |
| cb_wait_front(c_one, 1); | |
| cb_wait_front(c_et, MT); | |
| reconfig_full_operand(c_v, c_et); // srcA = in1 = V / ONES, srcB = in0 = e | |
| pack_reconfig_data_format<true>(c_out); | |
| matmul_init(c_et, c_v, 0); | |
| cb_reserve_back(c_out, 2); | |
| tile_regs_acquire(); | |
| for (uint32_t j = 0; j < MT; ++j) { | |
| matmul_tiles(c_et, c_v, j, j * 2, 0); | |
| matmul_tiles(c_et, c_v, j, j * 2 + 1, 1); | |
| matmul_tiles(c_et, c_one, j, 0, 2); | |
| } | |
| // the tiny [1, 32] tiles span DST faces 0 and 1 only: VectorMode::R | |
| recip_tile_init(); | |
| recip_tile(2, VectorMode::R); | |
| mul_binary_tile_init(); | |
| MATH((SFPU_BINARY_CALL(DST_SYNC_MODE, DST_ACCUM_MODE, calculate_sfpu_binary_mul, | |
| (APPROX, ckernel::BinaryOp::MUL, 8, DST_ACCUM_MODE), 0, 2, 0, VectorMode::R))); | |
| MATH((SFPU_BINARY_CALL(DST_SYNC_MODE, DST_ACCUM_MODE, calculate_sfpu_binary_mul, | |
| (APPROX, ckernel::BinaryOp::MUL, 8, DST_ACCUM_MODE), 1, 2, 1, VectorMode::R))); | |
| tile_regs_commit(); | |
| tile_regs_wait(); | |
| pack_tile(0, c_out); | |
| pack_tile(1, c_out); | |
| tile_regs_release(); | |
| cb_push_back(c_out, 2);} | |
| cb_pop_front(c_et, MT); | |
| cb_pop_front(c_e, 1); | |
| cb_pop_front(c_sd, 1); | |
| cb_pop_front(c_one, 1); | |
| cb_pop_front(c_qt, 2); | |
| cb_pop_front(c_k, 2 * MT); | |
| cb_pop_front(c_v, 2 * MT); | |
| cb_pop_front(c_scal, 1); | |
| } | |