void multMatrix4fx4f(float *lMatrix, float *rMatrix, float *out) {
  float tmp[16];
  for (int i = 0; i < 4; i++) {
    for (int j = 0; j < 4; j++) {
      tmp[(i * 4) + j] = lMatrix[(i * 4) + 0] * rMatrix[(0 * 4) + j] +
                         lMatrix[(i * 4) + 1] * rMatrix[(1 * 4) + j] +
                         lMatrix[(i * 4) + 2] * rMatrix[(2 * 4) + j] +
                         lMatrix[(i * 4) + 3] * rMatrix[(3 * 4) + j];
    }
  }
  for (int i = 0; i < 16; i++) {
    out[i] = tmp[i];
  }
}


x86 assembly (clang, -O0):
<multMatrix4fx4f>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %rdx,-0x18(%rbp)
movl   $0x0,-0x64(%rbp)
cmpl   $0x4,-0x64(%rbp)
jge    1218 <multMatrix4fx4f+0x118>
movl   $0x0,-0x68(%rbp)
cmpl   $0x4,-0x68(%rbp)
jge    1205 <multMatrix4fx4f+0x105>
mov    -0x8(%rbp),%rax
mov    -0x64(%rbp),%ecx
shl    $0x2,%ecx
add    $0x0,%ecx
movslq %ecx,%rcx
movss  (%rax,%rcx,4),%xmm0
mov    -0x10(%rbp),%rax
mov    -0x68(%rbp),%ecx
add    $0x0,%ecx
movslq %ecx,%rcx
movss  (%rax,%rcx,4),%xmm2
mov    -0x8(%rbp),%rax
mov    -0x64(%rbp),%ecx
shl    $0x2,%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
movss  (%rax,%rcx,4),%xmm1
mov    -0x10(%rbp),%rax
mov    -0x68(%rbp),%ecx
add    $0x4,%ecx
movslq %ecx,%rcx
mulss  (%rax,%rcx,4),%xmm1
mulss  %xmm2,%xmm0
addss  %xmm1,%xmm0
mov    -0x8(%rbp),%rax
mov    -0x64(%rbp),%ecx
shl    $0x2,%ecx
add    $0x2,%ecx
movslq %ecx,%rcx
movss  (%rax,%rcx,4),%xmm1
mov    -0x10(%rbp),%rax
mov    -0x68(%rbp),%ecx
add    $0x8,%ecx
movslq %ecx,%rcx
movss  (%rax,%rcx,4),%xmm2
mulss  %xmm2,%xmm1
addss  %xmm0,%xmm1
mov    -0x8(%rbp),%rax
mov    -0x64(%rbp),%ecx
shl    $0x2,%ecx
add    $0x3,%ecx
movslq %ecx,%rcx
movss  (%rax,%rcx,4),%xmm0
mov    -0x10(%rbp),%rax
mov    -0x68(%rbp),%ecx
add    $0xc,%ecx
movslq %ecx,%rcx
movss  (%rax,%rcx,4),%xmm2
mulss  %xmm2,%xmm0
addss  %xmm1,%xmm0
mov    -0x64(%rbp),%eax
shl    $0x2,%eax
add    -0x68(%rbp),%eax
cltq
movss  %xmm0,-0x60(%rbp,%rax,4)
mov    -0x68(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x68(%rbp)
jmp    1128 <multMatrix4fx4f+0x28>
jmp    120a <multMatrix4fx4f+0x10a>
mov    -0x64(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x64(%rbp)
jmp    1117 <multMatrix4fx4f+0x17>
movl   $0x0,-0x6c(%rbp)
cmpl   $0x10,-0x6c(%rbp)
jge    124e <multMatrix4fx4f+0x14e>
movslq -0x6c(%rbp),%rax
movss  -0x60(%rbp,%rax,4),%xmm0
mov    -0x18(%rbp),%rax
movslq -0x6c(%rbp),%rcx
movss  %xmm0,(%rax,%rcx,4)
mov    -0x6c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x6c(%rbp)
jmp    121f <multMatrix4fx4f+0x11f>
pop    %rbp
ret

x86 assembly (clang, -O2):
<multMatrix4fx4f>:
movups (%rdi),%xmm8
movups 0x10(%rdi),%xmm0
movups 0x20(%rdi),%xmm5
movups 0x30(%rdi),%xmm6
movaps %xmm6,%xmm3
movlhps %xmm5,%xmm3
movaps %xmm8,%xmm1
unpcklps %xmm0,%xmm1
shufps $0x24,%xmm3,%xmm1
movaps %xmm5,%xmm3
unpcklps %xmm6,%xmm3
movaps %xmm0,%xmm4
shufps $0x11,%xmm8,%xmm4
shufps $0xe2,%xmm3,%xmm4
movaps %xmm6,%xmm7
unpckhpd %xmm5,%xmm7
movaps %xmm8,%xmm3
unpckhps %xmm0,%xmm3
shufps $0x24,%xmm7,%xmm3
movss  (%rsi),%xmm7
unpckhps %xmm6,%xmm5
movss  0x4(%rsi),%xmm2
shufps $0x33,%xmm8,%xmm0
movss  0x8(%rsi),%xmm6
shufps $0x0,%xmm6,%xmm6
shufps $0x0,%xmm2,%xmm2
shufps $0x0,%xmm7,%xmm7
shufps $0xe2,%xmm5,%xmm0
movss  0x10(%rsi),%xmm5
shufps $0x0,%xmm5,%xmm5
mulps  %xmm4,%xmm5
mulps  %xmm1,%xmm7
addps  %xmm5,%xmm7
movss  0x20(%rsi),%xmm5
shufps $0x0,%xmm5,%xmm5
mulps  %xmm3,%xmm5
addps  %xmm7,%xmm5
movss  0x30(%rsi),%xmm8
shufps $0x0,%xmm8,%xmm8
mulps  %xmm0,%xmm8
addps  %xmm5,%xmm8
movss  0x14(%rsi),%xmm5
shufps $0x0,%xmm5,%xmm5
mulps  %xmm4,%xmm5
mulps  %xmm1,%xmm2
addps  %xmm5,%xmm2
movss  0x24(%rsi),%xmm7
shufps $0x0,%xmm7,%xmm7
mulps  %xmm3,%xmm7
addps  %xmm2,%xmm7
movss  0x34(%rsi),%xmm5
shufps $0x0,%xmm5,%xmm5
mulps  %xmm0,%xmm5
addps  %xmm7,%xmm5
movss  0x18(%rsi),%xmm2
shufps $0x0,%xmm2,%xmm2
mulps  %xmm4,%xmm2
mulps  %xmm1,%xmm6
addps  %xmm2,%xmm6
movss  0x28(%rsi),%xmm2
shufps $0x0,%xmm2,%xmm2
mulps  %xmm3,%xmm2
addps  %xmm6,%xmm2
movss  0x38(%rsi),%xmm6
shufps $0x0,%xmm6,%xmm6
mulps  %xmm0,%xmm6
addps  %xmm2,%xmm6
movss  0x1c(%rsi),%xmm2
shufps $0x0,%xmm2,%xmm2
mulps  %xmm2,%xmm4
movss  0xc(%rsi),%xmm2
shufps $0x0,%xmm2,%xmm2
mulps  %xmm2,%xmm1
movss  0x3c(%rsi),%xmm2
shufps $0x0,%xmm2,%xmm2
addps  %xmm4,%xmm1
movss  0x2c(%rsi),%xmm4
shufps $0x0,%xmm4,%xmm4
mulps  %xmm4,%xmm3
addps  %xmm1,%xmm3
mulps  %xmm2,%xmm0
addps  %xmm3,%xmm0
movaps %xmm0,%xmm1
movlhps %xmm6,%xmm1
movaps %xmm8,%xmm2
unpcklps %xmm5,%xmm2
shufps $0x24,%xmm1,%xmm2
movaps %xmm6,%xmm1
unpcklps %xmm0,%xmm1
movaps %xmm5,%xmm3
shufps $0x11,%xmm8,%xmm3
shufps $0xe2,%xmm1,%xmm3
movaps %xmm0,%xmm1
unpckhpd %xmm6,%xmm1
movaps %xmm8,%xmm4
unpckhps %xmm5,%xmm4
shufps $0x24,%xmm1,%xmm4
unpckhps %xmm0,%xmm6
shufps $0x33,%xmm8,%xmm5
shufps $0xe2,%xmm6,%xmm5
movaps %xmm5,-0x18(%rsp)
movaps %xmm4,-0x28(%rsp)
movaps %xmm3,-0x38(%rsp)
movaps %xmm2,-0x48(%rsp)
movaps -0x18(%rsp),%xmm0
movups %xmm0,0x30(%rdx)
movaps -0x28(%rsp),%xmm0
movups %xmm0,0x20(%rdx)
movaps -0x38(%rsp),%xmm0
movups %xmm0,0x10(%rdx)
movaps -0x48(%rsp),%xmm0
movups %xmm0,(%rdx)
ret

LLVM IR (-O0):
define void @multMatrix4fx4f(float* %0, float* %1, float* %2) {
%4 = alloca float*
%5 = alloca float*
%6 = alloca float*
%7 = alloca [16 x float]
%8 = alloca i32
%9 = alloca i32
%10 = alloca i32
store float* %0, float** %4
store float* %1, float** %5
store float* %2, float** %6
store i32 0, i32* %8
br label %11
11: ; preds = %85, %3
%12 = load i32, i32* %8
%13 = icmp slt i32 %12, 4
br i1 %13, label %14, label %88
14: ; preds = %11
store i32 0, i32* %9
br label %15
15: ; preds = %81, %14
%16 = load i32, i32* %9
%17 = icmp slt i32 %16, 4
br i1 %17, label %18, label %84
18: ; preds = %15
%19 = load float*, float** %4
%20 = load i32, i32* %8
%21 = mul nsw i32 %20, 4
%22 = add nsw i32 %21, 0
%23 = sext i32 %22 to i64
%24 = getelementptr inbounds float, float* %19, i64 %23
%25 = load float, float* %24
%26 = load float*, float** %5
%27 = load i32, i32* %9
%28 = add nsw i32 0, %27
%29 = sext i32 %28 to i64
%30 = getelementptr inbounds float, float* %26, i64 %29
%31 = load float, float* %30
%32 = load float*, float** %4
%33 = load i32, i32* %8
%34 = mul nsw i32 %33, 4
%35 = add nsw i32 %34, 1
%36 = sext i32 %35 to i64
%37 = getelementptr inbounds float, float* %32, i64 %36
%38 = load float, float* %37
%39 = load float*, float** %5
%40 = load i32, i32* %9
%41 = add nsw i32 4, %40
%42 = sext i32 %41 to i64
%43 = getelementptr inbounds float, float* %39, i64 %42
%44 = load float, float* %43
%45 = fmul float %38, %44
%46 = call float @llvm.fmuladd.f32(float %25, float %31, float %45)
%47 = load float*, float** %4
%48 = load i32, i32* %8
%49 = mul nsw i32 %48, 4
%50 = add nsw i32 %49, 2
%51 = sext i32 %50 to i64
%52 = getelementptr inbounds float, float* %47, i64 %51
%53 = load float, float* %52
%54 = load float*, float** %5
%55 = load i32, i32* %9
%56 = add nsw i32 8, %55
%57 = sext i32 %56 to i64
%58 = getelementptr inbounds float, float* %54, i64 %57
%59 = load float, float* %58
%60 = call float @llvm.fmuladd.f32(float %53, float %59, float %46)
%61 = load float*, float** %4
%62 = load i32, i32* %8
%63 = mul nsw i32 %62, 4
%64 = add nsw i32 %63, 3
%65 = sext i32 %64 to i64
%66 = getelementptr inbounds float, float* %61, i64 %65
%67 = load float, float* %66
%68 = load float*, float** %5
%69 = load i32, i32* %9
%70 = add nsw i32 12, %69
%71 = sext i32 %70 to i64
%72 = getelementptr inbounds float, float* %68, i64 %71
%73 = load float, float* %72
%74 = call float @llvm.fmuladd.f32(float %67, float %73, float %60)
%75 = load i32, i32* %8
%76 = mul nsw i32 %75, 4
%77 = load i32, i32* %9
%78 = add nsw i32 %76, %77
%79 = sext i32 %78 to i64
%80 = getelementptr inbounds [16 x float], [16 x float]* %7, i64 0, i64 %79
store float %74, float* %80
br label %81
81: ; preds = %18
%82 = load i32, i32* %9
%83 = add nsw i32 %82, 1
store i32 %83, i32* %9
br label %15
84: ; preds = %15
br label %85
85: ; preds = %84
%86 = load i32, i32* %8
%87 = add nsw i32 %86, 1
store i32 %87, i32* %8
br label %11
88: ; preds = %11
store i32 0, i32* %10
br label %89
89: ; preds = %101, %88
%90 = load i32, i32* %10
%91 = icmp slt i32 %90, 16
br i1 %91, label %92, label %104
92: ; preds = %89
%93 = load i32, i32* %10
%94 = sext i32 %93 to i64
%95 = getelementptr inbounds [16 x float], [16 x float]* %7, i64 0, i64 %94
%96 = load float, float* %95
%97 = load float*, float** %6
%98 = load i32, i32* %10
%99 = sext i32 %98 to i64
%100 = getelementptr inbounds float, float* %97, i64 %99
store float %96, float* %100
br label %101
101: ; preds = %92
%102 = load i32, i32* %10
%103 = add nsw i32 %102, 1
store i32 %103, i32* %10
br label %89
104: ; preds = %89
ret void
}

LLVM IR (-O2):
define void @multMatrix4fx4f(float* nocapture %0, float* nocapture %1, float* nocapture writeonly %2) {
%4 = alloca <16 x float>
%5 = bitcast <16 x float>* %4 to i8*
%6 = getelementptr inbounds float, float* %1, i64 15
%7 = load float, float* %6
%8 = insertelement <4 x float> poison, float %7, i64 0
%9 = shufflevector <4 x float> %8, <4 x float> poison, <4 x i32> zeroinitializer
%10 = getelementptr inbounds float, float* %1, i64 11
%11 = load float, float* %10
%12 = insertelement <4 x float> poison, float %11, i64 0
%13 = shufflevector <4 x float> %12, <4 x float> poison, <4 x i32> zeroinitializer
%14 = getelementptr inbounds float, float* %1, i64 3
%15 = load float, float* %14
%16 = insertelement <4 x float> poison, float %15, i64 0
%17 = shufflevector <4 x float> %16, <4 x float> poison, <4 x i32> zeroinitializer
%18 = getelementptr inbounds float, float* %1, i64 7
%19 = load float, float* %18
%20 = insertelement <4 x float> poison, float %19, i64 0
%21 = shufflevector <4 x float> %20, <4 x float> poison, <4 x i32> zeroinitializer
%22 = getelementptr inbounds float, float* %1, i64 14
%23 = load float, float* %22
%24 = insertelement <4 x float> poison, float %23, i64 0
%25 = shufflevector <4 x float> %24, <4 x float> poison, <4 x i32> zeroinitializer
%26 = getelementptr inbounds float, float* %1, i64 10
%27 = load float, float* %26
%28 = insertelement <4 x float> poison, float %27, i64 0
%29 = shufflevector <4 x float> %28, <4 x float> poison, <4 x i32> zeroinitializer
%30 = getelementptr inbounds float, float* %1, i64 2
%31 = load float, float* %30
%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 = getelementptr inbounds float, float* %1, i64 6
%35 = load float, float* %34
%36 = insertelement <4 x float> poison, float %35, i64 0
%37 = shufflevector <4 x float> %36, <4 x float> poison, <4 x i32> zeroinitializer
%38 = getelementptr inbounds float, float* %1, i64 13
%39 = load float, float* %38
%40 = insertelement <4 x float> poison, float %39, i64 0
%41 = shufflevector <4 x float> %40, <4 x float> poison, <4 x i32> zeroinitializer
%42 = getelementptr inbounds float, float* %1, i64 9
%43 = load float, float* %42
%44 = insertelement <4 x float> poison, float %43, i64 0
%45 = shufflevector <4 x float> %44, <4 x float> poison, <4 x i32> zeroinitializer
%46 = getelementptr inbounds float, float* %1, i64 1
%47 = load float, float* %46
%48 = insertelement <4 x float> poison, float %47, i64 0
%49 = shufflevector <4 x float> %48, <4 x float> poison, <4 x i32> zeroinitializer
%50 = getelementptr inbounds float, float* %1, i64 5
%51 = load float, float* %50
%52 = insertelement <4 x float> poison, float %51, i64 0
%53 = shufflevector <4 x float> %52, <4 x float> poison, <4 x i32> zeroinitializer
%54 = getelementptr inbounds float, float* %1, i64 12
%55 = load float, float* %54
%56 = insertelement <4 x float> poison, float %55, i64 0
%57 = shufflevector <4 x float> %56, <4 x float> poison, <4 x i32> zeroinitializer
%58 = getelementptr inbounds float, float* %1, i64 8
%59 = load float, float* %58
%60 = insertelement <4 x float> poison, float %59, i64 0
%61 = shufflevector <4 x float> %60, <4 x float> poison, <4 x i32> zeroinitializer
%62 = load float, float* %1
%63 = insertelement <4 x float> poison, float %62, i64 0
%64 = shufflevector <4 x float> %63, <4 x float> poison, <4 x i32> zeroinitializer
%65 = getelementptr inbounds float, float* %1, i64 4
%66 = load float, float* %65
%67 = insertelement <4 x float> poison, float %66, i64 0
%68 = shufflevector <4 x float> %67, <4 x float> poison, <4 x i32> zeroinitializer
%69 = bitcast float* %0 to <16 x float>*
%70 = load <16 x float>, <16 x float>* %69
%71 = shufflevector <16 x float> %70, <16 x float> poison, <4 x i32> <i32 0, i32 4, i32 8, i32 12>
%72 = shufflevector <16 x float> %70, <16 x float> poison, <4 x i32> <i32 1, i32 5, i32 9, i32 13>
%73 = shufflevector <16 x float> %70, <16 x float> poison, <4 x i32> <i32 2, i32 6, i32 10, i32 14>
%74 = shufflevector <16 x float> %70, <16 x float> poison, <4 x i32> <i32 3, i32 7, i32 11, i32 15>
%75 = fmul <4 x float> %72, %68
%76 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %71, <4 x float> %64, <4 x float> %75)
%77 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %73, <4 x float> %61, <4 x float> %76)
%78 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %74, <4 x float> %57, <4 x float> %77)
%79 = fmul <4 x float> %72, %53
%80 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %71, <4 x float> %49, <4 x float> %79)
%81 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %73, <4 x float> %45, <4 x float> %80)
%82 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %74, <4 x float> %41, <4 x float> %81)
%83 = fmul <4 x float> %72, %37
%84 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %71, <4 x float> %33, <4 x float> %83)
%85 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %73, <4 x float> %29, <4 x float> %84)
%86 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %74, <4 x float> %25, <4 x float> %85)
%87 = fmul <4 x float> %72, %21
%88 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %71, <4 x float> %17, <4 x float> %87)
%89 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %73, <4 x float> %13, <4 x float> %88)
%90 = call <4 x float> @llvm.fmuladd.v4f32(<4 x float> %74, <4 x float> %9, <4 x float> %89)
%91 = shufflevector <4 x float> %78, <4 x float> %82, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
%92 = shufflevector <4 x float> %86, <4 x float> %90, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7>
%93 = shufflevector <8 x float> %91, <8 x float> %92, <16 x i32> <i32 0, i32 4, i32 8, i32 12, i32 1, i32 5, i32 9, i32 13, i32 2, i32 6, i32 10, i32 14, i32 3, i32 7, i32 11, i32 15>
store <16 x float> %93, <16 x float>* %4
%94 = bitcast float* %2 to i8*
ret void
}