code wiki / (root) / nx_bert_ce_lib.nx

nx_bert_ce_lib.nx source

↩ module page · 346 lines · 17919 B

1// nx_bert_ce_lib.nx -- SOVEREIGN BERT cross-encoder (BertForSequenceClassification with one logit) composed from 2// the estate's own f32 tower: nx_safetensors_load (weights), vit_mhsa and vit_mhsa_pool (multi-head attention 3// with biases, the ViT block's kernel), nx_f32_layernorm, nx_f32_matmul_t and its pooled twin, nx_f32_gelu_vec and 4// nx_f32_tanh. The model is a LICENSED DATA ASSET (Apache-2.0, mirrored with provenance under knowledge/fetched/) 5// read by NishiLang from the first byte; nothing foreign executes. BERT differs from the ViT block already in the 6// tree in three places and only those are written here: POST-norm residuals (LayerNorm after each add), an 7// embedding layer of word + absolute position + token type followed by LayerNorm, and the pooler (tanh of a dense 8// over the [CLS] row) with the classifier. Depth, width, heads, intermediate size, position count and the LayerNorm 9// epsilon are read from the model's config.json at load, never from a constant. Search rung R0, 2026-09-14. 10// license_tier: ORIGINAL 11import "nx_syscalls.nx" 12import "nx_f32.nx" 13import "nx_f32_cvt.nx" 14import "nx_f32_div.nx" 15import "nx_f32_activations.nx" 16import "nx_f32_matmul_t.nx" 17import "nx_f32_layernorm.nx" 18import "nx_f32_gelu.nx" 19import "nx_thread_pool.nx" 20import "nx_safetensors_load.nx" 21import "nx_vit_encoder_layer.nx" 22 23// g-box slots; the caller mmaps BC_G_BYTES 24const BC_G_HID: i64 = 0 25const BC_G_LAYERS: i64 = 1 26const BC_G_HEADS: i64 = 2 27const BC_G_INTER: i64 = 3 28const BC_G_MAXPOS: i64 = 4 29const BC_G_VOCAB: i64 = 5 30const BC_G_EPS: i64 = 6 // f32 bits, from config layer_norm_eps 31const BC_G_SCALE: i64 = 7 // f32 bits, 1 / sqrt(head_dim) 32const BC_G_WEMB: i64 = 8 33const BC_G_PEMB: i64 = 9 34const BC_G_TEMB: i64 = 10 35const BC_G_ELNG: i64 = 11 36const BC_G_ELNB: i64 = 12 37const BC_G_LAYERW: i64 = 13 // *i64, BC_L_SLOTS pointers per layer 38const BC_G_POOLW: i64 = 14 39const BC_G_POOLB: i64 = 15 40const BC_G_CLSW: i64 = 16 41const BC_G_CLSB: i64 = 17 42const BC_G_LOADED: i64 = 18 43const BC_G_MISSING: i64 = 19 // *u8 name of the first tensor or field that failed, for the announce 44const BC_G_POOL: i64 = 20 // *NxThreadPool, or 0 for the serial path 45const BC_G_SLOTS: i64 = 21 46const BC_G_BYTES: i64 = 168 47// per-layer weight slots (HF BertLayer tensor set) 48const BC_L_WQ: i64 = 0 49const BC_L_BQ: i64 = 1 50const BC_L_WK: i64 = 2 51const BC_L_BK: i64 = 3 52const BC_L_WV: i64 = 4 53const BC_L_BV: i64 = 5 54const BC_L_WO: i64 = 6 55const BC_L_BO: i64 = 7 56const BC_L_LN1G: i64 = 8 57const BC_L_LN1B: i64 = 9 58const BC_L_W1: i64 = 10 59const BC_L_B1: i64 = 11 60const BC_L_W2: i64 = 12 61const BC_L_B2: i64 = 13 62const BC_L_LN2G: i64 = 14 63const BC_L_LN2B: i64 = 15 64const BC_L_SLOTS: i64 = 16 65// the longest tensor name in this family is under 70 bytes; bc_lname REFUSES a name that would not fit 66const BC_NAME_CAP: i64 = 256 67const BC_DTYPE_CAP: i64 = 16 68const BC_DECIMAL: i64 = 10 69const BC_ASCII_ZERO: i64 = 48 70const BC_ASCII_NINE: i64 = 57 71const BC_COLON: i64 = 58 72const BC_SPACE: i64 = 32 73const BC_MINUS: i64 = 45 74const BC_PLUS: i64 = 43 75const BC_DOT: i64 = 46 76const BC_LOWER_E: i64 = 101 77const BC_UPPER_E: i64 = 69 78const BC_MILLI: i64 = 1000 79const BC_MICRO: i64 = 1000000 80 81// index of the first value byte after a JSON key, or -1 82func bc_skip_to_value(buf: *u8, n: i64, key: *u8) -> i64 { 83 let p: i64 = stl_find(buf, n, 0, key) 84 if p < 0 { return 0 - 1 } 85 var i: i64 = p 86 var go: i64 = 1 87 while go == 1 { if i >= n { go = 0 } else { if buf[i] == (BC_COLON as u8) { go = 0 } else { i = i + 1 } } } 88 if i >= n { return 0 - 1 } 89 i = i + 1 90 while i < n { if buf[i] == (BC_SPACE as u8) { i = i + 1 } else { return i } } 91 return 0 - 1 92} 93 94func bc_cfg_int(buf: *u8, n: i64, key: *u8) -> i64 { 95 let i: i64 = bc_skip_to_value(buf, n, key) 96 if i < 0 { return 0 - 1 } 97 let e: *i64 = sys_mmap(8) as *i64 98 return stl_parse_int(buf, i, e) 99} 100 101func bc_is_digit(c: i64) -> i64 { if c >= BC_ASCII_ZERO { if c <= BC_ASCII_NINE { return 1 } } return 0 } 102 103// a decimal with optional fraction and exponent (1e-12, 1e-05, 0.00001) as f32 bits, or -1 when absent 104func bc_cfg_f32(buf: *u8, n: i64, key: *u8) -> i64 { 105 var i: i64 = bc_skip_to_value(buf, n, key) 106 if i < 0 { return 0 - 1 } 107 var mant: i64 = 0 108 var fracd: i64 = 0 109 var exp10: i64 = 0 110 while bc_is_digit(buf[i] as i64) == 1 { mant = mant * BC_DECIMAL + ((buf[i] as i64) - BC_ASCII_ZERO); i = i + 1 } 111 if buf[i] == (BC_DOT as u8) { 112 i = i + 1 113 while bc_is_digit(buf[i] as i64) == 1 { mant = mant * BC_DECIMAL + ((buf[i] as i64) - BC_ASCII_ZERO); fracd = fracd + 1; i = i + 1 } 114 } 115 var ise: i64 = 0 116 if buf[i] == (BC_LOWER_E as u8) { ise = 1 } 117 if buf[i] == (BC_UPPER_E as u8) { ise = 1 } 118 if ise == 1 { 119 i = i + 1 120 var neg: i64 = 0 121 if buf[i] == (BC_MINUS as u8) { neg = 1; i = i + 1 } 122 if buf[i] == (BC_PLUS as u8) { i = i + 1 } 123 var ex: i64 = 0 124 while bc_is_digit(buf[i] as i64) == 1 { ex = ex * BC_DECIMAL + ((buf[i] as i64) - BC_ASCII_ZERO); i = i + 1 } 125 if neg == 1 { ex = 0 - ex } 126 exp10 = ex 127 } 128 var k: i64 = exp10 - fracd 129 var f: i64 = nx_i32_to_f32(mant) 130 let ten: i64 = nx_i32_to_f32(BC_DECIMAL) 131 while k < 0 { f = nx_f32_div(f, ten); k = k + 1 } 132 while k > 0 { f = nx_f32_mul(f, ten); k = k - 1 } 133 return f 134} 135 136// one tensor into a fresh i64-per-element buffer; 0 when absent or of an unreadable dtype 137func bc_tensor(buf: *u8, hlen: i64, dstart: i64, name: *u8, dt: *u8, offs: *i64) -> i64 { 138 if stl_tensor(buf, hlen, name, dt, offs) == 0 { return 0 } 139 let nbytes: i64 = offs[1] - offs[0] 140 if nbytes <= 0 { return 0 } 141 // one i64 per element; the smallest element the loader reads is 2 bytes, so 4x the byte count covers every dtype 142 let out: *i64 = sys_mmap(nbytes * 4) as *i64 143 if stl_read_f32(buf, dstart, offs, dt, out) < 0 { return 0 } 144 return out as i64 145} 146 147func bc_cat(dst: *u8, pos: i64, s: *u8) -> i64 { 148 var i: i64 = 0 149 while s[i] != (0 as u8) { if pos + i < BC_NAME_CAP - 1 { dst[pos + i] = s[i] } i = i + 1 } 150 return pos + i 151} 152 153// bert.encoder.layer.<l>.<suffix> into scr; 1 if it fit, 0 if it would overflow the scratch 154func bc_lname(scr: *u8, layer: i64, suffix: *u8) -> i64 { 155 var p: i64 = bc_cat(scr, 0, "bert.encoder.layer." as *u8) 156 let tens: i64 = layer / BC_DECIMAL 157 if tens > 0 { if p < BC_NAME_CAP - 1 { scr[p] = (tens + BC_ASCII_ZERO) as u8 } p = p + 1 } 158 if p < BC_NAME_CAP - 1 { scr[p] = ((layer - tens * BC_DECIMAL) + BC_ASCII_ZERO) as u8 } 159 p = p + 1 160 p = bc_cat(scr, p, "." as *u8) 161 p = bc_cat(scr, p, suffix) 162 if p >= BC_NAME_CAP - 1 { return 0 } 163 scr[p] = 0 as u8 164 return 1 165} 166 167// record the failing name durably (scr is reused) and return 0 168func bc_fail(g: *i64, name: *u8) -> i64 { 169 let keep: *u8 = sys_mmap(BC_NAME_CAP) 170 var i: i64 = 0 171 while name[i] != (0 as u8) { if i < BC_NAME_CAP - 1 { keep[i] = name[i] } i = i + 1 } 172 if i > BC_NAME_CAP - 1 { i = BC_NAME_CAP - 1 } 173 keep[i] = 0 as u8 174 g[BC_G_MISSING] = keep as i64 175 g[BC_G_LOADED] = 0 176 return 0 177} 178 179// one per-layer tensor into lw[layer*BC_L_SLOTS + slot]; 1 ok, 0 failed (the name is left in scr) 180func bc_lload(lw: *i64, mb: *u8, hlen: i64, dstart: i64, scr: *u8, layer: i64, slot: i64, suffix: *u8, dt: *u8, offs: *i64) -> i64 { 181 if bc_lname(scr, layer, suffix) == 0 { return 0 } 182 let p: i64 = bc_tensor(mb, hlen, dstart, scr, dt, offs) 183 if p == 0 { return 0 } 184 lw[layer * BC_L_SLOTS + slot] = p 185 return 1 186} 187 188// load config.json + model.safetensors; 1 loaded, 0 refused with g[BC_G_MISSING] naming what was absent 189func bc_load(g: *i64, model_path: *u8, config_path: *u8) -> i64 { 190 g[BC_G_LOADED] = 0 191 g[BC_G_MISSING] = ("none" as *u8) as i64 192 let lb: *i64 = sys_mmap(8) as *i64 193 let cb: *u8 = sys_read_file(config_path, lb) 194 if lb[0] <= 0 { return bc_fail(g, "config.json" as *u8) } 195 let cn: i64 = lb[0] 196 let hid: i64 = bc_cfg_int(cb, cn, "\"hidden_size\"" as *u8) 197 let layers: i64 = bc_cfg_int(cb, cn, "\"num_hidden_layers\"" as *u8) 198 let heads: i64 = bc_cfg_int(cb, cn, "\"num_attention_heads\"" as *u8) 199 let inter: i64 = bc_cfg_int(cb, cn, "\"intermediate_size\"" as *u8) 200 let maxpos: i64 = bc_cfg_int(cb, cn, "\"max_position_embeddings\"" as *u8) 201 let vocab: i64 = bc_cfg_int(cb, cn, "\"vocab_size\"" as *u8) 202 let epsb: i64 = bc_cfg_f32(cb, cn, "\"layer_norm_eps\"" as *u8) 203 if hid < 1 { return bc_fail(g, "config hidden_size" as *u8) } 204 if layers < 1 { return bc_fail(g, "config num_hidden_layers" as *u8) } 205 if heads < 1 { return bc_fail(g, "config num_attention_heads" as *u8) } 206 if inter < 1 { return bc_fail(g, "config intermediate_size" as *u8) } 207 if maxpos < 1 { return bc_fail(g, "config max_position_embeddings" as *u8) } 208 if vocab < 1 { return bc_fail(g, "config vocab_size" as *u8) } 209 if epsb < 0 { return bc_fail(g, "config layer_norm_eps" as *u8) } 210 let hd: i64 = hid / heads 211 if hd * heads != hid { return bc_fail(g, "config hidden_size not divisible by heads" as *u8) } 212 let one: i64 = nx_i32_to_f32(1) 213 g[BC_G_HID] = hid 214 g[BC_G_LAYERS] = layers 215 g[BC_G_HEADS] = heads 216 g[BC_G_INTER] = inter 217 g[BC_G_MAXPOS] = maxpos 218 g[BC_G_VOCAB] = vocab 219 g[BC_G_EPS] = epsb 220 g[BC_G_SCALE] = nx_f32_div(one, nx_f32_sqrt(nx_i32_to_f32(hd))) 221 let mb: *u8 = sys_read_file(model_path, lb) 222 if lb[0] <= 0 { return bc_fail(g, "model.safetensors" as *u8) } 223 let hlen: i64 = stl_header_len(mb) 224 let dstart: i64 = stl_data_start(mb) 225 if hlen <= 0 { return bc_fail(g, "safetensors header" as *u8) } 226 if dstart > lb[0] { return bc_fail(g, "safetensors header" as *u8) } 227 let dt: *u8 = sys_mmap(BC_DTYPE_CAP) 228 let offs: *i64 = sys_mmap(16) as *i64 229 g[BC_G_WEMB] = bc_tensor(mb, hlen, dstart, "bert.embeddings.word_embeddings.weight" as *u8, dt, offs) 230 if g[BC_G_WEMB] == 0 { return bc_fail(g, "bert.embeddings.word_embeddings.weight" as *u8) } 231 g[BC_G_PEMB] = bc_tensor(mb, hlen, dstart, "bert.embeddings.position_embeddings.weight" as *u8, dt, offs) 232 if g[BC_G_PEMB] == 0 { return bc_fail(g, "bert.embeddings.position_embeddings.weight" as *u8) } 233 g[BC_G_TEMB] = bc_tensor(mb, hlen, dstart, "bert.embeddings.token_type_embeddings.weight" as *u8, dt, offs) 234 if g[BC_G_TEMB] == 0 { return bc_fail(g, "bert.embeddings.token_type_embeddings.weight" as *u8) } 235 g[BC_G_ELNG] = bc_tensor(mb, hlen, dstart, "bert.embeddings.LayerNorm.weight" as *u8, dt, offs) 236 if g[BC_G_ELNG] == 0 { return bc_fail(g, "bert.embeddings.LayerNorm.weight" as *u8) } 237 g[BC_G_ELNB] = bc_tensor(mb, hlen, dstart, "bert.embeddings.LayerNorm.bias" as *u8, dt, offs) 238 if g[BC_G_ELNB] == 0 { return bc_fail(g, "bert.embeddings.LayerNorm.bias" as *u8) } 239 let lw: *i64 = sys_mmap(layers * BC_L_SLOTS * 8) as *i64 240 let scr: *u8 = sys_mmap(BC_NAME_CAP) 241 var l: i64 = 0 242 while l < layers { 243 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_WQ, "attention.self.query.weight" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 244 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_BQ, "attention.self.query.bias" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 245 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_WK, "attention.self.key.weight" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 246 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_BK, "attention.self.key.bias" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 247 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_WV, "attention.self.value.weight" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 248 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_BV, "attention.self.value.bias" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 249 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_WO, "attention.output.dense.weight" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 250 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_BO, "attention.output.dense.bias" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 251 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_LN1G, "attention.output.LayerNorm.weight" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 252 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_LN1B, "attention.output.LayerNorm.bias" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 253 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_W1, "intermediate.dense.weight" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 254 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_B1, "intermediate.dense.bias" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 255 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_W2, "output.dense.weight" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 256 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_B2, "output.dense.bias" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 257 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_LN2G, "output.LayerNorm.weight" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 258 if bc_lload(lw, mb, hlen, dstart, scr, l, BC_L_LN2B, "output.LayerNorm.bias" as *u8, dt, offs) == 0 { return bc_fail(g, scr) } 259 l = l + 1 260 } 261 g[BC_G_LAYERW] = lw as i64 262 g[BC_G_POOLW] = bc_tensor(mb, hlen, dstart, "bert.pooler.dense.weight" as *u8, dt, offs) 263 if g[BC_G_POOLW] == 0 { return bc_fail(g, "bert.pooler.dense.weight" as *u8) } 264 g[BC_G_POOLB] = bc_tensor(mb, hlen, dstart, "bert.pooler.dense.bias" as *u8, dt, offs) 265 if g[BC_G_POOLB] == 0 { return bc_fail(g, "bert.pooler.dense.bias" as *u8) } 266 g[BC_G_CLSW] = bc_tensor(mb, hlen, dstart, "classifier.weight" as *u8, dt, offs) 267 if g[BC_G_CLSW] == 0 { return bc_fail(g, "classifier.weight" as *u8) } 268 g[BC_G_CLSB] = bc_tensor(mb, hlen, dstart, "classifier.bias" as *u8, dt, offs) 269 if g[BC_G_CLSB] == 0 { return bc_fail(g, "classifier.bias" as *u8) } 270 g[BC_G_LOADED] = 1 271 return 1 272} 273 274// the relevance logit (f32 bits) for a tokenised pair ids[0..T) with token types; pooled when g[BC_G_POOL] is set 275func bc_forward(g: *i64, ids: *i64, types: *i64, T: i64) -> i64 { 276 if g[BC_G_LOADED] != 1 { return 0 } 277 let D: i64 = g[BC_G_HID] 278 let L: i64 = g[BC_G_LAYERS] 279 let nh: i64 = g[BC_G_HEADS] 280 let I: i64 = g[BC_G_INTER] 281 let hd: i64 = D / nh 282 let eps: i64 = g[BC_G_EPS] 283 let scale: i64 = g[BC_G_SCALE] 284 let wemb: *i64 = g[BC_G_WEMB] as *i64 285 let pemb: *i64 = g[BC_G_PEMB] as *i64 286 let temb: *i64 = g[BC_G_TEMB] as *i64 287 let e: *i64 = sys_mmap(8 * T * D) as *i64 288 let x: *i64 = sys_mmap(8 * T * D) as *i64 289 var t: i64 = 0 290 while t < T { 291 let id: i64 = ids[t] 292 let ty: i64 = types[t] 293 var d: i64 = 0 294 while d < D { e[t * D + d] = __f32_add(__f32_add(wemb[id * D + d], pemb[t * D + d]), temb[ty * D + d]); d = d + 1 } 295 t = t + 1 296 } 297 nx_f32_layernorm(e, g[BC_G_ELNG] as *i64, g[BC_G_ELNB] as *i64, T, D, eps, x) 298 let attn: *i64 = sys_mmap(8 * T * D) as *i64 299 let h: *i64 = sys_mmap(8 * T * D) as *i64 300 let hn: *i64 = sys_mmap(8 * T * D) as *i64 301 let f1: *i64 = sys_mmap(8 * T * I) as *i64 302 let m2: *i64 = sys_mmap(8 * T * D) as *i64 303 let y: *i64 = sys_mmap(8 * T * D) as *i64 304 let lw: *i64 = g[BC_G_LAYERW] as *i64 305 let pool: *NxThreadPool = g[BC_G_POOL] as *NxThreadPool 306 let pooled: i64 = g[BC_G_POOL] 307 var l: i64 = 0 308 while l < L { 309 let b: i64 = l * BC_L_SLOTS 310 if pooled != 0 { 311 vit_mhsa_pool(pool, x, lw[b + BC_L_WQ] as *i64, lw[b + BC_L_BQ] as *i64, lw[b + BC_L_WK] as *i64, lw[b + BC_L_BK] as *i64, lw[b + BC_L_WV] as *i64, lw[b + BC_L_BV] as *i64, lw[b + BC_L_WO] as *i64, lw[b + BC_L_BO] as *i64, T, D, nh, hd, scale, attn) 312 } else { 313 vit_mhsa(x, lw[b + BC_L_WQ] as *i64, lw[b + BC_L_BQ] as *i64, lw[b + BC_L_WK] as *i64, lw[b + BC_L_BK] as *i64, lw[b + BC_L_WV] as *i64, lw[b + BC_L_BV] as *i64, lw[b + BC_L_WO] as *i64, lw[b + BC_L_BO] as *i64, T, D, nh, hd, scale, attn) 314 } 315 var i: i64 = 0 316 while i < T * D { h[i] = __f32_add(x[i], attn[i]); i = i + 1 } 317 nx_f32_layernorm(h, lw[b + BC_L_LN1G] as *i64, lw[b + BC_L_LN1B] as *i64, T, D, eps, hn) 318 if pooled != 0 { nx_f32_matmul_t_pool(pool, hn, lw[b + BC_L_W1] as *i64, f1, T, D, I) } else { nx_f32_matmul_t(hn, lw[b + BC_L_W1] as *i64, f1, T, D, I) } 319 vit_bias_add(f1, lw[b + BC_L_B1] as *i64, T, I) 320 nx_f32_gelu_vec(f1, T * I) 321 if pooled != 0 { nx_f32_matmul_t_pool(pool, f1, lw[b + BC_L_W2] as *i64, m2, T, I, D) } else { nx_f32_matmul_t(f1, lw[b + BC_L_W2] as *i64, m2, T, I, D) } 322 vit_bias_add(m2, lw[b + BC_L_B2] as *i64, T, D) 323 i = 0 324 while i < T * D { y[i] = __f32_add(hn[i], m2[i]); i = i + 1 } 325 nx_f32_layernorm(y, lw[b + BC_L_LN2G] as *i64, lw[b + BC_L_LN2B] as *i64, T, D, eps, x) 326 l = l + 1 327 } 328 // pooler over the [CLS] row (row 0 of x), then the classifier 329 let p: *i64 = sys_mmap(8 * D) as *i64 330 nx_f32_matmul_t(x, g[BC_G_POOLW] as *i64, p, 1, D, D) 331 vit_bias_add(p, g[BC_G_POOLB] as *i64, 1, D) 332 var pd: i64 = 0 333 while pd < D { p[pd] = nx_f32_tanh(p[pd]); pd = pd + 1 } 334 let lg: *i64 = sys_mmap(8) as *i64 335 nx_f32_matmul_t(p, g[BC_G_CLSW] as *i64, lg, 1, D, 1) 336 let clsb: *i64 = g[BC_G_CLSB] as *i64 337 let logit: i64 = __f32_add(lg[0], clsb[0]) 338 sys_munmap(e as *u8, 8 * T * D); sys_munmap(x as *u8, 8 * T * D); sys_munmap(attn as *u8, 8 * T * D) 339 sys_munmap(h as *u8, 8 * T * D); sys_munmap(hn as *u8, 8 * T * D); sys_munmap(f1 as *u8, 8 * T * I) 340 sys_munmap(m2 as *u8, 8 * T * D); sys_munmap(y as *u8, 8 * T * D); sys_munmap(p as *u8, 8 * D); sys_munmap(lg as *u8, 8) 341 return logit 342} 343 344// f32 bits -> integer thousandths (truncated toward zero), for printing and for ordering 345func bc_f32_milli(x: i64) -> i64 { return __f32_to_i64(__f32_mul(x, __f32_from_i64(BC_MILLI))) } 346func bc_f32_micro(x: i64) -> i64 { return __f32_to_i64(__f32_mul(x, __f32_from_i64(BC_MICRO))) }