void mult3(int n, double result[n][3], double rm[3][3], double a[n][3]) {
  for (int i = 0; i < n; i++)
    for (int r = 0; r < 3; r++) {
      double s = 0;
      for (int c = 0; c < 3; c++)
        s += rm[r][c] * a[i][c];
      result[i][r] = s;
    }
}


x86 assembly (clang, -O0):
<mult3>:
push   %rbp
mov    %rsp,%rbp
mov    %edi,-0x4(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %rdx,-0x18(%rbp)
mov    %rcx,-0x20(%rbp)
movl   $0x0,-0x24(%rbp)
mov    -0x24(%rbp),%eax
cmp    -0x4(%rbp),%eax
jge    11de <mult3+0xde>
movl   $0x0,-0x28(%rbp)
cmpl   $0x3,-0x28(%rbp)
jge    11cb <mult3+0xcb>
xorps  %xmm0,%xmm0
movsd  %xmm0,-0x30(%rbp)
movl   $0x0,-0x34(%rbp)
cmpl   $0x3,-0x34(%rbp)
jge    11a0 <mult3+0xa0>
mov    -0x18(%rbp),%rax
movslq -0x28(%rbp),%rcx
imul   $0x18,%rcx,%rcx
add    %rcx,%rax
movslq -0x34(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x20(%rbp),%rax
movslq -0x24(%rbp),%rcx
imul   $0x18,%rcx,%rcx
add    %rcx,%rax
movslq -0x34(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm2
movsd  -0x30(%rbp),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x30(%rbp)
mov    -0x34(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x34(%rbp)
jmp    1146 <mult3+0x46>
movsd  -0x30(%rbp),%xmm0
mov    -0x10(%rbp),%rax
movslq -0x24(%rbp),%rcx
imul   $0x18,%rcx,%rcx
add    %rcx,%rax
movslq -0x28(%rbp),%rcx
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x28(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x28(%rbp)
jmp    112d <mult3+0x2d>
jmp    11d0 <mult3+0xd0>
mov    -0x24(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x24(%rbp)
jmp    111a <mult3+0x1a>
pop    %rbp
ret

x86 assembly (clang, -O2):
<mult3>:
test   %edi,%edi
jle    1322 <mult3+0x222>
mov    %edi,%eax
cmp    $0x1,%edi
jne    1117 <mult3+0x17>
xor    %r8d,%r8d
jmp    1261 <mult3+0x161>
lea    0x0(,%rax,8),%rdi
lea    (%rdi,%rdi,2),%rdi
lea    (%rsi,%rdi,1),%r8
lea    0x48(%rdx),%r9
add    %rcx,%rdi
cmp    %rsi,%r9
seta   %r10b
cmp    %rdx,%r8
seta   %r11b
cmp    %rsi,%rdi
seta   %dil
cmp    %rcx,%r8
seta   %r9b
xor    %r8d,%r8d
test   %r11b,%r10b
jne    1261 <mult3+0x161>
and    %r9b,%dil
jne    1261 <mult3+0x161>
mov    %eax,%r8d
and    $0xfffffffe,%r8d
xor    %edi,%edi
xorpd  %xmm0,%xmm0
mov    %r8,%r9
nop
movsd  (%rdx),%xmm6
movsd  0x8(%rdx),%xmm7
movsd  0x10(%rdx),%xmm1
movsd  0x18(%rdx),%xmm5
unpcklpd %xmm6,%xmm6
movsd  (%rcx,%rdi,1),%xmm4
movsd  0x8(%rcx,%rdi,1),%xmm3
movhpd 0x18(%rcx,%rdi,1),%xmm4
movsd  0x10(%rcx,%rdi,1),%xmm2
mulpd  %xmm4,%xmm6
addpd  %xmm0,%xmm6
unpcklpd %xmm7,%xmm7
movhpd 0x20(%rcx,%rdi,1),%xmm3
mulpd  %xmm3,%xmm7
addpd  %xmm6,%xmm7
unpcklpd %xmm1,%xmm1
movhpd 0x28(%rcx,%rdi,1),%xmm2
mulpd  %xmm2,%xmm1
addpd  %xmm7,%xmm1
unpcklpd %xmm5,%xmm5
mulpd  %xmm4,%xmm5
addpd  %xmm0,%xmm5
movsd  0x20(%rdx),%xmm6
unpcklpd %xmm6,%xmm6
mulpd  %xmm3,%xmm6
addpd  %xmm5,%xmm6
movsd  0x28(%rdx),%xmm5
unpcklpd %xmm5,%xmm5
mulpd  %xmm2,%xmm5
addpd  %xmm6,%xmm5
movsd  0x30(%rdx),%xmm6
unpcklpd %xmm6,%xmm6
mulpd  %xmm4,%xmm6
addpd  %xmm0,%xmm6
movsd  0x38(%rdx),%xmm4
unpcklpd %xmm4,%xmm4
mulpd  %xmm3,%xmm4
addpd  %xmm6,%xmm4
movsd  0x40(%rdx),%xmm3
unpcklpd %xmm3,%xmm3
mulpd  %xmm2,%xmm3
addpd  %xmm4,%xmm3
movapd %xmm1,%xmm2
unpcklpd %xmm5,%xmm2
movsd  %xmm3,%xmm1
movhlps %xmm5,%xmm3
movups %xmm3,0x20(%rsi,%rdi,1)
movupd %xmm1,0x10(%rsi,%rdi,1)
movupd %xmm2,(%rsi,%rdi,1)
add    $0x30,%rdi
add    $0xfffffffffffffffe,%r9
jne    1170 <mult3+0x70>
cmp    %rax,%r8
je     1322 <mult3+0x222>
lea    (%r8,%r8,2),%rdi
lea    0x10(,%rdi,8),%rdi
sub    %r8,%rax
xorpd  %xmm0,%xmm0
cs nopw 0x0(%rax,%rax,1)
xchg   %ax,%ax
movsd  (%rdx),%xmm1
movsd  0x8(%rdx),%xmm2
mulsd  -0x10(%rcx,%rdi,1),%xmm1
addsd  %xmm0,%xmm1
mulsd  -0x8(%rcx,%rdi,1),%xmm2
addsd  %xmm1,%xmm2
movsd  0x10(%rdx),%xmm1
mulsd  (%rcx,%rdi,1),%xmm1
addsd  %xmm2,%xmm1
movsd  %xmm1,-0x10(%rsi,%rdi,1)
movsd  0x18(%rdx),%xmm1
movsd  0x20(%rdx),%xmm2
mulsd  -0x10(%rcx,%rdi,1),%xmm1
addsd  %xmm0,%xmm1
mulsd  -0x8(%rcx,%rdi,1),%xmm2
addsd  %xmm1,%xmm2
movsd  0x28(%rdx),%xmm1
mulsd  (%rcx,%rdi,1),%xmm1
addsd  %xmm2,%xmm1
movsd  %xmm1,-0x8(%rsi,%rdi,1)
movsd  0x30(%rdx),%xmm1
mulsd  -0x10(%rcx,%rdi,1),%xmm1
movsd  0x38(%rdx),%xmm2
addsd  %xmm0,%xmm1
mulsd  -0x8(%rcx,%rdi,1),%xmm2
addsd  %xmm1,%xmm2
movsd  0x40(%rdx),%xmm1
mulsd  (%rcx,%rdi,1),%xmm1
addsd  %xmm2,%xmm1
movsd  %xmm1,(%rsi,%rdi,1)
add    $0x18,%rdi
add    $0xffffffffffffffff,%rax
jne    1280 <mult3+0x180>
ret

LLVM IR (-O0):
define void @mult3(i32 %0, [3 x double]* %1, [3 x double]* %2, [3 x double]* %3) {
%5 = alloca i32
%6 = alloca [3 x double]*
%7 = alloca [3 x double]*
%8 = alloca [3 x double]*
%9 = alloca i32
%10 = alloca i32
%11 = alloca double
%12 = alloca i32
store i32 %0, i32* %5
store [3 x double]* %1, [3 x double]** %6
store [3 x double]* %2, [3 x double]** %7
store [3 x double]* %3, [3 x double]** %8
%13 = load i32, i32* %5
%14 = zext i32 %13 to i64
%15 = load i32, i32* %5
%16 = zext i32 %15 to i64
store i32 0, i32* %9
br label %17
17: ; preds = %64, %4
%18 = load i32, i32* %9
%19 = load i32, i32* %5
%20 = icmp slt i32 %18, %19
br i1 %20, label %21, label %67
21: ; preds = %17
store i32 0, i32* %10
br label %22
22: ; preds = %60, %21
%23 = load i32, i32* %10
%24 = icmp slt i32 %23, 3
br i1 %24, label %25, label %63
25: ; preds = %22
store double 0.000000e+00, double* %11
store i32 0, i32* %12
br label %26
26: ; preds = %48, %25
%27 = load i32, i32* %12
%28 = icmp slt i32 %27, 3
br i1 %28, label %29, label %51
29: ; preds = %26
%30 = load [3 x double]*, [3 x double]** %7
%31 = load i32, i32* %10
%32 = sext i32 %31 to i64
%33 = getelementptr inbounds [3 x double], [3 x double]* %30, i64 %32
%34 = load i32, i32* %12
%35 = sext i32 %34 to i64
%36 = getelementptr inbounds [3 x double], [3 x double]* %33, i64 0, i64 %35
%37 = load double, double* %36
%38 = load [3 x double]*, [3 x double]** %8
%39 = load i32, i32* %9
%40 = sext i32 %39 to i64
%41 = getelementptr inbounds [3 x double], [3 x double]* %38, i64 %40
%42 = load i32, i32* %12
%43 = sext i32 %42 to i64
%44 = getelementptr inbounds [3 x double], [3 x double]* %41, i64 0, i64 %43
%45 = load double, double* %44
%46 = load double, double* %11
%47 = call double @llvm.fmuladd.f64(double %37, double %45, double %46)
store double %47, double* %11
br label %48
48: ; preds = %29
%49 = load i32, i32* %12
%50 = add nsw i32 %49, 1
store i32 %50, i32* %12
br label %26
51: ; preds = %26
%52 = load double, double* %11
%53 = load [3 x double]*, [3 x double]** %6
%54 = load i32, i32* %9
%55 = sext i32 %54 to i64
%56 = getelementptr inbounds [3 x double], [3 x double]* %53, i64 %55
%57 = load i32, i32* %10
%58 = sext i32 %57 to i64
%59 = getelementptr inbounds [3 x double], [3 x double]* %56, i64 0, i64 %58
store double %52, double* %59
br label %60
60: ; preds = %51
%61 = load i32, i32* %10
%62 = add nsw i32 %61, 1
store i32 %62, i32* %10
br label %22
63: ; preds = %22
br label %64
64: ; preds = %63
%65 = load i32, i32* %9
%66 = add nsw i32 %65, 1
store i32 %66, i32* %9
br label %17
67: ; preds = %17
ret void
}

LLVM IR (-O2):
define void @mult3(i32 %0, [3 x double]* nocapture writeonly %1, [3 x double]* nocapture %2, [3 x double]* nocapture %3) {
%5 = icmp sgt i32 %0, 0
br i1 %5, label %6, label %164
6: ; preds = %4
%7 = getelementptr inbounds [3 x double], [3 x double]* %2, i64 2, i64 0
%8 = zext i32 %0 to i64
%9 = getelementptr inbounds [3 x double], [3 x double]* %2, i64 0, i64 0
%10 = getelementptr inbounds [3 x double], [3 x double]* %2, i64 0, i64 1
%11 = getelementptr inbounds [3 x double], [3 x double]* %2, i64 0, i64 2
%12 = getelementptr inbounds [3 x double], [3 x double]* %2, i64 1, i64 0
%13 = getelementptr inbounds [3 x double], [3 x double]* %2, i64 1, i64 1
%14 = getelementptr inbounds [3 x double], [3 x double]* %2, i64 1, i64 2
%15 = getelementptr inbounds [3 x double], [3 x double]* %2, i64 2, i64 1
%16 = getelementptr inbounds [3 x double], [3 x double]* %2, i64 2, i64 2
%17 = icmp eq i32 %0, 1
br i1 %17, label %125, label %18
18: ; preds = %6
%19 = getelementptr [3 x double], [3 x double]* %1, i64 %8, i64 0
%20 = getelementptr [3 x double], [3 x double]* %2, i64 3, i64 0
%21 = getelementptr [3 x double], [3 x double]* %3, i64 %8, i64 0
%22 = bitcast double* %20 to [3 x double]*
%23 = icmp ugt [3 x double]* %22, %1
%24 = bitcast double* %19 to [3 x double]*
%25 = icmp ugt [3 x double]* %24, %2
%26 = and i1 %23, %25
%27 = bitcast double* %21 to [3 x double]*
%28 = icmp ugt [3 x double]* %27, %1
%29 = bitcast double* %19 to [3 x double]*
%30 = icmp ugt [3 x double]* %29, %3
%31 = and i1 %28, %30
%32 = or i1 %26, %31
br i1 %32, label %125, label %33
33: ; preds = %18
%34 = and i64 %8, 4294967294
br label %35
35: ; preds = %35, %33
%36 = phi i64 [ 0, %33 ], [ %121, %35 ]
%37 = or i64 %36, 1
%38 = load double, double* %9
%39 = insertelement <2 x double> poison, double %38, i64 0
%40 = shufflevector <2 x double> %39, <2 x double> poison, <2 x i32> zeroinitializer
%41 = getelementptr inbounds [3 x double], [3 x double]* %3, i64 %36, i64 0
%42 = getelementptr inbounds [3 x double], [3 x double]* %3, i64 %37, i64 0
%43 = load double, double* %41
%44 = load double, double* %42
%45 = insertelement <2 x double> poison, double %43, i64 0
%46 = insertelement <2 x double> %45, double %44, i64 1
%47 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %40, <2 x double> %46, <2 x double> zeroinitializer)
%48 = load double, double* %10
%49 = insertelement <2 x double> poison, double %48, i64 0
%50 = shufflevector <2 x double> %49, <2 x double> poison, <2 x i32> zeroinitializer
%51 = getelementptr inbounds [3 x double], [3 x double]* %3, i64 %36, i64 1
%52 = getelementptr inbounds [3 x double], [3 x double]* %3, i64 %37, i64 1
%53 = load double, double* %51
%54 = load double, double* %52
%55 = insertelement <2 x double> poison, double %53, i64 0
%56 = insertelement <2 x double> %55, double %54, i64 1
%57 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %50, <2 x double> %56, <2 x double> %47)
%58 = load double, double* %11
%59 = insertelement <2 x double> poison, double %58, i64 0
%60 = shufflevector <2 x double> %59, <2 x double> poison, <2 x i32> zeroinitializer
%61 = getelementptr inbounds [3 x double], [3 x double]* %3, i64 %36, i64 2
%62 = getelementptr inbounds [3 x double], [3 x double]* %3, i64 %37, i64 2
%63 = load double, double* %61
%64 = load double, double* %62
%65 = insertelement <2 x double> poison, double %63, i64 0
%66 = insertelement <2 x double> %65, double %64, i64 1
%67 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %60, <2 x double> %66, <2 x double> %57)
%68 = load double, double* %12
%69 = insertelement <2 x double> poison, double %68, i64 0
%70 = shufflevector <2 x double> %69, <2 x double> poison, <2 x i32> zeroinitializer
%71 = load double, double* %41
%72 = load double, double* %42
%73 = insertelement <2 x double> poison, double %71, i64 0
%74 = insertelement <2 x double> %73, double %72, i64 1
%75 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %70, <2 x double> %74, <2 x double> zeroinitializer)
%76 = load double, double* %13
%77 = insertelement <2 x double> poison, double %76, i64 0
%78 = shufflevector <2 x double> %77, <2 x double> poison, <2 x i32> zeroinitializer
%79 = load double, double* %51
%80 = load double, double* %52
%81 = insertelement <2 x double> poison, double %79, i64 0
%82 = insertelement <2 x double> %81, double %80, i64 1
%83 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %78, <2 x double> %82, <2 x double> %75)
%84 = load double, double* %14
%85 = insertelement <2 x double> poison, double %84, i64 0
%86 = shufflevector <2 x double> %85, <2 x double> poison, <2 x i32> zeroinitializer
%87 = load double, double* %61
%88 = load double, double* %62
%89 = insertelement <2 x double> poison, double %87, i64 0
%90 = insertelement <2 x double> %89, double %88, i64 1
%91 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %86, <2 x double> %90, <2 x double> %83)
%92 = load double, double* %7
%93 = insertelement <2 x double> poison, double %92, i64 0
%94 = shufflevector <2 x double> %93, <2 x double> poison, <2 x i32> zeroinitializer
%95 = load double, double* %41
%96 = load double, double* %42
%97 = insertelement <2 x double> poison, double %95, i64 0
%98 = insertelement <2 x double> %97, double %96, i64 1
%99 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %94, <2 x double> %98, <2 x double> zeroinitializer)
%100 = load double, double* %15
%101 = insertelement <2 x double> poison, double %100, i64 0
%102 = shufflevector <2 x double> %101, <2 x double> poison, <2 x i32> zeroinitializer
%103 = load double, double* %51
%104 = load double, double* %52
%105 = insertelement <2 x double> poison, double %103, i64 0
%106 = insertelement <2 x double> %105, double %104, i64 1
%107 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %102, <2 x double> %106, <2 x double> %99)
%108 = load double, double* %16
%109 = insertelement <2 x double> poison, double %108, i64 0
%110 = shufflevector <2 x double> %109, <2 x double> poison, <2 x i32> zeroinitializer
%111 = load double, double* %61
%112 = load double, double* %62
%113 = insertelement <2 x double> poison, double %111, i64 0
%114 = insertelement <2 x double> %113, double %112, i64 1
%115 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %110, <2 x double> %114, <2 x double> %107)
%116 = getelementptr inbounds [3 x double], [3 x double]* %1, i64 %36, i64 0
%117 = bitcast double* %116 to <6 x double>*
%118 = shufflevector <2 x double> %67, <2 x double> %91, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
%119 = shufflevector <2 x double> %115, <2 x double> poison, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
%120 = shufflevector <4 x double> %118, <4 x double> %119, <6 x i32> <i32 0, i32 2, i32 4, i32 1, i32 3, i32 5>
store <6 x double> %120, <6 x double>* %117
%121 = add nuw i64 %36, 2
%122 = icmp eq i64 %121, %34
br i1 %122, label %123, label %35
123: ; preds = %35
%124 = icmp eq i64 %34, %8
br i1 %124, label %164, label %125
125: ; preds = %18, %6, %123
%126 = phi i64 [ 0, %18 ], [ 0, %6 ], [ %34, %123 ]
br label %127
127: ; preds = %125, %127
%128 = phi i64 [ %162, %127 ], [ %126, %125 ]
%129 = load double, double* %9
%130 = getelementptr inbounds [3 x double], [3 x double]* %3, i64 %128, i64 0
%131 = load double, double* %130
%132 = tail call double @llvm.fmuladd.f64(double %129, double %131, double 0.000000e+00)
%133 = load double, double* %10
%134 = getelementptr inbounds [3 x double], [3 x double]* %3, i64 %128, i64 1
%135 = load double, double* %134
%136 = tail call double @llvm.fmuladd.f64(double %133, double %135, double %132)
%137 = load double, double* %11
%138 = getelementptr inbounds [3 x double], [3 x double]* %3, i64 %128, i64 2
%139 = load double, double* %138
%140 = tail call double @llvm.fmuladd.f64(double %137, double %139, double %136)
%141 = getelementptr inbounds [3 x double], [3 x double]* %1, i64 %128, i64 0
store double %140, double* %141
%142 = load double, double* %12
%143 = load double, double* %130
%144 = tail call double @llvm.fmuladd.f64(double %142, double %143, double 0.000000e+00)
%145 = load double, double* %13
%146 = load double, double* %134
%147 = tail call double @llvm.fmuladd.f64(double %145, double %146, double %144)
%148 = load double, double* %14
%149 = load double, double* %138
%150 = tail call double @llvm.fmuladd.f64(double %148, double %149, double %147)
%151 = getelementptr inbounds [3 x double], [3 x double]* %1, i64 %128, i64 1
store double %150, double* %151
%152 = load double, double* %7
%153 = load double, double* %130
%154 = tail call double @llvm.fmuladd.f64(double %152, double %153, double 0.000000e+00)
%155 = load double, double* %15
%156 = load double, double* %134
%157 = tail call double @llvm.fmuladd.f64(double %155, double %156, double %154)
%158 = load double, double* %16
%159 = load double, double* %138
%160 = tail call double @llvm.fmuladd.f64(double %158, double %159, double %157)
%161 = getelementptr inbounds [3 x double], [3 x double]* %1, i64 %128, i64 2
store double %160, double* %161
%162 = add nuw nsw i64 %128, 1
%163 = icmp eq i64 %162, %8
br i1 %163, label %164, label %127
164: ; preds = %127, %123, %4
ret void
}