| ; ------------------------------------------------------------ | |
| ; latent_to_waveform_nasm.asm | |
| ; | |
| ; AVX2 matrix-vector multiply: x = Ψ * z | |
| ; Ψ: N x m matrix (row-major, 8-byte doubles) | |
| ; z: m-vector | |
| ; x: N-vector (output) | |
| ; | |
| ; Calling convention (System V AMD64): | |
| ; rdi = pointer to Ψ (base address, row-major) | |
| ; rsi = pointer to z (latent vector) | |
| ; rdx = pointer to x (output buffer) | |
| ; ecx = N (number of rows) | |
| ; r8d = m (vector length, must be multiple of 8) | |
| ; | |
| ; Assemble: | |
| ; nasm -f elf64 -o latent_to_waveform_nasm.o latent_to_waveform_nasm.asm | |
| ; nasm -f macho64 -o latent_to_waveform_nasm.o latent_to_waveform_nasm.asm (macOS) | |
| ; ------------------------------------------------------------ | |
| rel | |
| .text | |
| latent_to_waveform_nasm | |
| latent_to_waveform_nasm: | |
| ; ------------------------------------------------------------ | |
| ; Prologue | |
| ; ------------------------------------------------------------ | |
| push rbp | |
| mov rbp, rsp | |
| push rbx | |
| push r12 | |
| push r13 | |
| push r14 | |
| push r15 | |
| ; r10 = Ψ base | |
| mov r10, rdi | |
| ; r11 = z pointer | |
| mov r11, rsi | |
| ; r12 = x pointer | |
| mov r12, rdx | |
| ; r13 = N | |
| mov r13d, ecx | |
| ; r14 = m | |
| mov r14d, r8d | |
| ; r15 = row index | |
| xor r15d, r15d | |
| .row_loop: | |
| cmp r15d, r13d | |
| jge .row_done | |
| ; rdx = &Ψ[i, 0] | |
| mov rbx, r14 | |
| imul rbx, rbx, 8 ; m * sizeof(double) | |
| imul rbx, rbx, r15 ; i * (m * 8) | |
| lea rdx, [r10 + rbx] ; base + offset | |
| ; Clear accumulators | |
| vxorpd ymm0, ymm0, ymm0 | |
| vxorpd ymm1, ymm1, ymm1 | |
| vxorpd ymm2, ymm2, ymm2 | |
| vxorpd ymm3, ymm3, ymm3 | |
| ; Column index | |
| xor r8d, r8d | |
| .col_loop: | |
| cmp r8d, r14d | |
| jge .col_done | |
| ; Load z[j:j+8] | |
| mov rax, r11 | |
| add rax, r8 | |
| shl rax, 3 ; *8 bytes | |
| vmovupd ymm4, [rax] | |
| ; Load Ψ[i, j:j+8] | |
| mov rax, rdx | |
| add rax, r8 | |
| shl rax, 3 | |
| vmovupd ymm5, [rax] | |
| ; FMA: ymm0 += z * Ψ | |
| vfmadd231pd ymm0, ymm4, ymm5 | |
| add r8d, 8 | |
| jmp .col_loop | |
| .col_done: | |
| ; Horizontal sum of ymm0 | |
| vextractf128 xmm1, ymm0, 1 | |
| vaddpd xmm0, xmm0, xmm1 | |
| movhlps xmm2, xmm0 | |
| addsd xmm0, xmm2 | |
| ; Store x[i] | |
| movsd [r12 + r15*8], xmm0 | |
| inc r15d | |
| jmp .row_loop | |
| .row_done: | |
| ; Epilogue | |
| pop r15 | |
| pop r14 | |
| pop r13 | |
| pop r12 | |
| pop rbx | |
| pop rbp | |
| vzeroupper | |
| ret | |
| ; ------------------------------------------------------------ | |
| ; latent_to_waveform_tiled | |
| ; | |
| ; Cache-blocked version for large N, m. | |
| ; Processes tiles of TILE_M rows x TILE_N columns. | |
| ; ------------------------------------------------------------ | |
| TILE_M 8 | |
| TILE_N 256 | |
| .text | |
| latent_to_waveform_tiled | |
| latent_to_waveform_tiled: | |
| push rbp | |
| mov rbp, rsp | |
| push rbx | |
| push r12 | |
| push r13 | |
| push r14 | |
| push r15 | |
| sub rsp, 32 ; local storage | |
| mov r10, rdi ; Ψ | |
| mov r11, rsi ; z | |
| mov r12, rdx ; x | |
| mov r13d, ecx ; N | |
| mov r14d, r8d ; m | |
| ; Zero output buffer | |
| xor eax, eax | |
| mov rcx, r13 | |
| lea rdi, [r12] | |
| .zero_loop: | |
| mov qword [rdi + rax*8], 0 | |
| inc rax | |
| dec rcx | |
| jnz .zero_loop | |
| ; Outer loop: tile over rows | |
| xor r15d, r15d ; row_tile = 0 | |
| .row_tile_loop: | |
| mov eax, r15d | |
| add eax, TILE_M | |
| cmp eax, r13d | |
| jg .row_tile_done | |
| ; Inner loop: tile over columns | |
| xor ecx, ecx ; col_tile = 0 | |
| .col_tile_loop: | |
| mov eax, ecx | |
| add eax, TILE_N | |
| cmp eax, r14d | |
| jg .col_tile_done | |
| ; Process TILE_M rows x TILE_N columns | |
| ; ... (tile body: 8 rows x 256 cols with 4 ymm accumulators) | |
| ; For brevity, delegates to untiled kernel per row | |
| mov r8d, TILE_N | |
| call .process_tile | |
| add ecx, TILE_N | |
| jmp .col_tile_loop | |
| .col_tile_done: | |
| add r15d, TILE_M | |
| jmp .row_tile_loop | |
| .row_tile_done: | |
| add rsp, 32 | |
| pop r15 | |
| pop r14 | |
| pop r13 | |
| pop r12 | |
| pop rbx | |
| pop rbp | |
| vzeroupper | |
| ret | |
| .process_tile: | |
| ; Placeholder for tile body | |
| ret | |