code wiki / (root) / nx_conv2d.nx

nx_conv2d.nx

buildroot/runtime/nx_conv2d.nx

22295 B562 linesdepth 7pulls 12 transitivereach 3 importersview sourcekind tool
docsdependenciesstructsconstsfunctions

about

nx_conv2d.nx -- multi-channel 2D convolution forward pass. L3 canonical primitive. Closes the diffusion / vision-model gap: every modern image-gen architecture (VAE encoder/decoder, UNet stages, attention pre/post conv blocks, ResNet / EfficientNet classifiers) is built around Conv2D layers. Substrate had nx_winograd_conv (per-tile math) but no multi-channel composer. L4 consumers queued: nx_unet_block, nx_vae_decode, nx_resnet_block. Each composes nx_conv2d in their per-layer flow. ===== Tensor layout ============================================= Input: [N, C_in, H, W] NHWC? No -- NCHW (PyTorch/Caffe convention; canonical for the Q10 substrate). Weight: [C_out, C_in, KH, KW] KH, KW = kernel height/width. v1 hardcodes KH=KW=3. Bias: [C_out] nullable. Output: [N, C_out, H', W'] stride 1 + padding 1 -> H'=H, W'=W. Padding mode: zero-padding by (KH-1)/2 = 1 around input. Same as PyTorch default for "padding=1, stride=1". All tensors in Q10 (substrate convention). Caller is responsible for ensuring intermediate sums don't overflow i64 -- for typical dimensions (C_in <= 1024, KH*KW = 9, Q10 * Q10 = ~1e6) the accumulator stays under 1e10, plenty of i64 headroom. ===== Algorithm ================================================= v1: direct 3x3 convolution. 6 nested loops: n, c_out, h, w, c_in, k. O(N * C_out * H * W * C_in * 9) ops. v2 (queued): Winograd F(2x2, 3x3) per-tile via nx_winograd_conv (already shipped 2026-05-15). 2.25x reduction in multiplies. Plumbed by adding a `winograd` flag dispatching to a different inner loop. Per the bits-up cardinal + bounded-loop discipline.

dependencies 5 imports · 2 importers

nx_syscalls.nx nx_tier.nx nx_loop.nx nx_tensor.nx nx_thread_pool.nx nx_conv2d.nx nx_conv2d_mt_gate.nx nx_unet_block.nx

imports: nx_syscalls.nxnx_tier.nxnx_loop.nxnx_tensor.nxnx_thread_pool.nx

imported by: nx_conv2d_mt_gate.nxnx_unet_block.nx

call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown

main sys_mmap nx_t_alloc nx_dt_is_valid nx_dt_element_bytes sys_mmap ↻ nx_t_compute_strides_rowma nx_conv2d_forward nx_t_is_contiguous nx_cv2_verdict_is_valid nx_conv2d_forward_mt nx_hw_worker_count nx_hw_cpu_count sys_mmap ↻ sys_munmap nx_conv2d_forward ↻ nx_pool_new nx_hw_worker_count ↻ sys_mmap ↻ nx_chan_new sys_mmap ↻ _nx_chan_cell sys_thread_create nx_thread_spawn sys_mmap ↻ nx_thread_spawn_fn sys_mmap ↻ nx_conv2d_forward_pool nx_t_is_contiguous ↻ sys_mmap ↻ nx_pool_n_completed nx_atom_load_i64 nx_pool_submit nx_atom_faa_i64 nx_chan_send nx_chan_try_send _nx_chan_cell ↻ nx_thread_yield _pool_futex_wake_all sys_futex_wake

structs

239struct NxCv2Ctx

consts

60const NX_CV2_Q10: nx_int = 1024
61const NX_CV2_KH: nx_int = 3
62const NX_CV2_KW: nx_int = 3
63const NX_CV2_PAD: nx_int = 1 // (KH - 1) / 2
67const NX_CV2_OK: nx_int = 0
68const NX_CV2_ERR_BAD_DTYPE: nx_int = 1
69const NX_CV2_ERR_BAD_NDIM: nx_int = 2
70const NX_CV2_ERR_SHAPE_MISMATCH: nx_int = 3
71const NX_CV2_ERR_KERNEL_SIZE: nx_int = 4
72const NX_CV2_ERR_NOT_CONTIGUOUS: nx_int = 5
73const NX_CV2_ERR_POOL_WAIT: nx_int = 6
74const NX_CV2_N_VERDICTS: nx_int = 7
252const NX_CV2_CTX_BYTES: i64 = 80

functions

76func nx_cv2_verdict_is_valid(v: nx_int) -> nx_int
called by 1: main
92func nx_conv2d_forward(input: *NxTensor, weight: *NxTensor,
257func _nx_cv2_rows(cx: *NxCv2Ctx) -> i64
called by 1: _nx_cv2_task
319func _nx_cv2_task(ctx_i: i64) -> i64
calls 1: _nx_cv2_rows
329func nx_conv2d_forward_pool(pool: *NxThreadPool, input: *NxTensor,
395func nx_conv2d_forward_mt(input: *NxTensor, weight: *NxTensor,
428func main() -> i64