void calc_mv(long n, float matrix[][4], float vector[], float mv[]) {
  long i;
  for (i = 0; i < n; i++)
    mv[i] = matrix[i][0] * vector[0] + matrix[i][1] * vector[1] +
            matrix[i][2] * vector[2] + matrix[i][3] * vector[3];
}


x86 assembly (clang, -O0):
<calc_mv>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %rdx,-0x18(%rbp)
mov    %rcx,-0x20(%rbp)
movq   $0x0,-0x28(%rbp)
mov    -0x28(%rbp),%rax
cmp    -0x8(%rbp),%rax
jge    11d2 <calc_mv+0xd2>
mov    -0x10(%rbp),%rax
mov    -0x28(%rbp),%rcx
shl    $0x4,%rcx
add    %rcx,%rax
movss  (%rax),%xmm0
mov    -0x18(%rbp),%rax
movss  (%rax),%xmm2
mov    -0x10(%rbp),%rax
mov    -0x28(%rbp),%rcx
shl    $0x4,%rcx
add    %rcx,%rax
movss  0x4(%rax),%xmm1
mov    -0x18(%rbp),%rax
mulss  0x4(%rax),%xmm1
mulss  %xmm2,%xmm0
addss  %xmm1,%xmm0
mov    -0x10(%rbp),%rax
mov    -0x28(%rbp),%rcx
shl    $0x4,%rcx
add    %rcx,%rax
movss  0x8(%rax),%xmm1
mov    -0x18(%rbp),%rax
movss  0x8(%rax),%xmm2
mulss  %xmm2,%xmm1
addss  %xmm0,%xmm1
mov    -0x10(%rbp),%rax
mov    -0x28(%rbp),%rcx
shl    $0x4,%rcx
add    %rcx,%rax
movss  0xc(%rax),%xmm0
mov    -0x18(%rbp),%rax
movss  0xc(%rax),%xmm2
mulss  %xmm2,%xmm0
addss  %xmm1,%xmm0
mov    -0x20(%rbp),%rax
mov    -0x28(%rbp),%rcx
movss  %xmm0,(%rax,%rcx,4)
mov    -0x28(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x28(%rbp)
jmp    111c <calc_mv+0x1c>
pop    %rbp
ret

x86 assembly (clang, -O2):
<calc_mv>:
push   %rbx
test   %rdi,%rdi
jle    1295 <calc_mv+0x195>
cmp    $0x4,%rdi
jae    1118 <calc_mv+0x18>
xor    %r8d,%r8d
jmp    1235 <calc_mv+0x135>
lea    (%rcx,%rdi,4),%r8
mov    %rdi,%rax
shl    $0x4,%rax
add    %rsi,%rax
cmp    %rcx,%rax
seta   %r11b
lea    0x10(%rdx),%rax
cmp    %rsi,%r8
seta   %bl
cmp    %rcx,%rax
seta   %r10b
cmp    %rdx,%r8
seta   %r9b
xor    %r8d,%r8d
test   %bl,%r11b
jne    1235 <calc_mv+0x135>
and    %r9b,%r10b
jne    1235 <calc_mv+0x135>
mov    %rdi,%r8
and    $0xfffffffffffffffc,%r8
movss  (%rdx),%xmm8
movss  0x4(%rdx),%xmm9
movss  0x8(%rdx),%xmm2
movss  0xc(%rdx),%xmm3
shufps $0x0,%xmm8,%xmm8
shufps $0x0,%xmm9,%xmm9
shufps $0x0,%xmm2,%xmm2
shufps $0x0,%xmm3,%xmm3
lea    0x3c(%rsi),%rax
xor    %r9d,%r9d
nop
movss  -0xc(%rax),%xmm4
movss  -0x1c(%rax),%xmm5
unpcklps %xmm4,%xmm5
movss  -0x2c(%rax),%xmm4
movss  -0x3c(%rax),%xmm6
unpcklps %xmm4,%xmm6
movlhps %xmm5,%xmm6
mulps  %xmm8,%xmm6
movss  -0x38(%rax),%xmm7
movss  -0x34(%rax),%xmm4
movss  -0x30(%rax),%xmm5
movss  -0x8(%rax),%xmm0
movss  -0x18(%rax),%xmm1
unpcklps %xmm0,%xmm1
movss  -0x28(%rax),%xmm0
unpcklps %xmm0,%xmm7
movlhps %xmm1,%xmm7
mulps  %xmm9,%xmm7
addps  %xmm6,%xmm7
movss  -0x4(%rax),%xmm0
movss  -0x14(%rax),%xmm1
unpcklps %xmm0,%xmm1
movss  -0x24(%rax),%xmm0
unpcklps %xmm0,%xmm4
movlhps %xmm1,%xmm4
mulps  %xmm2,%xmm4
addps  %xmm7,%xmm4
movss  (%rax),%xmm0
movss  -0x10(%rax),%xmm1
unpcklps %xmm0,%xmm1
movss  -0x20(%rax),%xmm0
unpcklps %xmm0,%xmm5
movlhps %xmm1,%xmm5
mulps  %xmm3,%xmm5
addps  %xmm4,%xmm5
movups %xmm5,(%rcx,%r9,4)
add    $0x4,%r9
add    $0x40,%rax
cmp    %r9,%r8
jne    1190 <calc_mv+0x90>
cmp    %rdi,%r8
je     1295 <calc_mv+0x195>
mov    %r8,%rax
shl    $0x4,%rax
add    %rsi,%rax
add    $0xc,%rax
cs nopw 0x0(%rax,%rax,1)
nopl   (%rax)
movss  -0x8(%rax),%xmm0
mulss  0x4(%rdx),%xmm0
movss  -0xc(%rax),%xmm1
mulss  (%rdx),%xmm1
addss  %xmm0,%xmm1
movss  -0x4(%rax),%xmm0
mulss  0x8(%rdx),%xmm0
addss  %xmm1,%xmm0
movss  (%rax),%xmm1
mulss  0xc(%rdx),%xmm1
addss  %xmm0,%xmm1
movss  %xmm1,(%rcx,%r8,4)
add    $0x1,%r8
add    $0x10,%rax
cmp    %r8,%rdi
jne    1250 <calc_mv+0x150>
pop    %rbx
ret

LLVM IR (-O0):
define void @calc_mv(i64 %0, [4 x float]* %1, float* %2, float* %3) {
%5 = alloca i64
%6 = alloca [4 x float]*
%7 = alloca float*
%8 = alloca float*
%9 = alloca i64
store i64 %0, i64* %5
store [4 x float]* %1, [4 x float]** %6
store float* %2, float** %7
store float* %3, float** %8
store i64 0, i64* %9
br label %10
10: ; preds = %54, %4
%11 = load i64, i64* %9
%12 = load i64, i64* %5
%13 = icmp slt i64 %11, %12
br i1 %13, label %14, label %57
14: ; preds = %10
%15 = load [4 x float]*, [4 x float]** %6
%16 = load i64, i64* %9
%17 = getelementptr inbounds [4 x float], [4 x float]* %15, i64 %16
%18 = getelementptr inbounds [4 x float], [4 x float]* %17, i64 0, i64 0
%19 = load float, float* %18
%20 = load float*, float** %7
%21 = getelementptr inbounds float, float* %20, i64 0
%22 = load float, float* %21
%23 = load [4 x float]*, [4 x float]** %6
%24 = load i64, i64* %9
%25 = getelementptr inbounds [4 x float], [4 x float]* %23, i64 %24
%26 = getelementptr inbounds [4 x float], [4 x float]* %25, i64 0, i64 1
%27 = load float, float* %26
%28 = load float*, float** %7
%29 = getelementptr inbounds float, float* %28, i64 1
%30 = load float, float* %29
%31 = fmul float %27, %30
%32 = call float @llvm.fmuladd.f32(float %19, float %22, float %31)
%33 = load [4 x float]*, [4 x float]** %6
%34 = load i64, i64* %9
%35 = getelementptr inbounds [4 x float], [4 x float]* %33, i64 %34
%36 = getelementptr inbounds [4 x float], [4 x float]* %35, i64 0, i64 2
%37 = load float, float* %36
%38 = load float*, float** %7
%39 = getelementptr inbounds float, float* %38, i64 2
%40 = load float, float* %39
%41 = call float @llvm.fmuladd.f32(float %37, float %40, float %32)
%42 = load [4 x float]*, [4 x float]** %6
%43 = load i64, i64* %9
%44 = getelementptr inbounds [4 x float], [4 x float]* %42, i64 %43
%45 = getelementptr inbounds [4 x float], [4 x float]* %44, i64 0, i64 3
%46 = load float, float* %45
%47 = load float*, float** %7
%48 = getelementptr inbounds float, float* %47, i64 3
%49 = load float, float* %48
%50 = call float @llvm.fmuladd.f32(float %46, float %49, float %41)
%51 = load float*, float** %8
%52 = load i64, i64* %9
%53 = getelementptr inbounds float, float* %51, i64 %52
store float %50, float* %53
br label %54
54: ; preds = %14
%55 = load i64, i64* %9
%56 = add nsw i64 %55, 1
store i64 %56, i64* %9
br label %10
57: ; preds = %10
ret void
}

LLVM IR (-O2):
define void @calc_mv(i64 %0, [4 x float]* nocapture %1, float* nocapture %2, float* nocapture writeonly %3) {
%5 = icmp sgt i64 %0, 0
br i1 %5, label %6, label %123
6: ; preds = %4
%7 = getelementptr inbounds float, float* %2, i64 1
%8 = getelementptr inbounds float, float* %2, i64 2
%9 = getelementptr inbounds float, float* %2, i64 3
%10 = icmp ult i64 %0, 4
br i1 %10, label %100, label %11
11: ; preds = %6
%12 = getelementptr float, float* %3, i64 %0
%13 = getelementptr [4 x float], [4 x float]* %1, i64 %0, i64 0
%14 = getelementptr float, float* %2, i64 4
%15 = icmp ugt float* %13, %3
%16 = bitcast float* %12 to [4 x float]*
%17 = icmp ugt [4 x float]* %16, %1
%18 = and i1 %15, %17
%19 = icmp ugt float* %14, %3
%20 = icmp ugt float* %12, %2
%21 = and i1 %19, %20
%22 = or i1 %18, %21
br i1 %22, label %100, label %23
23: ; preds = %11
%24 = and i64 %0, -4
%25 = load float, float* %2
%26 = insertelement <4 x float> poison, float %25, i64 0
%27 = shufflevector <4 x float> %26, <4 x float> poison, <4 x i32> zeroinitializer
%28 = load float, float* %7
%29 = insertelement <4 x float> poison, float %28, i64 0
%30 = shufflevector <4 x float> %29, <4 x float> poison, <4 x i32> zeroinitializer
%31 = load float, float* %8
%32 = insertelement <4 x float> poison, float %31, i64 0
%33 = shufflevector <4 x float> %32, <4 x float> poison, <4 x i32> zeroinitializer
%34 = load float, float* %9
%35 = insertelement <4 x float> poison, float %34, i64 0
%36 = shufflevector <4 x float> %35, <4 x float> poison, <4 x i32> zeroinitializer
br label %37
37: ; preds = %37, %23
%38 = phi i64 [ 0, %23 ], [ %96, %37 ]
%39 = or i64 %38, 1
%40 = or i64 %38, 2
%41 = or i64 %38, 3
%42 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %38, i64 0
%43 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %39, i64 0
%44 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %40, i64 0
%45 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %41, i64 0
%46 = load float, float* %42
%47 = load float, float* %43
%48 = load float, float* %44
%49 = load float, float* %45
%50 = insertelement <4 x float> poison, float %46, i64 0
%51 = insertelement <4 x float> %50, float %47, i64 1
%52 = insertelement <4 x float> %51, float %48, i64 2
%53 = insertelement <4 x float> %52, float %49, i64 3
%54 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %38, i64 1
%55 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %39, i64 1
%56 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %40, i64 1
%57 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %41, i64 1
%58 = load float, float* %54
%59 = load float, float* %55
%60 = load float, float* %56
%61 = load float, float* %57
%62 = insertelement <4 x float> poison, float %58, i64 0
%63 = insertelement <4 x float> %62, float %59, i64 1
%64 = insertelement <4 x float> %63, float %60, i64 2
%65 = insertelement <4 x float> %64, float %61, i64 3
%66 = fmul <4 x float> %65, %30
%67 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %53, <4 x float> %27, <4 x float> %66)
%68 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %38, i64 2
%69 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %39, i64 2
%70 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %40, i64 2
%71 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %41, i64 2
%72 = load float, float* %68
%73 = load float, float* %69
%74 = load float, float* %70
%75 = load float, float* %71
%76 = insertelement <4 x float> poison, float %72, i64 0
%77 = insertelement <4 x float> %76, float %73, i64 1
%78 = insertelement <4 x float> %77, float %74, i64 2
%79 = insertelement <4 x float> %78, float %75, i64 3
%80 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %79, <4 x float> %33, <4 x float> %67)
%81 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %38, i64 3
%82 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %39, i64 3
%83 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %40, i64 3
%84 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %41, i64 3
%85 = load float, float* %81
%86 = load float, float* %82
%87 = load float, float* %83
%88 = load float, float* %84
%89 = insertelement <4 x float> poison, float %85, i64 0
%90 = insertelement <4 x float> %89, float %86, i64 1
%91 = insertelement <4 x float> %90, float %87, i64 2
%92 = insertelement <4 x float> %91, float %88, i64 3
%93 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %92, <4 x float> %36, <4 x float> %80)
%94 = getelementptr inbounds float, float* %3, i64 %38
%95 = bitcast float* %94 to <4 x float>*
store <4 x float> %93, <4 x float>* %95
%96 = add nuw i64 %38, 4
%97 = icmp eq i64 %96, %24
br i1 %97, label %98, label %37
98: ; preds = %37
%99 = icmp eq i64 %24, %0
br i1 %99, label %123, label %100
100: ; preds = %11, %6, %98
%101 = phi i64 [ 0, %11 ], [ 0, %6 ], [ %24, %98 ]
br label %102
102: ; preds = %100, %102
%103 = phi i64 [ %121, %102 ], [ %101, %100 ]
%104 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %103, i64 0
%105 = load float, float* %104
%106 = load float, float* %2
%107 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %103, i64 1
%108 = load float, float* %107
%109 = load float, float* %7
%110 = fmul float %108, %109
%111 = tail call float @llvm.fmuladd.f32(float %105, float %106, float %110)
%112 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %103, i64 2
%113 = load float, float* %112
%114 = load float, float* %8
%115 = tail call float @llvm.fmuladd.f32(float %113, float %114, float %111)
%116 = getelementptr inbounds [4 x float], [4 x float]* %1, i64 %103, i64 3
%117 = load float, float* %116
%118 = load float, float* %9
%119 = tail call float @llvm.fmuladd.f32(float %117, float %118, float %115)
%120 = getelementptr inbounds float, float* %3, i64 %103
store float %119, float* %120
%121 = add nuw nsw i64 %103, 1
%122 = icmp eq i64 %121, %0
br i1 %122, label %123, label %102
123: ; preds = %102, %98, %4
ret void
}