src/cpu/cpu_jit_fused.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "cpu_jit.h" | ||
| 2 | #include <brotensor/detail/cpu/thread_pool.h> | ||
| 3 | #include <algorithm> | ||
| 4 | #include <cmath> | ||
| 5 | #include <cstdint> | ||
| 6 | |||
| 7 | namespace brotensor::detail::cpu::jit { | ||
| 8 | namespace ref { | ||
| 9 | |||
| 10 | ✗ | inline void fused_residual_rmsnorm(float* X, const float* res, const float* gamma, float eps, float* Y, int B, int D) { | |
| 11 | ✗ | if (B <= 0 || D <= 0) return; | |
| 12 | ✗ | const float inv_D = 1.0f / static_cast<float>(D); | |
| 13 | ✗ | auto row_fn = [&](int b) { | |
| 14 | ✗ | float* xr = X + static_cast<size_t>(b) * D; | |
| 15 | ✗ | const float* rr = res + static_cast<size_t>(b) * D; | |
| 16 | ✗ | float* yr = Y + static_cast<size_t>(b) * D; | |
| 17 | ✗ | float sum = 0.0f; | |
| 18 | ✗ | for (int i = 0; i < D; ++i) { | |
| 19 | ✗ | xr[i] += rr[i]; | |
| 20 | ✗ | sum += xr[i] * xr[i]; | |
| 21 | ✗ | } | |
| 22 | ✗ | float rrms = 1.0f / std::sqrt(sum * inv_D + eps); | |
| 23 | ✗ | for (int i = 0; i < D; ++i) { | |
| 24 | ✗ | yr[i] = xr[i] * gamma[i] * rrms; | |
| 25 | ✗ | } | |
| 26 | ✗ | }; | |
| 27 | ✗ | if (B > 1 && static_cast<int64_t>(B) * D >= 262144) { | |
| 28 | ✗ | detail::cpu::parallel_for(static_cast<size_t>(B), [&](size_t bi) { | |
| 29 | ✗ | row_fn(static_cast<int>(bi)); | |
| 30 | ✗ | }); | |
| 31 | ✗ | } else { | |
| 32 | ✗ | for (int b = 0; b < B; ++b) row_fn(b); | |
| 33 | } | ||
| 34 | ✗ | } | |
| 35 | |||
| 36 | ✗ | inline void fused_residual_layernorm(float* X, const float* res, const float* gamma, const float* beta, | |
| 37 | float eps, float* Y, int B, int D) { | ||
| 38 | ✗ | if (B <= 0 || D <= 0) return; | |
| 39 | ✗ | const float inv_D = 1.0f / static_cast<float>(D); | |
| 40 | ✗ | auto row_fn = [&](int b) { | |
| 41 | ✗ | float* xr = X + static_cast<size_t>(b) * D; | |
| 42 | ✗ | const float* rr = res + static_cast<size_t>(b) * D; | |
| 43 | ✗ | float* yr = Y + static_cast<size_t>(b) * D; | |
| 44 | ✗ | float sum = 0.0f; | |
| 45 | ✗ | for (int i = 0; i < D; ++i) { | |
| 46 | ✗ | xr[i] += rr[i]; | |
| 47 | ✗ | sum += xr[i]; | |
| 48 | ✗ | } | |
| 49 | ✗ | float mean = sum * inv_D; | |
| 50 | ✗ | float sumsq = 0.0f; | |
| 51 | ✗ | for (int i = 0; i < D; ++i) { | |
| 52 | ✗ | float diff = xr[i] - mean; | |
| 53 | ✗ | sumsq += diff * diff; | |
| 54 | ✗ | } | |
| 55 | ✗ | float var = sumsq * inv_D; | |
| 56 | ✗ | float rstd = 1.0f / std::sqrt(var + eps); | |
| 57 | ✗ | for (int i = 0; i < D; ++i) { | |
| 58 | ✗ | float g = gamma ? gamma[i] : 1.0f; | |
| 59 | ✗ | float bv = beta ? beta[i] : 0.0f; | |
| 60 | ✗ | yr[i] = g * ((xr[i] - mean) * rstd) + bv; | |
| 61 | ✗ | } | |
| 62 | ✗ | }; | |
| 63 | ✗ | if (B > 1 && static_cast<int64_t>(B) * D >= 262144) { | |
| 64 | ✗ | detail::cpu::parallel_for(static_cast<size_t>(B), [&](size_t bi) { | |
| 65 | ✗ | row_fn(static_cast<int>(bi)); | |
| 66 | ✗ | }); | |
| 67 | ✗ | } else { | |
| 68 | ✗ | for (int b = 0; b < B; ++b) row_fn(b); | |
| 69 | } | ||
| 70 | ✗ | } | |
| 71 | |||
| 72 | ✗ | inline void fused_layernorm_modulate(const float* X, const float* gamma, const float* beta, | |
| 73 | const float* scale, const float* shift, float eps, float* Y, int R, int D) { | ||
| 74 | ✗ | if (R <= 0 || D <= 0) return; | |
| 75 | ✗ | const float inv_D = 1.0f / static_cast<float>(D); | |
| 76 | ✗ | auto row_fn = [&](int r) { | |
| 77 | ✗ | const float* xr = X + static_cast<size_t>(r) * D; | |
| 78 | ✗ | float* yr = Y + static_cast<size_t>(r) * D; | |
| 79 | ✗ | float sum = 0.0f; | |
| 80 | ✗ | for (int i = 0; i < D; ++i) sum += xr[i]; | |
| 81 | ✗ | float mean = sum * inv_D; | |
| 82 | ✗ | float sumsq = 0.0f; | |
| 83 | ✗ | for (int i = 0; i < D; ++i) { | |
| 84 | ✗ | float diff = xr[i] - mean; | |
| 85 | ✗ | sumsq += diff * diff; | |
| 86 | ✗ | } | |
| 87 | ✗ | float var = sumsq * inv_D; | |
| 88 | ✗ | float rstd = 1.0f / std::sqrt(var + eps); | |
| 89 | ✗ | for (int i = 0; i < D; ++i) { | |
| 90 | ✗ | float g = gamma ? gamma[i] : 1.0f; | |
| 91 | ✗ | float bv = beta ? beta[i] : 0.0f; | |
| 92 | ✗ | float norm = g * ((xr[i] - mean) * rstd) + bv; | |
| 93 | ✗ | yr[i] = norm * (1.0f + scale[i]) + shift[i]; | |
| 94 | ✗ | } | |
| 95 | ✗ | }; | |
| 96 | ✗ | if (R > 1 && static_cast<int64_t>(R) * D >= 262144) { | |
| 97 | ✗ | detail::cpu::parallel_for(static_cast<size_t>(R), [&](size_t ri) { | |
| 98 | ✗ | row_fn(static_cast<int>(ri)); | |
| 99 | ✗ | }); | |
| 100 | ✗ | } else { | |
| 101 | ✗ | for (int r = 0; r < R; ++r) row_fn(r); | |
| 102 | } | ||
| 103 | ✗ | } | |
| 104 | |||
| 105 | } // namespace ref | ||
| 106 | } // namespace brotensor::detail::cpu::jit | ||
| 107 | |||
| 108 | #if BROTENSOR_HAS_BRASS_JIT | ||
| 109 | |||
| 110 | #include <brass/codegen/kernel_jit.hpp> | ||
| 111 | #include <brass/mir/builder.hpp> | ||
| 112 | #include <brass/mir/module.hpp> | ||
| 113 | #include <brass/mir/function.hpp> | ||
| 114 | #include <cmath> | ||
| 115 | #include <mutex> | ||
| 116 | #include <vector> | ||
| 117 | #include <memory> | ||
| 118 | #include <algorithm> | ||
| 119 | #include <iostream> | ||
| 120 | |||
| 121 | namespace brotensor::detail::cpu::jit { | ||
| 122 | |||
| 123 | namespace { | ||
| 124 | |||
| 125 | using namespace brass; | ||
| 126 | using namespace brass::codegen; | ||
| 127 | |||
| 128 | struct JitFusedKernels { | ||
| 129 | bool available = false; | ||
| 130 | |||
| 131 | using FusedResidualRmsNormRowFn = void (*)(float* x, const float* res, const float* gamma, float* y, uint64_t d, float eps, float inv_d); | ||
| 132 | FusedResidualRmsNormRowFn fused_residual_rmsnorm_row_fn = nullptr; | ||
| 133 | |||
| 134 | using FusedResidualLayerNormRowFn = void (*)(float* x, const float* res, const float* gamma, const float* beta, float* y, uint64_t d, float eps, float inv_d); | ||
| 135 | FusedResidualLayerNormRowFn fused_residual_layernorm_row_fn = nullptr; | ||
| 136 | |||
| 137 | using FusedLayerNormModulateRowFn = void (*)(const float* x, const float* gamma, const float* beta, const float* scale, const float* shift, float* y, uint64_t d, float eps, float inv_d); | ||
| 138 | FusedLayerNormModulateRowFn fused_layernorm_modulate_row_fn = nullptr; | ||
| 139 | |||
| 140 | std::vector<std::shared_ptr<JitExecutionEngine>> engines; | ||
| 141 | }; | ||
| 142 | |||
| 143 | // Horizontal sum of an 8-wide float vector using destination scratch buffer | ||
| 144 | 15 | static Value* reduce_vsum8(KernelBuilder& kb, Value* scratch, Value* vsum) { | |
| 145 | 15 | kb.vstore_f32x8(scratch, vsum); | |
| 146 | 15 | Value* s0 = kb.load_f32(scratch, 0); Value* s1 = kb.load_f32(scratch, 4); | |
| 147 | 15 | Value* s2 = kb.load_f32(scratch, 8); Value* s3 = kb.load_f32(scratch, 12); | |
| 148 | 15 | Value* s4 = kb.load_f32(scratch, 16); Value* s5 = kb.load_f32(scratch, 20); | |
| 149 | 15 | Value* s6 = kb.load_f32(scratch, 24); Value* s7 = kb.load_f32(scratch, 28); | |
| 150 | 15 | Value* sum0123 = kb.add(kb.add(s0, s1), kb.add(s2, s3)); | |
| 151 | 15 | Value* sum4567 = kb.add(kb.add(s4, s5), kb.add(s6, s7)); | |
| 152 | 15 | return kb.add(sum0123, sum4567); | |
| 153 | } | ||
| 154 | |||
| 155 | // ── 1. Fused Residual RMSNorm Row (Option B: X += res in-place + RMSNorm) ─── | ||
| 156 | // | ||
| 157 | // Computes in-place residual addition X += res, writes X, and accumulates sum_sq | ||
| 158 | // in the EXACT same vector register pass, eliminating a full memory read/write pass. | ||
| 159 | 3 | static KernelFunction build_fused_residual_rmsnorm_row(KernelJit& jit) { | |
| 160 | 3 | Module mod("mod_fused_residual_rmsnorm_row"); | |
| 161 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | mod.add_external_symbol("rsqrtf"); |
| 162 |
9/18✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
|
3 | Function* fn = mod.create_function("fused_residual_rmsnorm_row", Type::void_type(), { |
| 163 | 21 | Type::ptr(), Type::ptr(), Type::ptr(), Type::ptr(), Type::i64(), Type::f32(), Type::f32() | |
| 164 | }); | ||
| 165 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | KernelBuilder kb(mod, fn); |
| 166 | |||
| 167 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* entry = kb.builder().append_block("entry"); |
| 168 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* x = kb.builder().add_block_param(entry, Type::ptr()); |
| 169 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* res = kb.builder().add_block_param(entry, Type::ptr()); |
| 170 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* gamma = kb.builder().add_block_param(entry, Type::ptr()); |
| 171 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* y = kb.builder().add_block_param(entry, Type::ptr()); |
| 172 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* d = kb.builder().add_block_param(entry, Type::i64()); |
| 173 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* eps = kb.builder().add_block_param(entry, Type::f32()); |
| 174 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* inv_d = kb.builder().add_block_param(entry, Type::f32()); |
| 175 | |||
| 176 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_vhead = kb.builder().create_block("res_rms_l1_vhead"); |
| 177 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_vbody = kb.builder().create_block("res_rms_l1_vbody"); |
| 178 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_vexit = kb.builder().create_block("res_rms_l1_vexit"); |
| 179 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_shead = kb.builder().create_block("res_rms_l1_shead"); |
| 180 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_sbody = kb.builder().create_block("res_rms_l1_sbody"); |
| 181 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_exit = kb.builder().create_block("res_rms_l1_exit"); |
| 182 | |||
| 183 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_vhead = kb.builder().create_block("res_rms_l2_vhead"); |
| 184 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_vbody = kb.builder().create_block("res_rms_l2_vbody"); |
| 185 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_shead = kb.builder().create_block("res_rms_l2_shead"); |
| 186 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_sbody = kb.builder().create_block("res_rms_l2_sbody"); |
| 187 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_exit = kb.builder().create_block("res_rms_l2_exit"); |
| 188 | |||
| 189 | 3 | kb.position_at_end(entry); | |
| 190 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* zero_i64 = kb.builder().build_iconst_i64(0); |
| 191 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* one_i64 = kb.builder().build_iconst_i64(1); |
| 192 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* two_i64 = kb.builder().build_iconst_i64(2); |
| 193 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* eight_i64 = kb.builder().build_iconst_i64(8); |
| 194 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* zero_f32 = kb.builder().build_fconst_f32(0.0f); |
| 195 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vzero = kb.vzero(Type::f32x8()); |
| 196 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* mask_eight = kb.builder().build_iconst_i64(~int64_t(7)); |
| 197 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vec_d = kb.builder().build_and(d, mask_eight); |
| 198 | |||
| 199 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* has_vec = kb.builder().build_sge(d, eight_i64); |
| 200 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(has_vec, l1_vhead, {zero_i64, vzero}, l1_shead, {zero_i64, zero_f32}); |
| 201 | |||
| 202 | // Pass 1: Vector loop X += res in-place AND accumulates sum_sq in same register pass | ||
| 203 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_vhead); |
| 204 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv1_v = kb.builder().add_block_param(l1_vhead, Type::i64()); |
| 205 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vsum = kb.builder().add_block_param(l1_vhead, Type::f32x8()); |
| 206 | 3 | kb.position_at_end(l1_vhead); | |
| 207 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond1_v = kb.builder().build_slt(iv1_v, vec_d); |
| 208 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond1_v, l1_vbody, {}, l1_vexit, {iv1_v, vsum}); |
| 209 | |||
| 210 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_vbody); |
| 211 | 3 | kb.position_at_end(l1_vbody); | |
| 212 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* byte_off1 = kb.builder().build_shl(iv1_v, two_i64); |
| 213 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* px1 = kb.builder().build_add(x, byte_off1); |
| 214 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* pres1 = kb.builder().build_add(res, byte_off1); |
| 215 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vx1 = kb.vload_f32x8(px1); |
| 216 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vr1 = kb.vload_f32x8(pres1); |
| 217 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vx_new = kb.vadd(vx1, vr1); |
| 218 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.vstore_f32x8(px1, vx_new); // X += res in-place |
| 219 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_vsum = kb.vfma(vx_new, vx_new, vsum); // sum_sq accumulation in exact same pass |
| 220 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv1_v = kb.builder().build_add(iv1_v, eight_i64); |
| 221 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l1_vhead, {next_iv1_v, next_vsum}); |
| 222 | |||
| 223 | // Pass 1: Vector exit -> horizontal reduction | ||
| 224 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_vexit); |
| 225 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* exit_iv1 = kb.builder().add_block_param(l1_vexit, Type::i64()); |
| 226 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* exit_vsum = kb.builder().add_block_param(l1_vexit, Type::f32x8()); |
| 227 | 3 | kb.position_at_end(l1_vexit); | |
| 228 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* init_scalar_sum = reduce_vsum8(kb, y, exit_vsum); |
| 229 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l1_shead, {exit_iv1, init_scalar_sum}); |
| 230 | |||
| 231 | // Pass 1: Scalar remainder | ||
| 232 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_shead); |
| 233 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv1_s = kb.builder().add_block_param(l1_shead, Type::i64()); |
| 234 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* sum_sq = kb.builder().add_block_param(l1_shead, Type::f32()); |
| 235 | 3 | kb.position_at_end(l1_shead); | |
| 236 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond1_s = kb.builder().build_slt(iv1_s, d); |
| 237 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond1_s, l1_sbody, {}, l1_exit, {sum_sq}); |
| 238 | |||
| 239 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_sbody); |
| 240 | 3 | kb.position_at_end(l1_sbody); | |
| 241 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* xi = kb.load_f32_indexed(x, iv1_s, 4, 0); |
| 242 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* ri = kb.load_f32_indexed(res, iv1_s, 4, 0); |
| 243 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* xi_new = kb.add(xi, ri); |
| 244 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.store_f32_indexed(x, iv1_s, xi_new, 4, 0); |
| 245 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* xi_sq = kb.mul(xi_new, xi_new); |
| 246 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_sum = kb.add(sum_sq, xi_sq); |
| 247 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv1_s = kb.builder().build_add(iv1_s, one_i64); |
| 248 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l1_shead, {next_iv1_s, next_sum}); |
| 249 | |||
| 250 | // Pass 1 exit -> compute rrms | ||
| 251 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_exit); |
| 252 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* final_sum = kb.builder().add_block_param(l1_exit, Type::f32()); |
| 253 | 3 | kb.position_at_end(l1_exit); | |
| 254 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* mean_sq = kb.mul(final_sum, inv_d); |
| 255 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* denom = kb.add(mean_sq, eps); |
| 256 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | Value* rrms = kb.builder().build_call("rsqrtf", Type::f32(), {denom}); |
| 257 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vrrms = kb.vbroadcast(Type::f32x8(), rrms); |
| 258 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l2_vhead, {zero_i64, rrms, vrrms}); |
| 259 | |||
| 260 | // Pass 2: Vector loop y = x * gamma * rrms | ||
| 261 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_vhead); |
| 262 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv2_v = kb.builder().add_block_param(l2_vhead, Type::i64()); |
| 263 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* rrms_val = kb.builder().add_block_param(l2_vhead, Type::f32()); |
| 264 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vrrms_val = kb.builder().add_block_param(l2_vhead, Type::f32x8()); |
| 265 | 3 | kb.position_at_end(l2_vhead); | |
| 266 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond2_v = kb.builder().build_slt(iv2_v, vec_d); |
| 267 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond2_v, l2_vbody, {}, l2_shead, {iv2_v, rrms_val}); |
| 268 | |||
| 269 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_vbody); |
| 270 | 3 | kb.position_at_end(l2_vbody); | |
| 271 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* byte_off2 = kb.builder().build_shl(iv2_v, two_i64); |
| 272 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* px2 = kb.builder().build_add(x, byte_off2); |
| 273 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* pg2 = kb.builder().build_add(gamma, byte_off2); |
| 274 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* py2 = kb.builder().build_add(y, byte_off2); |
| 275 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vx2 = kb.vload_f32x8(px2); |
| 276 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vg2 = kb.vload_f32x8(pg2); |
| 277 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vxg = kb.vmul(vx2, vg2); |
| 278 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vy = kb.vmul(vxg, vrrms_val); |
| 279 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.vstore_f32x8(py2, vy); |
| 280 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv2_v = kb.builder().build_add(iv2_v, eight_i64); |
| 281 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l2_vhead, {next_iv2_v, rrms_val, vrrms_val}); |
| 282 | |||
| 283 | // Pass 2: Scalar remainder | ||
| 284 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_shead); |
| 285 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv2_s = kb.builder().add_block_param(l2_shead, Type::i64()); |
| 286 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* rrms_scalar = kb.builder().add_block_param(l2_shead, Type::f32()); |
| 287 | 3 | kb.position_at_end(l2_shead); | |
| 288 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond2_s = kb.builder().build_slt(iv2_s, d); |
| 289 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond2_s, l2_sbody, l2_exit); |
| 290 | |||
| 291 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_sbody); |
| 292 | 3 | kb.position_at_end(l2_sbody); | |
| 293 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* x2 = kb.load_f32_indexed(x, iv2_s, 4, 0); |
| 294 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* g2 = kb.load_f32_indexed(gamma, iv2_s, 4, 0); |
| 295 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* xg2 = kb.mul(x2, g2); |
| 296 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* out_val = kb.mul(xg2, rrms_scalar); |
| 297 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.store_f32_indexed(y, iv2_s, out_val, 4, 0); |
| 298 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv2_s = kb.builder().build_add(iv2_s, one_i64); |
| 299 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l2_shead, {next_iv2_s, rrms_scalar}); |
| 300 | |||
| 301 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_exit); |
| 302 | 3 | kb.position_at_end(l2_exit); | |
| 303 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_ret_void(); |
| 304 | |||
| 305 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | return jit.compile(mod, "fused_residual_rmsnorm_row"); |
| 306 | 3 | } | |
| 307 | |||
| 308 | // ── 2. Fused Residual LayerNorm Row (X += res in-place + LayerNorm) ───────── | ||
| 309 | // | ||
| 310 | // Computes in-place residual addition X += res, writes X, and computes mean and | ||
| 311 | // variance across vector registers, writing Y = gamma * (X - mean) * rstd + beta | ||
| 312 | // directly in registers without intermediate buffers. | ||
| 313 | 3 | static KernelFunction build_fused_residual_layernorm_row(KernelJit& jit) { | |
| 314 | 3 | Module mod("mod_fused_residual_layernorm_row"); | |
| 315 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | mod.add_external_symbol("rsqrtf"); |
| 316 |
10/20✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✗ Branch 19 not taken.
|
3 | Function* fn = mod.create_function("fused_residual_layernorm_row", Type::void_type(), { |
| 317 | 24 | Type::ptr(), Type::ptr(), Type::ptr(), Type::ptr(), Type::ptr(), Type::i64(), Type::f32(), Type::f32() | |
| 318 | }); | ||
| 319 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | KernelBuilder kb(mod, fn); |
| 320 | |||
| 321 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* entry = kb.builder().append_block("entry"); |
| 322 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* x = kb.builder().add_block_param(entry, Type::ptr()); |
| 323 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* res = kb.builder().add_block_param(entry, Type::ptr()); |
| 324 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* gamma = kb.builder().add_block_param(entry, Type::ptr()); |
| 325 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* beta = kb.builder().add_block_param(entry, Type::ptr()); |
| 326 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* y = kb.builder().add_block_param(entry, Type::ptr()); |
| 327 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* d = kb.builder().add_block_param(entry, Type::i64()); |
| 328 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* eps = kb.builder().add_block_param(entry, Type::f32()); |
| 329 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* inv_d = kb.builder().add_block_param(entry, Type::f32()); |
| 330 | |||
| 331 | // Pass 1 blocks (residual add + mean) | ||
| 332 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_vhead = kb.builder().create_block("res_ln_l1_vhead"); |
| 333 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_vbody = kb.builder().create_block("res_ln_l1_vbody"); |
| 334 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_vexit = kb.builder().create_block("res_ln_l1_vexit"); |
| 335 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_shead = kb.builder().create_block("res_ln_l1_shead"); |
| 336 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_sbody = kb.builder().create_block("res_ln_l1_sbody"); |
| 337 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_exit = kb.builder().create_block("res_ln_l1_exit"); |
| 338 | |||
| 339 | // Pass 2 blocks (variance) | ||
| 340 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_vhead = kb.builder().create_block("res_ln_l2_vhead"); |
| 341 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_vbody = kb.builder().create_block("res_ln_l2_vbody"); |
| 342 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_vexit = kb.builder().create_block("res_ln_l2_vexit"); |
| 343 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_shead = kb.builder().create_block("res_ln_l2_shead"); |
| 344 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_sbody = kb.builder().create_block("res_ln_l2_sbody"); |
| 345 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_exit = kb.builder().create_block("res_ln_l2_exit"); |
| 346 | |||
| 347 | // Pass 3 blocks (gamma * xhat + beta) | ||
| 348 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l3_vhead = kb.builder().create_block("res_ln_l3_vhead"); |
| 349 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l3_vbody = kb.builder().create_block("res_ln_l3_vbody"); |
| 350 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l3_shead = kb.builder().create_block("res_ln_l3_shead"); |
| 351 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l3_sbody = kb.builder().create_block("res_ln_l3_sbody"); |
| 352 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l3_exit = kb.builder().create_block("res_ln_l3_exit"); |
| 353 | |||
| 354 | 3 | kb.position_at_end(entry); | |
| 355 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* zero_i64 = kb.builder().build_iconst_i64(0); |
| 356 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* one_i64 = kb.builder().build_iconst_i64(1); |
| 357 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* two_i64 = kb.builder().build_iconst_i64(2); |
| 358 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* eight_i64 = kb.builder().build_iconst_i64(8); |
| 359 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* zero_f32 = kb.builder().build_fconst_f32(0.0f); |
| 360 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vzero = kb.vzero(Type::f32x8()); |
| 361 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* mask_eight = kb.builder().build_iconst_i64(~int64_t(7)); |
| 362 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vec_d = kb.builder().build_and(d, mask_eight); |
| 363 | |||
| 364 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* has_vec = kb.builder().build_sge(d, eight_i64); |
| 365 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(has_vec, l1_vhead, {zero_i64, vzero}, l1_shead, {zero_i64, zero_f32}); |
| 366 | |||
| 367 | // Pass 1: Vector sum + in-place residual addition X += res | ||
| 368 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_vhead); |
| 369 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv1_v = kb.builder().add_block_param(l1_vhead, Type::i64()); |
| 370 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vsum1 = kb.builder().add_block_param(l1_vhead, Type::f32x8()); |
| 371 | 3 | kb.position_at_end(l1_vhead); | |
| 372 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond1_v = kb.builder().build_slt(iv1_v, vec_d); |
| 373 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond1_v, l1_vbody, {}, l1_vexit, {iv1_v, vsum1}); |
| 374 | |||
| 375 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_vbody); |
| 376 | 3 | kb.position_at_end(l1_vbody); | |
| 377 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* byte_off1 = kb.builder().build_shl(iv1_v, two_i64); |
| 378 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* px1 = kb.builder().build_add(x, byte_off1); |
| 379 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* pres1 = kb.builder().build_add(res, byte_off1); |
| 380 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vx1 = kb.vload_f32x8(px1); |
| 381 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vr1 = kb.vload_f32x8(pres1); |
| 382 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vx_new = kb.vadd(vx1, vr1); |
| 383 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.vstore_f32x8(px1, vx_new); // X += res in-place! |
| 384 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_vsum1 = kb.vadd(vsum1, vx_new); |
| 385 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv1_v = kb.builder().build_add(iv1_v, eight_i64); |
| 386 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l1_vhead, {next_iv1_v, next_vsum1}); |
| 387 | |||
| 388 | // Pass 1: Vector exit -> horizontal sum | ||
| 389 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_vexit); |
| 390 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* exit_iv1 = kb.builder().add_block_param(l1_vexit, Type::i64()); |
| 391 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* exit_vsum1 = kb.builder().add_block_param(l1_vexit, Type::f32x8()); |
| 392 | 3 | kb.position_at_end(l1_vexit); | |
| 393 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* init_sum1 = reduce_vsum8(kb, y, exit_vsum1); |
| 394 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l1_shead, {exit_iv1, init_sum1}); |
| 395 | |||
| 396 | // Pass 1: Scalar remainder | ||
| 397 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_shead); |
| 398 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv1_s = kb.builder().add_block_param(l1_shead, Type::i64()); |
| 399 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* sum1 = kb.builder().add_block_param(l1_shead, Type::f32()); |
| 400 | 3 | kb.position_at_end(l1_shead); | |
| 401 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond1_s = kb.builder().build_slt(iv1_s, d); |
| 402 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond1_s, l1_sbody, {}, l1_exit, {sum1}); |
| 403 | |||
| 404 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_sbody); |
| 405 | 3 | kb.position_at_end(l1_sbody); | |
| 406 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* xi1 = kb.load_f32_indexed(x, iv1_s, 4, 0); |
| 407 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* ri1 = kb.load_f32_indexed(res, iv1_s, 4, 0); |
| 408 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* xi_new = kb.add(xi1, ri1); |
| 409 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.store_f32_indexed(x, iv1_s, xi_new, 4, 0); // X += res in-place! |
| 410 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_sum1 = kb.add(sum1, xi_new); |
| 411 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv1_s = kb.builder().build_add(iv1_s, one_i64); |
| 412 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l1_shead, {next_iv1_s, next_sum1}); |
| 413 | |||
| 414 | // Pass 1: Mean computed -> enter Pass 2 | ||
| 415 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_exit); |
| 416 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* final_sum1 = kb.builder().add_block_param(l1_exit, Type::f32()); |
| 417 | 3 | kb.position_at_end(l1_exit); | |
| 418 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* mean = kb.mul(final_sum1, inv_d); |
| 419 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vmean = kb.vbroadcast(Type::f32x8(), mean); |
| 420 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(has_vec, l2_vhead, {zero_i64, vzero, mean, vmean}, l2_shead, {zero_i64, zero_f32, mean}); |
| 421 | |||
| 422 | // Pass 2: Vector sum of squared deviations | ||
| 423 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_vhead); |
| 424 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv2_v = kb.builder().add_block_param(l2_vhead, Type::i64()); |
| 425 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vsum2 = kb.builder().add_block_param(l2_vhead, Type::f32x8()); |
| 426 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* m2_scalar = kb.builder().add_block_param(l2_vhead, Type::f32()); |
| 427 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vm2 = kb.builder().add_block_param(l2_vhead, Type::f32x8()); |
| 428 | 3 | kb.position_at_end(l2_vhead); | |
| 429 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond2_v = kb.builder().build_slt(iv2_v, vec_d); |
| 430 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond2_v, l2_vbody, {}, l2_vexit, {iv2_v, vsum2, m2_scalar}); |
| 431 | |||
| 432 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_vbody); |
| 433 | 3 | kb.position_at_end(l2_vbody); | |
| 434 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* byte_off2 = kb.builder().build_shl(iv2_v, two_i64); |
| 435 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* px2 = kb.builder().build_add(x, byte_off2); |
| 436 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vx2 = kb.vload_f32x8(px2); |
| 437 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vdev = kb.vsub(vx2, vm2); |
| 438 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_vsum2 = kb.vfma(vdev, vdev, vsum2); |
| 439 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv2_v = kb.builder().build_add(iv2_v, eight_i64); |
| 440 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l2_vhead, {next_iv2_v, next_vsum2, m2_scalar, vm2}); |
| 441 | |||
| 442 | // Pass 2: Vector exit -> horizontal sum | ||
| 443 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_vexit); |
| 444 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* exit_iv2 = kb.builder().add_block_param(l2_vexit, Type::i64()); |
| 445 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* exit_vsum2 = kb.builder().add_block_param(l2_vexit, Type::f32x8()); |
| 446 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* m2_out = kb.builder().add_block_param(l2_vexit, Type::f32()); |
| 447 | 3 | kb.position_at_end(l2_vexit); | |
| 448 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* init_sumsq = reduce_vsum8(kb, y, exit_vsum2); |
| 449 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l2_shead, {exit_iv2, init_sumsq, m2_out}); |
| 450 | |||
| 451 | // Pass 2: Scalar remainder | ||
| 452 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_shead); |
| 453 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv2_s = kb.builder().add_block_param(l2_shead, Type::i64()); |
| 454 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* sumsq = kb.builder().add_block_param(l2_shead, Type::f32()); |
| 455 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* m2_s = kb.builder().add_block_param(l2_shead, Type::f32()); |
| 456 | 3 | kb.position_at_end(l2_shead); | |
| 457 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond2_s = kb.builder().build_slt(iv2_s, d); |
| 458 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond2_s, l2_sbody, {}, l2_exit, {sumsq, m2_s}); |
| 459 | |||
| 460 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_sbody); |
| 461 | 3 | kb.position_at_end(l2_sbody); | |
| 462 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* xi2 = kb.load_f32_indexed(x, iv2_s, 4, 0); |
| 463 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* diff2 = kb.sub(xi2, m2_s); |
| 464 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* diff_sq2 = kb.mul(diff2, diff2); |
| 465 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_sumsq = kb.add(sumsq, diff_sq2); |
| 466 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv2_s = kb.builder().build_add(iv2_s, one_i64); |
| 467 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l2_shead, {next_iv2_s, next_sumsq, m2_s}); |
| 468 | |||
| 469 | // Pass 2 exit -> compute rstd | ||
| 470 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_exit); |
| 471 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* final_sumsq = kb.builder().add_block_param(l2_exit, Type::f32()); |
| 472 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* final_mean = kb.builder().add_block_param(l2_exit, Type::f32()); |
| 473 | 3 | kb.position_at_end(l2_exit); | |
| 474 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* var = kb.mul(final_sumsq, inv_d); |
| 475 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* var_eps = kb.add(var, eps); |
| 476 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | Value* rstd = kb.builder().build_call("rsqrtf", Type::f32(), {var_eps}); |
| 477 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vmean3 = kb.vbroadcast(Type::f32x8(), final_mean); |
| 478 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vrstd3 = kb.vbroadcast(Type::f32x8(), rstd); |
| 479 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l3_vhead, {zero_i64, final_mean, rstd, vmean3, vrstd3}); |
| 480 | |||
| 481 | // Pass 3: Vector LayerNorm Y = gamma * (X - mean) * rstd + beta | ||
| 482 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l3_vhead); |
| 483 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv3_v = kb.builder().add_block_param(l3_vhead, Type::i64()); |
| 484 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* m3_s = kb.builder().add_block_param(l3_vhead, Type::f32()); |
| 485 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* r3_s = kb.builder().add_block_param(l3_vhead, Type::f32()); |
| 486 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vm3 = kb.builder().add_block_param(l3_vhead, Type::f32x8()); |
| 487 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vr3 = kb.builder().add_block_param(l3_vhead, Type::f32x8()); |
| 488 | 3 | kb.position_at_end(l3_vhead); | |
| 489 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond3_v = kb.builder().build_slt(iv3_v, vec_d); |
| 490 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond3_v, l3_vbody, {}, l3_shead, {iv3_v, m3_s, r3_s}); |
| 491 | |||
| 492 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l3_vbody); |
| 493 | 3 | kb.position_at_end(l3_vbody); | |
| 494 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* byte_off3 = kb.builder().build_shl(iv3_v, two_i64); |
| 495 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* px3 = kb.builder().build_add(x, byte_off3); |
| 496 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* pg3 = kb.builder().build_add(gamma, byte_off3); |
| 497 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* pb3 = kb.builder().build_add(beta, byte_off3); |
| 498 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* py3 = kb.builder().build_add(y, byte_off3); |
| 499 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vx3 = kb.vload_f32x8(px3); |
| 500 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vg3 = kb.vload_f32x8(pg3); |
| 501 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vb3 = kb.vload_f32x8(pb3); |
| 502 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vdiff3 = kb.vsub(vx3, vm3); |
| 503 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vxhat3 = kb.vmul(vdiff3, vr3); |
| 504 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vy3 = kb.vfma(vg3, vxhat3, vb3); // y = gamma * xhat + beta |
| 505 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.vstore_f32x8(py3, vy3); |
| 506 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv3_v = kb.builder().build_add(iv3_v, eight_i64); |
| 507 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l3_vhead, {next_iv3_v, m3_s, r3_s, vm3, vr3}); |
| 508 | |||
| 509 | // Pass 3: Scalar remainder | ||
| 510 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l3_shead); |
| 511 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv3_s = kb.builder().add_block_param(l3_shead, Type::i64()); |
| 512 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* m3_sc = kb.builder().add_block_param(l3_shead, Type::f32()); |
| 513 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* r3_sc = kb.builder().add_block_param(l3_shead, Type::f32()); |
| 514 | 3 | kb.position_at_end(l3_shead); | |
| 515 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond3_s = kb.builder().build_slt(iv3_s, d); |
| 516 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond3_s, l3_sbody, l3_exit); |
| 517 | |||
| 518 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l3_sbody); |
| 519 | 3 | kb.position_at_end(l3_sbody); | |
| 520 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* x3 = kb.load_f32_indexed(x, iv3_s, 4, 0); |
| 521 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* g3 = kb.load_f32_indexed(gamma, iv3_s, 4, 0); |
| 522 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* b3 = kb.load_f32_indexed(beta, iv3_s, 4, 0); |
| 523 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* diff3 = kb.sub(x3, m3_sc); |
| 524 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* xhat3 = kb.mul(diff3, r3_sc); |
| 525 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* y3 = kb.builder().build_fma_f32(g3, xhat3, b3); |
| 526 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.store_f32_indexed(y, iv3_s, y3, 4, 0); |
| 527 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv3_s = kb.builder().build_add(iv3_s, one_i64); |
| 528 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l3_shead, {next_iv3_s, m3_sc, r3_sc}); |
| 529 | |||
| 530 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l3_exit); |
| 531 | 3 | kb.position_at_end(l3_exit); | |
| 532 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_ret_void(); |
| 533 | |||
| 534 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | return jit.compile(mod, "fused_residual_layernorm_row"); |
| 535 | 3 | } | |
| 536 | |||
| 537 | // ── 3. Fused LayerNorm + Modulate Row (Option B: Zero Intermediate Memory) ── | ||
| 538 | // | ||
| 539 | // Computes LayerNorm directly into registers and immediately applies AdaLN | ||
| 540 | // modulation by (1 + scale) + shift into output Y, writing zero intermediate | ||
| 541 | // tensors to memory. | ||
| 542 | 3 | static KernelFunction build_fused_layernorm_modulate_row(KernelJit& jit) { | |
| 543 | 3 | Module mod("mod_fused_layernorm_modulate_row"); | |
| 544 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | mod.add_external_symbol("rsqrtf"); |
| 545 |
11/22✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 3 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 3 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 3 times.
✗ Branch 21 not taken.
|
3 | Function* fn = mod.create_function("fused_layernorm_modulate_row", Type::void_type(), { |
| 546 | 27 | Type::ptr(), Type::ptr(), Type::ptr(), Type::ptr(), Type::ptr(), Type::ptr(), Type::i64(), Type::f32(), Type::f32() | |
| 547 | }); | ||
| 548 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | KernelBuilder kb(mod, fn); |
| 549 | |||
| 550 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* entry = kb.builder().append_block("entry"); |
| 551 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* x = kb.builder().add_block_param(entry, Type::ptr()); |
| 552 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* gamma = kb.builder().add_block_param(entry, Type::ptr()); |
| 553 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* beta = kb.builder().add_block_param(entry, Type::ptr()); |
| 554 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* scale = kb.builder().add_block_param(entry, Type::ptr()); |
| 555 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* shift = kb.builder().add_block_param(entry, Type::ptr()); |
| 556 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* y = kb.builder().add_block_param(entry, Type::ptr()); |
| 557 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* d = kb.builder().add_block_param(entry, Type::i64()); |
| 558 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* eps = kb.builder().add_block_param(entry, Type::f32()); |
| 559 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* inv_d = kb.builder().add_block_param(entry, Type::f32()); |
| 560 | |||
| 561 | // Pass 1 blocks (mean) | ||
| 562 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_vhead = kb.builder().create_block("flm_l1_vhead"); |
| 563 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_vbody = kb.builder().create_block("flm_l1_vbody"); |
| 564 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_vexit = kb.builder().create_block("flm_l1_vexit"); |
| 565 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_shead = kb.builder().create_block("flm_l1_shead"); |
| 566 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_sbody = kb.builder().create_block("flm_l1_sbody"); |
| 567 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l1_exit = kb.builder().create_block("flm_l1_exit"); |
| 568 | |||
| 569 | // Pass 2 blocks (variance) | ||
| 570 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_vhead = kb.builder().create_block("flm_l2_vhead"); |
| 571 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_vbody = kb.builder().create_block("flm_l2_vbody"); |
| 572 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_vexit = kb.builder().create_block("flm_l2_vexit"); |
| 573 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_shead = kb.builder().create_block("flm_l2_shead"); |
| 574 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_sbody = kb.builder().create_block("flm_l2_sbody"); |
| 575 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l2_exit = kb.builder().create_block("flm_l2_exit"); |
| 576 | |||
| 577 | // Pass 3 blocks (fused LayerNorm + Modulate directly to Y) | ||
| 578 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l3_vhead = kb.builder().create_block("flm_l3_vhead"); |
| 579 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l3_vbody = kb.builder().create_block("flm_l3_vbody"); |
| 580 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l3_shead = kb.builder().create_block("flm_l3_shead"); |
| 581 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l3_sbody = kb.builder().create_block("flm_l3_sbody"); |
| 582 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | BasicBlock* l3_exit = kb.builder().create_block("flm_l3_exit"); |
| 583 | |||
| 584 | 3 | kb.position_at_end(entry); | |
| 585 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* zero_i64 = kb.builder().build_iconst_i64(0); |
| 586 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* one_i64 = kb.builder().build_iconst_i64(1); |
| 587 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* two_i64 = kb.builder().build_iconst_i64(2); |
| 588 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* eight_i64 = kb.builder().build_iconst_i64(8); |
| 589 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* zero_f32 = kb.builder().build_fconst_f32(0.0f); |
| 590 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* one_f32 = kb.builder().build_fconst_f32(1.0f); |
| 591 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vzero = kb.vzero(Type::f32x8()); |
| 592 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vone = kb.vbroadcast(Type::f32x8(), one_f32); |
| 593 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* mask_eight = kb.builder().build_iconst_i64(~int64_t(7)); |
| 594 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vec_d = kb.builder().build_and(d, mask_eight); |
| 595 | |||
| 596 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* has_vec = kb.builder().build_sge(d, eight_i64); |
| 597 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(has_vec, l1_vhead, {zero_i64, vzero}, l1_shead, {zero_i64, zero_f32}); |
| 598 | |||
| 599 | // Pass 1: Vector sum | ||
| 600 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_vhead); |
| 601 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv1_v = kb.builder().add_block_param(l1_vhead, Type::i64()); |
| 602 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vsum1 = kb.builder().add_block_param(l1_vhead, Type::f32x8()); |
| 603 | 3 | kb.position_at_end(l1_vhead); | |
| 604 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond1_v = kb.builder().build_slt(iv1_v, vec_d); |
| 605 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond1_v, l1_vbody, {}, l1_vexit, {iv1_v, vsum1}); |
| 606 | |||
| 607 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_vbody); |
| 608 | 3 | kb.position_at_end(l1_vbody); | |
| 609 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* byte_off1 = kb.builder().build_shl(iv1_v, two_i64); |
| 610 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* px1 = kb.builder().build_add(x, byte_off1); |
| 611 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vx1 = kb.vload_f32x8(px1); |
| 612 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_vsum1 = kb.vadd(vsum1, vx1); |
| 613 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv1_v = kb.builder().build_add(iv1_v, eight_i64); |
| 614 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l1_vhead, {next_iv1_v, next_vsum1}); |
| 615 | |||
| 616 | // Pass 1: Vector exit -> horizontal sum | ||
| 617 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_vexit); |
| 618 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* exit_iv1 = kb.builder().add_block_param(l1_vexit, Type::i64()); |
| 619 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* exit_vsum1 = kb.builder().add_block_param(l1_vexit, Type::f32x8()); |
| 620 | 3 | kb.position_at_end(l1_vexit); | |
| 621 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* init_sum1 = reduce_vsum8(kb, y, exit_vsum1); |
| 622 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l1_shead, {exit_iv1, init_sum1}); |
| 623 | |||
| 624 | // Pass 1: Scalar remainder | ||
| 625 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_shead); |
| 626 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv1_s = kb.builder().add_block_param(l1_shead, Type::i64()); |
| 627 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* sum1 = kb.builder().add_block_param(l1_shead, Type::f32()); |
| 628 | 3 | kb.position_at_end(l1_shead); | |
| 629 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond1_s = kb.builder().build_slt(iv1_s, d); |
| 630 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond1_s, l1_sbody, {}, l1_exit, {sum1}); |
| 631 | |||
| 632 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_sbody); |
| 633 | 3 | kb.position_at_end(l1_sbody); | |
| 634 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* xi1 = kb.load_f32_indexed(x, iv1_s, 4, 0); |
| 635 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_sum1 = kb.add(sum1, xi1); |
| 636 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv1_s = kb.builder().build_add(iv1_s, one_i64); |
| 637 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l1_shead, {next_iv1_s, next_sum1}); |
| 638 | |||
| 639 | // Pass 1: Mean computed -> enter Pass 2 | ||
| 640 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l1_exit); |
| 641 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* final_sum1 = kb.builder().add_block_param(l1_exit, Type::f32()); |
| 642 | 3 | kb.position_at_end(l1_exit); | |
| 643 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* mean = kb.mul(final_sum1, inv_d); |
| 644 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vmean = kb.vbroadcast(Type::f32x8(), mean); |
| 645 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(has_vec, l2_vhead, {zero_i64, vzero, mean, vmean}, l2_shead, {zero_i64, zero_f32, mean}); |
| 646 | |||
| 647 | // Pass 2: Vector sum of squared deviations | ||
| 648 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_vhead); |
| 649 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv2_v = kb.builder().add_block_param(l2_vhead, Type::i64()); |
| 650 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vsum2 = kb.builder().add_block_param(l2_vhead, Type::f32x8()); |
| 651 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* m2_scalar = kb.builder().add_block_param(l2_vhead, Type::f32()); |
| 652 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vm2 = kb.builder().add_block_param(l2_vhead, Type::f32x8()); |
| 653 | 3 | kb.position_at_end(l2_vhead); | |
| 654 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond2_v = kb.builder().build_slt(iv2_v, vec_d); |
| 655 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond2_v, l2_vbody, {}, l2_vexit, {iv2_v, vsum2, m2_scalar}); |
| 656 | |||
| 657 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_vbody); |
| 658 | 3 | kb.position_at_end(l2_vbody); | |
| 659 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* byte_off2 = kb.builder().build_shl(iv2_v, two_i64); |
| 660 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* px2 = kb.builder().build_add(x, byte_off2); |
| 661 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vx2 = kb.vload_f32x8(px2); |
| 662 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vdev = kb.vsub(vx2, vm2); |
| 663 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_vsum2 = kb.vfma(vdev, vdev, vsum2); |
| 664 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv2_v = kb.builder().build_add(iv2_v, eight_i64); |
| 665 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l2_vhead, {next_iv2_v, next_vsum2, m2_scalar, vm2}); |
| 666 | |||
| 667 | // Pass 2: Vector exit -> horizontal sum | ||
| 668 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_vexit); |
| 669 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* exit_iv2 = kb.builder().add_block_param(l2_vexit, Type::i64()); |
| 670 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* exit_vsum2 = kb.builder().add_block_param(l2_vexit, Type::f32x8()); |
| 671 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* m2_out = kb.builder().add_block_param(l2_vexit, Type::f32()); |
| 672 | 3 | kb.position_at_end(l2_vexit); | |
| 673 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* init_sumsq = reduce_vsum8(kb, y, exit_vsum2); |
| 674 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l2_shead, {exit_iv2, init_sumsq, m2_out}); |
| 675 | |||
| 676 | // Pass 2: Scalar remainder | ||
| 677 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_shead); |
| 678 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv2_s = kb.builder().add_block_param(l2_shead, Type::i64()); |
| 679 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* sumsq = kb.builder().add_block_param(l2_shead, Type::f32()); |
| 680 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* m2_s = kb.builder().add_block_param(l2_shead, Type::f32()); |
| 681 | 3 | kb.position_at_end(l2_shead); | |
| 682 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond2_s = kb.builder().build_slt(iv2_s, d); |
| 683 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond2_s, l2_sbody, {}, l2_exit, {sumsq, m2_s}); |
| 684 | |||
| 685 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_sbody); |
| 686 | 3 | kb.position_at_end(l2_sbody); | |
| 687 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* xi2 = kb.load_f32_indexed(x, iv2_s, 4, 0); |
| 688 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* diff2 = kb.sub(xi2, m2_s); |
| 689 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* diff_sq2 = kb.mul(diff2, diff2); |
| 690 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_sumsq = kb.add(sumsq, diff_sq2); |
| 691 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv2_s = kb.builder().build_add(iv2_s, one_i64); |
| 692 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l2_shead, {next_iv2_s, next_sumsq, m2_s}); |
| 693 | |||
| 694 | // Pass 2 exit -> compute rstd | ||
| 695 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l2_exit); |
| 696 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* final_sumsq = kb.builder().add_block_param(l2_exit, Type::f32()); |
| 697 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* final_mean = kb.builder().add_block_param(l2_exit, Type::f32()); |
| 698 | 3 | kb.position_at_end(l2_exit); | |
| 699 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* var = kb.mul(final_sumsq, inv_d); |
| 700 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* var_eps = kb.add(var, eps); |
| 701 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | Value* rstd = kb.builder().build_call("rsqrtf", Type::f32(), {var_eps}); |
| 702 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vmean3 = kb.vbroadcast(Type::f32x8(), final_mean); |
| 703 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vrstd3 = kb.vbroadcast(Type::f32x8(), rstd); |
| 704 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l3_vhead, {zero_i64, final_mean, rstd, vmean3, vrstd3}); |
| 705 | |||
| 706 | // Pass 3: Vector fused LayerNorm + AdaLN Modulate directly into registers, zero intermediate RAM | ||
| 707 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l3_vhead); |
| 708 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv3_v = kb.builder().add_block_param(l3_vhead, Type::i64()); |
| 709 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* m3_s = kb.builder().add_block_param(l3_vhead, Type::f32()); |
| 710 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* r3_s = kb.builder().add_block_param(l3_vhead, Type::f32()); |
| 711 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vm3 = kb.builder().add_block_param(l3_vhead, Type::f32x8()); |
| 712 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vr3 = kb.builder().add_block_param(l3_vhead, Type::f32x8()); |
| 713 | 3 | kb.position_at_end(l3_vhead); | |
| 714 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond3_v = kb.builder().build_slt(iv3_v, vec_d); |
| 715 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond3_v, l3_vbody, {}, l3_shead, {iv3_v, m3_s, r3_s}); |
| 716 | |||
| 717 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l3_vbody); |
| 718 | 3 | kb.position_at_end(l3_vbody); | |
| 719 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* byte_off3 = kb.builder().build_shl(iv3_v, two_i64); |
| 720 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* px3 = kb.builder().build_add(x, byte_off3); |
| 721 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* pg3 = kb.builder().build_add(gamma, byte_off3); |
| 722 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* pb3 = kb.builder().build_add(beta, byte_off3); |
| 723 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* pscale3 = kb.builder().build_add(scale, byte_off3); |
| 724 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* pshift3 = kb.builder().build_add(shift, byte_off3); |
| 725 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* py3 = kb.builder().build_add(y, byte_off3); |
| 726 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vx3 = kb.vload_f32x8(px3); |
| 727 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vg3 = kb.vload_f32x8(pg3); |
| 728 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vb3 = kb.vload_f32x8(pb3); |
| 729 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vscale3 = kb.vload_f32x8(pscale3); |
| 730 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vshift3 = kb.vload_f32x8(pshift3); |
| 731 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vdiff3 = kb.vsub(vx3, vm3); |
| 732 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vxhat3 = kb.vmul(vdiff3, vr3); |
| 733 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* v_ln3 = kb.vfma(vg3, vxhat3, vb3); // LayerNorm in registers |
| 734 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* v_1_plus_scale = kb.vadd(vone, vscale3); |
| 735 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* vy3 = kb.vfma(v_ln3, v_1_plus_scale, vshift3); // Modulated in registers |
| 736 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.vstore_f32x8(py3, vy3); // Stored directly to destination! |
| 737 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv3_v = kb.builder().build_add(iv3_v, eight_i64); |
| 738 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l3_vhead, {next_iv3_v, m3_s, r3_s, vm3, vr3}); |
| 739 | |||
| 740 | // Pass 3: Scalar remainder | ||
| 741 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l3_shead); |
| 742 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* iv3_s = kb.builder().add_block_param(l3_shead, Type::i64()); |
| 743 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* m3_sc = kb.builder().add_block_param(l3_shead, Type::f32()); |
| 744 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* r3_sc = kb.builder().add_block_param(l3_shead, Type::f32()); |
| 745 | 3 | kb.position_at_end(l3_shead); | |
| 746 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* cond3_s = kb.builder().build_slt(iv3_s, d); |
| 747 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br_if(cond3_s, l3_sbody, l3_exit); |
| 748 | |||
| 749 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l3_sbody); |
| 750 | 3 | kb.position_at_end(l3_sbody); | |
| 751 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* x3 = kb.load_f32_indexed(x, iv3_s, 4, 0); |
| 752 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* g3 = kb.load_f32_indexed(gamma, iv3_s, 4, 0); |
| 753 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* b3 = kb.load_f32_indexed(beta, iv3_s, 4, 0); |
| 754 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* s3 = kb.load_f32_indexed(scale, iv3_s, 4, 0); |
| 755 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* sh3 = kb.load_f32_indexed(shift, iv3_s, 4, 0); |
| 756 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* diff3 = kb.sub(x3, m3_sc); |
| 757 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* xhat3 = kb.mul(diff3, r3_sc); |
| 758 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* ln_val3 = kb.builder().build_fma_f32(g3, xhat3, b3); |
| 759 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* one_plus_s3 = kb.add(one_f32, s3); |
| 760 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* y3 = kb.builder().build_fma_f32(ln_val3, one_plus_s3, sh3); |
| 761 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.store_f32_indexed(y, iv3_s, y3, 4, 0); |
| 762 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | Value* next_iv3_s = kb.builder().build_add(iv3_s, one_i64); |
| 763 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_br(l3_shead, {next_iv3_s, m3_sc, r3_sc}); |
| 764 | |||
| 765 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | fn->append_block(l3_exit); |
| 766 | 3 | kb.position_at_end(l3_exit); | |
| 767 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kb.builder().build_ret_void(); |
| 768 | |||
| 769 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | return jit.compile(mod, "fused_layernorm_modulate_row"); |
| 770 | 3 | } | |
| 771 | |||
| 772 | // ── Kernel Initialization & JIT Engine Management ─────────────────────────── | ||
| 773 | 490 | static const JitFusedKernels& get_fused_kernels() { | |
| 774 |
3/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 487 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
490 | static JitFusedKernels kernels; |
| 775 | static std::once_flag init_flag; | ||
| 776 | 493 | std::call_once(init_flag, [] { | |
| 777 | try { | ||
| 778 | 3 | KernelOptions opts; | |
| 779 | 3 | opts.enable_optimizations = true; | |
| 780 | 3 | opts.enable_avx2 = true; | |
| 781 | 3 | opts.enable_fma = true; | |
| 782 | 3 | opts.enable_vectorize = true; | |
| 783 | 3 | opts.enable_unroll = true; | |
| 784 | 3 | opts.unroll_factor = 4; | |
| 785 | 3 | opts.enable_fp_reassociation = true; | |
| 786 | |||
| 787 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | KernelJit jit(opts); |
| 788 | |||
| 789 | // 1. Fused Residual RMSNorm row (Option B) | ||
| 790 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | KernelFunction k_fused_res_rms = build_fused_residual_rmsnorm_row(jit); |
| 791 | 3 | kernels.fused_residual_rmsnorm_row_fn = k_fused_res_rms.as<JitFusedKernels::FusedResidualRmsNormRowFn>(); | |
| 792 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kernels.engines.push_back(k_fused_res_rms.engine()); |
| 793 | |||
| 794 | // 2. Fused Residual LayerNorm row | ||
| 795 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | KernelFunction k_fused_res_ln = build_fused_residual_layernorm_row(jit); |
| 796 | 3 | kernels.fused_residual_layernorm_row_fn = k_fused_res_ln.as<JitFusedKernels::FusedResidualLayerNormRowFn>(); | |
| 797 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kernels.engines.push_back(k_fused_res_ln.engine()); |
| 798 | |||
| 799 | // 3. Fused LayerNorm Modulate row (Option B) | ||
| 800 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | KernelFunction k_fused_ln_mod = build_fused_layernorm_modulate_row(jit); |
| 801 | 3 | kernels.fused_layernorm_modulate_row_fn = k_fused_ln_mod.as<JitFusedKernels::FusedLayerNormModulateRowFn>(); | |
| 802 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | kernels.engines.push_back(k_fused_ln_mod.engine()); |
| 803 | |||
| 804 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
6 | kernels.available = (kernels.fused_residual_rmsnorm_row_fn != nullptr && |
| 805 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | kernels.fused_residual_layernorm_row_fn != nullptr && |
| 806 | 3 | kernels.fused_layernorm_modulate_row_fn != nullptr); | |
| 807 |
0/2✗ Branch 0 not taken.
✗ Branch 1 not taken.
|
3 | } catch (const std::exception& e) { |
| 808 | ✗ | std::cerr << "brotensor: Brass JIT fused kernels initialization failed: " << e.what() << "\n"; | |
| 809 | ✗ | kernels.available = false; | |
| 810 | ✗ | } | |
| 811 | 3 | }); | |
| 812 | 490 | return kernels; | |
| 813 | } | ||
| 814 | |||
| 815 | } // namespace | ||
| 816 | |||
| 817 | 246 | void fused_residual_rmsnorm(float* X, const float* res, const float* gamma, float eps, float* Y, int B, int D) { | |
| 818 | 246 | const auto& k = get_fused_kernels(); | |
| 819 |
2/4✓ Branch 0 taken 246 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 246 times.
|
246 | if (!k.available || k.fused_residual_rmsnorm_row_fn == nullptr) { |
| 820 | ✗ | ref::fused_residual_rmsnorm(X, res, gamma, eps, Y, B, D); | |
| 821 | ✗ | return; | |
| 822 | } | ||
| 823 | |||
| 824 | 246 | const float inv_D = 1.0f / static_cast<float>(D); | |
| 825 | |||
| 826 |
3/4✓ Branch 0 taken 185 times.
✓ Branch 1 taken 61 times.
✓ Branch 2 taken 185 times.
✗ Branch 3 not taken.
|
246 | if (B > 1 && static_cast<int64_t>(B) * D >= 262144) { |
| 827 | ✗ | detail::cpu::parallel_for(static_cast<std::size_t>(B), [&](std::size_t bi) { | |
| 828 | ✗ | const int b = static_cast<int>(bi); | |
| 829 | ✗ | float* xr = X + static_cast<std::size_t>(b) * D; | |
| 830 | ✗ | const float* rr = res + static_cast<std::size_t>(b) * D; | |
| 831 | ✗ | float* yr = Y + static_cast<std::size_t>(b) * D; | |
| 832 | ✗ | k.fused_residual_rmsnorm_row_fn(xr, rr, gamma, yr, static_cast<uint64_t>(D), eps, inv_D); | |
| 833 | ✗ | }); | |
| 834 | ✗ | } else { | |
| 835 |
2/2✓ Branch 0 taken 2753 times.
✓ Branch 1 taken 246 times.
|
2999 | for (int b = 0; b < B; ++b) { |
| 836 | 2753 | float* xr = X + static_cast<std::size_t>(b) * D; | |
| 837 | 2753 | const float* rr = res + static_cast<std::size_t>(b) * D; | |
| 838 | 2753 | float* yr = Y + static_cast<std::size_t>(b) * D; | |
| 839 | 2753 | k.fused_residual_rmsnorm_row_fn(xr, rr, gamma, yr, static_cast<uint64_t>(D), eps, inv_D); | |
| 840 | 2753 | } | |
| 841 | } | ||
| 842 | 246 | } | |
| 843 | |||
| 844 | 2 | void fused_residual_layernorm(float* X, const float* res, const float* gamma, const float* beta, | |
| 845 | float eps, float* Y, int B, int D) { | ||
| 846 | 2 | const auto& k = get_fused_kernels(); | |
| 847 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | if (!k.available || k.fused_residual_layernorm_row_fn == nullptr) { |
| 848 | ✗ | ref::fused_residual_layernorm(X, res, gamma, beta, eps, Y, B, D); | |
| 849 | ✗ | return; | |
| 850 | } | ||
| 851 | |||
| 852 | 2 | const float inv_D = 1.0f / static_cast<float>(D); | |
| 853 | |||
| 854 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | if (B > 1 && static_cast<int64_t>(B) * D >= 262144) { |
| 855 | ✗ | detail::cpu::parallel_for(static_cast<std::size_t>(B), [&](std::size_t bi) { | |
| 856 | ✗ | const int b = static_cast<int>(bi); | |
| 857 | ✗ | float* xr = X + static_cast<std::size_t>(b) * D; | |
| 858 | ✗ | const float* rr = res + static_cast<std::size_t>(b) * D; | |
| 859 | ✗ | float* yr = Y + static_cast<std::size_t>(b) * D; | |
| 860 | ✗ | k.fused_residual_layernorm_row_fn(xr, rr, gamma, beta, yr, static_cast<uint64_t>(D), eps, inv_D); | |
| 861 | ✗ | }); | |
| 862 | ✗ | } else { | |
| 863 |
2/2✓ Branch 0 taken 397 times.
✓ Branch 1 taken 2 times.
|
399 | for (int b = 0; b < B; ++b) { |
| 864 | 397 | float* xr = X + static_cast<std::size_t>(b) * D; | |
| 865 | 397 | const float* rr = res + static_cast<std::size_t>(b) * D; | |
| 866 | 397 | float* yr = Y + static_cast<std::size_t>(b) * D; | |
| 867 | 397 | k.fused_residual_layernorm_row_fn(xr, rr, gamma, beta, yr, static_cast<uint64_t>(D), eps, inv_D); | |
| 868 | 397 | } | |
| 869 | } | ||
| 870 | 2 | } | |
| 871 | |||
| 872 | 242 | void fused_layernorm_modulate(const float* X, const float* gamma, const float* beta, | |
| 873 | const float* scale, const float* shift, float eps, float* Y, int R, int D) { | ||
| 874 | 242 | const auto& k = get_fused_kernels(); | |
| 875 |
2/4✓ Branch 0 taken 242 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 242 times.
|
242 | if (!k.available || k.fused_layernorm_modulate_row_fn == nullptr) { |
| 876 | ✗ | ref::fused_layernorm_modulate(X, gamma, beta, scale, shift, eps, Y, R, D); | |
| 877 | ✗ | return; | |
| 878 | } | ||
| 879 | |||
| 880 | 242 | const float inv_D = 1.0f / static_cast<float>(D); | |
| 881 | |||
| 882 |
3/4✓ Branch 0 taken 182 times.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 182 times.
✗ Branch 3 not taken.
|
242 | if (R > 1 && static_cast<int64_t>(R) * D >= 262144) { |
| 883 | ✗ | detail::cpu::parallel_for(static_cast<std::size_t>(R), [&](std::size_t ri) { | |
| 884 | ✗ | const int r = static_cast<int>(ri); | |
| 885 | ✗ | const float* xr = X + static_cast<std::size_t>(r) * D; | |
| 886 | ✗ | float* yr = Y + static_cast<std::size_t>(r) * D; | |
| 887 | ✗ | k.fused_layernorm_modulate_row_fn(xr, gamma, beta, scale, shift, yr, static_cast<uint64_t>(D), eps, inv_D); | |
| 888 | ✗ | }); | |
| 889 | ✗ | } else { | |
| 890 |
2/2✓ Branch 0 taken 2716 times.
✓ Branch 1 taken 242 times.
|
2958 | for (int r = 0; r < R; ++r) { |
| 891 | 2716 | const float* xr = X + static_cast<std::size_t>(r) * D; | |
| 892 | 2716 | float* yr = Y + static_cast<std::size_t>(r) * D; | |
| 893 | 2716 | k.fused_layernorm_modulate_row_fn(xr, gamma, beta, scale, shift, yr, static_cast<uint64_t>(D), eps, inv_D); | |
| 894 | 2716 | } | |
| 895 | } | ||
| 896 | 242 | } | |
| 897 | |||
| 898 | } // namespace brotensor::detail::cpu::jit | ||
| 899 | |||
| 900 | #else // !BROTENSOR_HAS_BRASS_JIT | ||
| 901 | |||
| 902 | namespace brotensor::detail::cpu::jit { | ||
| 903 | |||
| 904 | void fused_residual_rmsnorm(float* X, const float* res, const float* gamma, float eps, float* Y, int B, int D) { | ||
| 905 | ref::fused_residual_rmsnorm(X, res, gamma, eps, Y, B, D); | ||
| 906 | } | ||
| 907 | void fused_residual_layernorm(float* X, const float* res, const float* gamma, const float* beta, float eps, float* Y, int B, int D) { | ||
| 908 | ref::fused_residual_layernorm(X, res, gamma, beta, eps, Y, B, D); | ||
| 909 | } | ||
| 910 | void fused_layernorm_modulate(const float* X, const float* gamma, const float* beta, | ||
| 911 | const float* scale, const float* shift, float eps, float* Y, int R, int D) { | ||
| 912 | ref::fused_layernorm_modulate(X, gamma, beta, scale, shift, eps, Y, R, D); | ||
| 913 | } | ||
| 914 | |||
| 915 | } // namespace brotensor::detail::cpu::jit | ||
| 916 | |||
| 917 | #endif // BROTENSOR_HAS_BRASS_JIT | ||
| 918 |