Базовая операция - нахождение скалярного произведения. У меня она для любой длины вектора - сперва множит остаток не кратный 4 поштучно, а затем запускает цикл умножения четверок. Для матрицы 4х4 процедура может быть укорочена, но скорости заметно это ней не прибавит. Вызывать процедуру можно на обычном C/С++ для каждого элемента произведения - там уже экономить смысла нет. В AVX/AVX2 эта процедура может быть записана короче, но я не буду ее приводить, т.к. там принцип тот же.
dot_f4_f4 PROC PUBLIC
; double dot_f4_f4( float *row1, float *row2, int length)
; SSE-procedure
; row1 = rcx
; row2 = rdx
; length = r8d
xorpd xmm0, xmm0
and r8, 0FFFFFFFFh ;length
jz short bypass_f4_f4
mov rax, r8
shl rax, 2 ;*sizeof(float)
repeat_f4_f4:
test r8, 3
jz short start_f4_f4
sub rax, 4 ;offset float[length-1]
movss xmm1, dword ptr[rcx+rax]
mulss xmm1, dword ptr[rdx+rax]
addss xmm0, xmm1
dec r8
jnb repeat_f4_f4
start_f4_f4:
mov r8, 16d
sub rax, r8
jb short sum_f4_f4
cycle_f4_f4:
movups xmm1, [rcx+rax]
movups xmm2, [rdx+rax]
mulps xmm1, xmm2
addps xmm0, xmm1
sub rax, r8
jnb cycle_f4_f4
sum_f4_f4:
movhlps xmm1, xmm0 ;low(xmm1)=high(xmm0)
addps xmm0, xmm1
movups xmm1, xmm0
shufps xmm1, xmm1, 1 ;swap(f0,f1)
addss xmm0, xmm1
cvtss2sd xmm0, xmm0
bypass_f4_f4:
ret
dot_f4_f4 ENDP