void mul3x3(double dst[3][3], double src[3][3]) {
  int i, j, k;
  double td[3][3];
  for (j = 0; j < 3; j++) {
    for (i = 0; i < 3; i++) {
      double tt = 0.0;
      for (k = 0; k < 3; k++)
        tt += src[j][k] * dst[k][i];
      td[j][i] = tt;
    }
  }
  for (j = 0; j < 3; j++)
    for (i = 0; i < 3; i++)
      dst[j][i] = td[j][i];
}


x86 assembly (clang, -O0):
<mul3x3>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
movl   $0x0,-0x18(%rbp)
cmpl   $0x3,-0x18(%rbp)
jge    11d5 <mul3x3+0xd5>
movl   $0x0,-0x14(%rbp)
cmpl   $0x3,-0x14(%rbp)
jge    11c2 <mul3x3+0xc2>
xorps  %xmm0,%xmm0
movsd  %xmm0,-0x78(%rbp)
movl   $0x0,-0x1c(%rbp)
cmpl   $0x3,-0x1c(%rbp)
jge    1197 <mul3x3+0x97>
mov    -0x10(%rbp),%rax
movslq -0x18(%rbp),%rcx
imul   $0x18,%rcx,%rcx
add    %rcx,%rax
movslq -0x1c(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x8(%rbp),%rax
movslq -0x1c(%rbp),%rcx
imul   $0x18,%rcx,%rcx
add    %rcx,%rax
movslq -0x14(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm2
movsd  -0x78(%rbp),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x78(%rbp)
mov    -0x1c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x1c(%rbp)
jmp    113d <mul3x3+0x3d>
movsd  -0x78(%rbp),%xmm0
movslq -0x18(%rbp),%rcx
lea    -0x70(%rbp),%rax
imul   $0x18,%rcx,%rcx
add    %rcx,%rax
movslq -0x14(%rbp),%rcx
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x14(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x14(%rbp)
jmp    1124 <mul3x3+0x24>
jmp    11c7 <mul3x3+0xc7>
mov    -0x18(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x18(%rbp)
jmp    1113 <mul3x3+0x13>
movl   $0x0,-0x18(%rbp)
cmpl   $0x3,-0x18(%rbp)
jge    1248 <mul3x3+0x148>
movl   $0x0,-0x14(%rbp)
cmpl   $0x3,-0x14(%rbp)
jge    1235 <mul3x3+0x135>
movslq -0x18(%rbp),%rcx
lea    -0x70(%rbp),%rax
imul   $0x18,%rcx,%rcx
add    %rcx,%rax
movslq -0x14(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    -0x8(%rbp),%rax
movslq -0x18(%rbp),%rcx
imul   $0x18,%rcx,%rcx
add    %rcx,%rax
movslq -0x14(%rbp),%rcx
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x14(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x14(%rbp)
jmp    11ed <mul3x3+0xed>
jmp    123a <mul3x3+0x13a>
mov    -0x18(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x18(%rbp)
jmp    11dc <mul3x3+0xdc>
pop    %rbp
ret

x86 assembly (clang, -O2):
<mul3x3>:
movupd (%rdi),%xmm5
movupd 0x18(%rdi),%xmm4
movupd 0x30(%rdi),%xmm3
movsd  0x10(%rdi),%xmm12
movsd  0x28(%rdi),%xmm11
movsd  0x40(%rdi),%xmm10
movsd  (%rsi),%xmm1
movsd  0x8(%rsi),%xmm2
movsd  0x10(%rsi),%xmm7
movapd %xmm1,%xmm0
unpcklpd %xmm1,%xmm0
mulpd  %xmm5,%xmm0
xorpd  %xmm8,%xmm8
addpd  %xmm8,%xmm0
movapd %xmm2,%xmm6
unpcklpd %xmm2,%xmm6
mulpd  %xmm4,%xmm6
addpd  %xmm0,%xmm6
movapd %xmm7,%xmm0
unpcklpd %xmm7,%xmm0
mulpd  %xmm3,%xmm0
addpd  %xmm6,%xmm0
movapd %xmm0,-0x48(%rsp)
mulsd  %xmm12,%xmm1
xorpd  %xmm9,%xmm9
addsd  %xmm9,%xmm1
mulsd  %xmm11,%xmm2
addsd  %xmm1,%xmm2
mulsd  %xmm10,%xmm7
addsd  %xmm2,%xmm7
movsd  %xmm7,-0x38(%rsp)
movsd  0x18(%rsi),%xmm0
movsd  0x20(%rsi),%xmm1
movsd  0x28(%rsi),%xmm2
movapd %xmm0,%xmm6
unpcklpd %xmm0,%xmm6
mulpd  %xmm5,%xmm6
addpd  %xmm8,%xmm6
movapd %xmm1,%xmm7
unpcklpd %xmm1,%xmm7
mulpd  %xmm4,%xmm7
addpd  %xmm6,%xmm7
movapd %xmm2,%xmm6
unpcklpd %xmm2,%xmm6
mulpd  %xmm3,%xmm6
addpd  %xmm7,%xmm6
movupd %xmm6,-0x30(%rsp)
mulsd  %xmm12,%xmm0
addsd  %xmm9,%xmm0
mulsd  %xmm11,%xmm1
addsd  %xmm0,%xmm1
mulsd  %xmm10,%xmm2
addsd  %xmm1,%xmm2
movsd  %xmm2,-0x20(%rsp)
movsd  0x30(%rsi),%xmm0
movsd  0x38(%rsi),%xmm1
movsd  0x40(%rsi),%xmm2
movapd %xmm0,%xmm6
unpcklpd %xmm0,%xmm6
mulpd  %xmm5,%xmm6
addpd  %xmm8,%xmm6
movapd %xmm1,%xmm5
unpcklpd %xmm1,%xmm5
mulpd  %xmm4,%xmm5
addpd  %xmm6,%xmm5
movapd %xmm2,%xmm4
unpcklpd %xmm2,%xmm4
mulpd  %xmm3,%xmm4
addpd  %xmm5,%xmm4
movapd %xmm4,-0x18(%rsp)
mulsd  %xmm12,%xmm0
addsd  %xmm9,%xmm0
mulsd  %xmm11,%xmm1
addsd  %xmm0,%xmm1
mulsd  %xmm10,%xmm2
addsd  %xmm1,%xmm2
movsd  %xmm2,-0x8(%rsp)
movaps -0x28(%rsp),%xmm0
movups %xmm0,0x20(%rdi)
movaps -0x38(%rsp),%xmm0
movups %xmm0,0x10(%rdi)
movaps -0x48(%rsp),%xmm0
movups %xmm0,(%rdi)
mov    -0x8(%rsp),%rax
mov    %rax,0x40(%rdi)
movaps -0x18(%rsp),%xmm0
movups %xmm0,0x30(%rdi)
ret

LLVM IR (-O0):
define void @mul3x3([3 x double]* %0, [3 x double]* %1) {
%3 = alloca [3 x double]*
%4 = alloca [3 x double]*
%5 = alloca i32
%6 = alloca i32
%7 = alloca i32
%8 = alloca [3 x [3 x double]]
%9 = alloca double
store [3 x double]* %0, [3 x double]** %3
store [3 x double]* %1, [3 x double]** %4
store i32 0, i32* %6
br label %10
10: ; preds = %55, %2
%11 = load i32, i32* %6
%12 = icmp slt i32 %11, 3
br i1 %12, label %13, label %58
13: ; preds = %10
store i32 0, i32* %5
br label %14
14: ; preds = %51, %13
%15 = load i32, i32* %5
%16 = icmp slt i32 %15, 3
br i1 %16, label %17, label %54
17: ; preds = %14
store double 0.000000e+00, double* %9
store i32 0, i32* %7
br label %18
18: ; preds = %40, %17
%19 = load i32, i32* %7
%20 = icmp slt i32 %19, 3
br i1 %20, label %21, label %43
21: ; preds = %18
%22 = load [3 x double]*, [3 x double]** %4
%23 = load i32, i32* %6
%24 = sext i32 %23 to i64
%25 = getelementptr inbounds [3 x double], [3 x double]* %22, i64 %24
%26 = load i32, i32* %7
%27 = sext i32 %26 to i64
%28 = getelementptr inbounds [3 x double], [3 x double]* %25, i64 0, i64 %27
%29 = load double, double* %28
%30 = load [3 x double]*, [3 x double]** %3
%31 = load i32, i32* %7
%32 = sext i32 %31 to i64
%33 = getelementptr inbounds [3 x double], [3 x double]* %30, i64 %32
%34 = load i32, i32* %5
%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 double, double* %9
%39 = call double @llvm.fmuladd.f64(double %29, double %37, double %38)
store double %39, double* %9
br label %40
40: ; preds = %21
%41 = load i32, i32* %7
%42 = add nsw i32 %41, 1
store i32 %42, i32* %7
br label %18
43: ; preds = %18
%44 = load double, double* %9
%45 = load i32, i32* %6
%46 = sext i32 %45 to i64
%47 = getelementptr inbounds [3 x [3 x double]], [3 x [3 x double]]* %8, i64 0, i64 %46
%48 = load i32, i32* %5
%49 = sext i32 %48 to i64
%50 = getelementptr inbounds [3 x double], [3 x double]* %47, i64 0, i64 %49
store double %44, double* %50
br label %51
51: ; preds = %43
%52 = load i32, i32* %5
%53 = add nsw i32 %52, 1
store i32 %53, i32* %5
br label %14
54: ; preds = %14
br label %55
55: ; preds = %54
%56 = load i32, i32* %6
%57 = add nsw i32 %56, 1
store i32 %57, i32* %6
br label %10
58: ; preds = %10
store i32 0, i32* %6
br label %59
59: ; preds = %85, %58
%60 = load i32, i32* %6
%61 = icmp slt i32 %60, 3
br i1 %61, label %62, label %88
62: ; preds = %59
store i32 0, i32* %5
br label %63
63: ; preds = %81, %62
%64 = load i32, i32* %5
%65 = icmp slt i32 %64, 3
br i1 %65, label %66, label %84
66: ; preds = %63
%67 = load i32, i32* %6
%68 = sext i32 %67 to i64
%69 = getelementptr inbounds [3 x [3 x double]], [3 x [3 x double]]* %8, i64 0, i64 %68
%70 = load i32, i32* %5
%71 = sext i32 %70 to i64
%72 = getelementptr inbounds [3 x double], [3 x double]* %69, i64 0, i64 %71
%73 = load double, double* %72
%74 = load [3 x double]*, [3 x double]** %3
%75 = load i32, i32* %6
%76 = sext i32 %75 to i64
%77 = getelementptr inbounds [3 x double], [3 x double]* %74, i64 %76
%78 = load i32, i32* %5
%79 = sext i32 %78 to i64
%80 = getelementptr inbounds [3 x double], [3 x double]* %77, i64 0, i64 %79
store double %73, double* %80
br label %81
81: ; preds = %66
%82 = load i32, i32* %5
%83 = add nsw i32 %82, 1
store i32 %83, i32* %5
br label %63
84: ; preds = %63
br label %85
85: ; preds = %84
%86 = load i32, i32* %6
%87 = add nsw i32 %86, 1
store i32 %87, i32* %6
br label %59
88: ; preds = %59
ret void
}

LLVM IR (-O2):
define void @mul3x3([3 x double]* nocapture %0, [3 x double]* nocapture %1) {
%3 = alloca [3 x [3 x double]]
%4 = bitcast [3 x [3 x double]]* %3 to i8*
%5 = getelementptr inbounds [3 x double], [3 x double]* %0, i64 1, i64 0
%6 = getelementptr inbounds [3 x double], [3 x double]* %0, i64 2, i64 0
%7 = bitcast [3 x double]* %0 to <2 x double>*
%8 = load <2 x double>, <2 x double>* %7
%9 = bitcast double* %5 to <2 x double>*
%10 = load <2 x double>, <2 x double>* %9
%11 = bitcast double* %6 to <2 x double>*
%12 = load <2 x double>, <2 x double>* %11
%13 = getelementptr inbounds [3 x double], [3 x double]* %0, i64 0, i64 2
%14 = load double, double* %13
%15 = getelementptr inbounds [3 x double], [3 x double]* %0, i64 1, i64 2
%16 = load double, double* %15
%17 = getelementptr inbounds [3 x double], [3 x double]* %0, i64 2, i64 2
%18 = load double, double* %17
%19 = getelementptr inbounds [3 x double], [3 x double]* %1, i64 0, i64 0
%20 = load double, double* %19
%21 = getelementptr inbounds [3 x double], [3 x double]* %1, i64 0, i64 1
%22 = load double, double* %21
%23 = getelementptr inbounds [3 x double], [3 x double]* %1, i64 0, i64 2
%24 = load double, double* %23
%25 = insertelement <2 x double> poison, double %20, i64 0
%26 = shufflevector <2 x double> %25, <2 x double> poison, <2 x i32> zeroinitializer
%27 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %26, <2 x double> %8, <2 x double> zeroinitializer)
%28 = insertelement <2 x double> poison, double %22, i64 0
%29 = shufflevector <2 x double> %28, <2 x double> poison, <2 x i32> zeroinitializer
%30 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %29, <2 x double> %10, <2 x double> %27)
%31 = insertelement <2 x double> poison, double %24, i64 0
%32 = shufflevector <2 x double> %31, <2 x double> poison, <2 x i32> zeroinitializer
%33 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %32, <2 x double> %12, <2 x double> %30)
%34 = bitcast [3 x [3 x double]]* %3 to <2 x double>*
store <2 x double> %33, <2 x double>* %34
%35 = tail call double @llvm.fmuladd.f64(double %20, double %14, double 0.000000e+00)
%36 = tail call double @llvm.fmuladd.f64(double %22, double %16, double %35)
%37 = tail call double @llvm.fmuladd.f64(double %24, double %18, double %36)
%38 = getelementptr inbounds [3 x [3 x double]], [3 x [3 x double]]* %3, i64 0, i64 0, i64 2
store double %37, double* %38
%39 = getelementptr inbounds [3 x double], [3 x double]* %1, i64 1, i64 0
%40 = load double, double* %39
%41 = getelementptr inbounds [3 x double], [3 x double]* %1, i64 1, i64 1
%42 = load double, double* %41
%43 = getelementptr inbounds [3 x double], [3 x double]* %1, i64 1, i64 2
%44 = load double, double* %43
%45 = getelementptr inbounds [3 x [3 x double]], [3 x [3 x double]]* %3, i64 0, i64 1, i64 0
%46 = insertelement <2 x double> poison, double %40, i64 0
%47 = shufflevector <2 x double> %46, <2 x double> poison, <2 x i32> zeroinitializer
%48 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %47, <2 x double> %8, <2 x double> zeroinitializer)
%49 = insertelement <2 x double> poison, double %42, i64 0
%50 = shufflevector <2 x double> %49, <2 x double> poison, <2 x i32> zeroinitializer
%51 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %50, <2 x double> %10, <2 x double> %48)
%52 = insertelement <2 x double> poison, double %44, i64 0
%53 = shufflevector <2 x double> %52, <2 x double> poison, <2 x i32> zeroinitializer
%54 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %53, <2 x double> %12, <2 x double> %51)
%55 = bitcast double* %45 to <2 x double>*
store <2 x double> %54, <2 x double>* %55
%56 = tail call double @llvm.fmuladd.f64(double %40, double %14, double 0.000000e+00)
%57 = tail call double @llvm.fmuladd.f64(double %42, double %16, double %56)
%58 = tail call double @llvm.fmuladd.f64(double %44, double %18, double %57)
%59 = getelementptr inbounds [3 x [3 x double]], [3 x [3 x double]]* %3, i64 0, i64 1, i64 2
store double %58, double* %59
%60 = getelementptr inbounds [3 x double], [3 x double]* %1, i64 2, i64 0
%61 = load double, double* %60
%62 = getelementptr inbounds [3 x double], [3 x double]* %1, i64 2, i64 1
%63 = load double, double* %62
%64 = getelementptr inbounds [3 x double], [3 x double]* %1, i64 2, i64 2
%65 = load double, double* %64
%66 = getelementptr inbounds [3 x [3 x double]], [3 x [3 x double]]* %3, i64 0, i64 2, i64 0
%67 = insertelement <2 x double> poison, double %61, i64 0
%68 = shufflevector <2 x double> %67, <2 x double> poison, <2 x i32> zeroinitializer
%69 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %68, <2 x double> %8, <2 x double> zeroinitializer)
%70 = insertelement <2 x double> poison, double %63, i64 0
%71 = shufflevector <2 x double> %70, <2 x double> poison, <2 x i32> zeroinitializer
%72 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %71, <2 x double> %10, <2 x double> %69)
%73 = insertelement <2 x double> poison, double %65, i64 0
%74 = shufflevector <2 x double> %73, <2 x double> poison, <2 x i32> zeroinitializer
%75 = call <2 x double> @llvm.fmuladd.v2f64(<2 x double> %74, <2 x double> %12, <2 x double> %72)
%76 = bitcast double* %66 to <2 x double>*
store <2 x double> %75, <2 x double>* %76
%77 = tail call double @llvm.fmuladd.f64(double %61, double %14, double 0.000000e+00)
%78 = tail call double @llvm.fmuladd.f64(double %63, double %16, double %77)
%79 = tail call double @llvm.fmuladd.f64(double %65, double %18, double %78)
%80 = getelementptr inbounds [3 x [3 x double]], [3 x [3 x double]]* %3, i64 0, i64 2, i64 2
store double %79, double* %80
%81 = bitcast [3 x double]* %0 to i8*
ret void
}