void foo(_Complex double *self, _Complex double *a, _Complex double *b, int a1,
         int a2) {
  int i, j;
  for (i = 0; i < a1; ++i)
    for (j = 0; j < a2; ++j)
      self[i] = self[i] + a[i, j] * b[j];
}


x86 assembly (clang, -O0):
<foo>:
push   %rbp
mov    %rsp,%rbp
sub    $0x80,%rsp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %rdx,-0x18(%rbp)
mov    %ecx,-0x1c(%rbp)
mov    %r8d,-0x20(%rbp)
movl   $0x0,-0x24(%rbp)
mov    -0x24(%rbp),%eax
cmp    -0x1c(%rbp),%eax
jge    127c <foo+0x17c>
movl   $0x0,-0x28(%rbp)
mov    -0x28(%rbp),%eax
cmp    -0x20(%rbp),%eax
jge    1269 <foo+0x169>
mov    -0x8(%rbp),%rax
movslq -0x24(%rbp),%rcx
shl    $0x4,%rcx
add    %rcx,%rax
movsd  (%rax),%xmm0
movsd  %xmm0,-0x78(%rbp)
movsd  0x8(%rax),%xmm0
movsd  %xmm0,-0x70(%rbp)
mov    -0x10(%rbp),%rax
movslq -0x28(%rbp),%rcx
shl    $0x4,%rcx
add    %rcx,%rax
movsd  (%rax),%xmm1
movsd  %xmm1,-0x68(%rbp)
movsd  0x8(%rax),%xmm2
movsd  %xmm2,-0x60(%rbp)
mov    -0x18(%rbp),%rax
movslq -0x28(%rbp),%rcx
shl    $0x4,%rcx
add    %rcx,%rax
movsd  (%rax),%xmm4
movsd  %xmm4,-0x58(%rbp)
movsd  0x8(%rax),%xmm5
movsd  %xmm5,-0x50(%rbp)
movaps %xmm1,%xmm0
mulsd  %xmm4,%xmm0
movaps %xmm2,%xmm3
mulsd  %xmm5,%xmm3
mulsd  %xmm5,%xmm1
mulsd  %xmm4,%xmm2
subsd  %xmm3,%xmm0
movsd  %xmm0,-0x48(%rbp)
addsd  %xmm2,%xmm1
movsd  %xmm1,-0x40(%rbp)
ucomisd %xmm0,%xmm0
movsd  %xmm0,-0x38(%rbp)
movsd  %xmm1,-0x30(%rbp)
jnp    1227 <foo+0x127>
movsd  -0x40(%rbp),%xmm1
movsd  -0x48(%rbp),%xmm0
ucomisd %xmm1,%xmm1
movsd  %xmm0,-0x38(%rbp)
movsd  %xmm1,-0x30(%rbp)
jnp    1227 <foo+0x127>
movsd  -0x50(%rbp),%xmm3
movsd  -0x58(%rbp),%xmm2
movsd  -0x60(%rbp),%xmm1
movsd  -0x68(%rbp),%xmm0
call   1290 <__muldc3>
movsd  %xmm0,-0x38(%rbp)
movsd  %xmm1,-0x30(%rbp)
movsd  -0x70(%rbp),%xmm0
movsd  -0x78(%rbp),%xmm1
movsd  -0x38(%rbp),%xmm3
movsd  -0x30(%rbp),%xmm2
addsd  %xmm3,%xmm1
addsd  %xmm2,%xmm0
mov    -0x8(%rbp),%rax
movslq -0x24(%rbp),%rcx
shl    $0x4,%rcx
add    %rcx,%rax
movsd  %xmm1,(%rax)
movsd  %xmm0,0x8(%rax)
mov    -0x28(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x28(%rbp)
jmp    1138 <foo+0x38>
jmp    126e <foo+0x16e>
mov    -0x24(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x24(%rbp)
jmp    1125 <foo+0x25>
add    $0x80,%rsp
pop    %rbp
ret
cs nopw 0x0(%rax,%rax,1)
nop

x86 assembly (clang, -O2):
<foo>:
push   %rbp
push   %r15
push   %r14
push   %r13
push   %r12
push   %rbx
sub    $0x38,%rsp
test   %ecx,%ecx
jle    1212 <foo+0x112>
mov    %rdx,%rbx
mov    %rsi,%r13
mov    %ecx,%ecx
mov    %r8d,%ebp
shl    $0x4,%rbp
xor    %r14d,%r14d
jmp    113d <foo+0x3d>
nopw   0x0(%rax,%rax,1)
add    $0x1,%r14
cmp    %rcx,%r14
je     1212 <foo+0x112>
test   %r8d,%r8d
jle    1130 <foo+0x30>
mov    %r14,%rax
shl    $0x4,%rax
lea    (%rdi,%rax,1),%r12
movupd (%rdi,%rax,1),%xmm6
xor    %r15d,%r15d
cs nopw 0x0(%rax,%rax,1)
nop
movupd 0x0(%r13,%r15,1),%xmm0
movsd  (%rbx,%r15,1),%xmm2
movsd  0x8(%rbx,%r15,1),%xmm3
movapd %xmm3,%xmm1
unpcklpd %xmm3,%xmm1
movapd %xmm0,%xmm4
shufpd $0x1,%xmm0,%xmm4
mulpd  %xmm1,%xmm4
movapd %xmm2,%xmm1
unpcklpd %xmm2,%xmm1
mulpd  %xmm0,%xmm1
movapd %xmm1,%xmm5
subpd  %xmm4,%xmm5
addpd  %xmm4,%xmm1
movapd %xmm1,%xmm4
movsd  %xmm5,%xmm4
ucomisd %xmm5,%xmm5
jp     11c7 <foo+0xc7>
addpd  %xmm4,%xmm6
movupd %xmm6,(%r12)
add    $0x10,%r15
cmp    %r15,%rbp
jne    1160 <foo+0x60>
jmp    1130 <foo+0x30>
unpckhpd %xmm1,%xmm1
ucomisd %xmm1,%xmm1
jnp    11af <foo+0xaf>
movapd %xmm0,%xmm1
unpckhpd %xmm0,%xmm1
mov    %r8d,0xc(%rsp)
mov    %rdi,0x18(%rsp)
mov    %rcx,0x10(%rsp)
movapd %xmm6,0x20(%rsp)
call   1230 <__muldc3>
movapd 0x20(%rsp),%xmm6
mov    0x10(%rsp),%rcx
mov    0x18(%rsp),%rdi
mov    0xc(%rsp),%r8d
movapd %xmm0,%xmm4
unpcklpd %xmm1,%xmm4
jmp    11af <foo+0xaf>
add    $0x38,%rsp
pop    %rbx
pop    %r12
pop    %r13
pop    %r14
pop    %r15
pop    %rbp
ret
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax,%rax,1)

LLVM IR (-O0):
define void @foo({ double, double }* %0, { double, double }* %1, { double, double }* %2, i32 %3, i32 %4) {
%6 = alloca { double, double }*
%7 = alloca { double, double }*
%8 = alloca { double, double }*
%9 = alloca i32
%10 = alloca i32
%11 = alloca i32
%12 = alloca i32
store { double, double }* %0, { double, double }** %6
store { double, double }* %1, { double, double }** %7
store { double, double }* %2, { double, double }** %8
store i32 %3, i32* %9
store i32 %4, i32* %10
store i32 0, i32* %11
br label %13
13: ; preds = %76, %5
%14 = load i32, i32* %11
%15 = load i32, i32* %9
%16 = icmp slt i32 %14, %15
br i1 %16, label %17, label %79
17: ; preds = %13
store i32 0, i32* %12
br label %18
18: ; preds = %72, %17
%19 = load i32, i32* %12
%20 = load i32, i32* %10
%21 = icmp slt i32 %19, %20
br i1 %21, label %22, label %75
22: ; preds = %18
%23 = load { double, double }*, { double, double }** %6
%24 = load i32, i32* %11
%25 = sext i32 %24 to i64
%26 = getelementptr inbounds { double, double }, { double, double }* %23, i64 %25
%27 = getelementptr inbounds { double, double }, { double, double }* %26, i32 0, i32 0
%28 = load double, double* %27
%29 = getelementptr inbounds { double, double }, { double, double }* %26, i32 0, i32 1
%30 = load double, double* %29
%31 = load { double, double }*, { double, double }** %7
%32 = load i32, i32* %11
%33 = load i32, i32* %12
%34 = sext i32 %33 to i64
%35 = getelementptr inbounds { double, double }, { double, double }* %31, i64 %34
%36 = getelementptr inbounds { double, double }, { double, double }* %35, i32 0, i32 0
%37 = load double, double* %36
%38 = getelementptr inbounds { double, double }, { double, double }* %35, i32 0, i32 1
%39 = load double, double* %38
%40 = load { double, double }*, { double, double }** %8
%41 = load i32, i32* %12
%42 = sext i32 %41 to i64
%43 = getelementptr inbounds { double, double }, { double, double }* %40, i64 %42
%44 = getelementptr inbounds { double, double }, { double, double }* %43, i32 0, i32 0
%45 = load double, double* %44
%46 = getelementptr inbounds { double, double }, { double, double }* %43, i32 0, i32 1
%47 = load double, double* %46
%48 = fmul double %37, %45
%49 = fmul double %39, %47
%50 = fmul double %37, %47
%51 = fmul double %39, %45
%52 = fsub double %48, %49
%53 = fadd double %50, %51
%54 = fcmp uno double %52, %52
br i1 %54, label %55, label %61
55: ; preds = %22
%56 = fcmp uno double %53, %53
br i1 %56, label %57, label %61
57: ; preds = %55
%58 = call { double, double } @__muldc3(double %37, double %39, double %45, double %47)
%59 = extractvalue { double, double } %58, 0
%60 = extractvalue { double, double } %58, 1
br label %61
61: ; preds = %57, %55, %22
%62 = phi double [ %52, %22 ], [ %52, %55 ], [ %59, %57 ]
%63 = phi double [ %53, %22 ], [ %53, %55 ], [ %60, %57 ]
%64 = fadd double %28, %62
%65 = fadd double %30, %63
%66 = load { double, double }*, { double, double }** %6
%67 = load i32, i32* %11
%68 = sext i32 %67 to i64
%69 = getelementptr inbounds { double, double }, { double, double }* %66, i64 %68
%70 = getelementptr inbounds { double, double }, { double, double }* %69, i32 0, i32 0
%71 = getelementptr inbounds { double, double }, { double, double }* %69, i32 0, i32 1
store double %64, double* %70
store double %65, double* %71
br label %72
72: ; preds = %61
%73 = load i32, i32* %12
%74 = add nsw i32 %73, 1
store i32 %74, i32* %12
br label %18
75: ; preds = %18
br label %76
76: ; preds = %75
%77 = load i32, i32* %11
%78 = add nsw i32 %77, 1
store i32 %78, i32* %11
br label %13
79: ; preds = %13
ret void
}

LLVM IR (-O2):
define void @foo({ double, double }* nocapture %0, { double, double }* nocapture %1, { double, double }* nocapture %2, i32 %3, i32 %4) {
%6 = icmp sgt i32 %3, 0
br i1 %6, label %7, label %59
7: ; preds = %5
%8 = icmp sgt i32 %4, 0
%9 = zext i32 %3 to i64
%10 = zext i32 %4 to i64
br label %11
11: ; preds = %7, %56
%12 = phi i64 [ 0, %7 ], [ %57, %56 ]
br i1 %8, label %13, label %56
13: ; preds = %11
%14 = getelementptr inbounds { double, double }, { double, double }* %0, i64 %12, i32 0
%15 = bitcast double* %14 to <2 x double>*
%16 = load <2 x double>, <2 x double>* %15
%17 = bitcast double* %14 to <2 x double>*
br label %18
18: ; preds = %13, %51
%19 = phi i64 [ 0, %13 ], [ %54, %51 ]
%20 = phi <2 x double> [ %16, %13 ], [ %53, %51 ]
%21 = getelementptr inbounds { double, double }, { double, double }* %1, i64 %19, i32 0
%22 = bitcast double* %21 to <2 x double>*
%23 = load <2 x double>, <2 x double>* %22
%24 = getelementptr inbounds { double, double }, { double, double }* %2, i64 %19, i32 0
%25 = load double, double* %24
%26 = getelementptr inbounds { double, double }, { double, double }* %2, i64 %19, i32 1
%27 = load double, double* %26
%28 = insertelement <2 x double> poison, double %27, i64 0
%29 = shufflevector <2 x double> %28, <2 x double> poison, <2 x i32> zeroinitializer
%30 = fmul <2 x double> %23, %29
%31 = shufflevector <2 x double> %30, <2 x double> poison, <2 x i32> <i32 1, i32 0>
%32 = insertelement <2 x double> poison, double %25, i64 0
%33 = shufflevector <2 x double> %32, <2 x double> poison, <2 x i32> zeroinitializer
%34 = fmul <2 x double> %23, %33
%35 = fsub <2 x double> %34, %31
%36 = fadd <2 x double> %34, %31
%37 = shufflevector <2 x double> %35, <2 x double> %36, <2 x i32> <i32 0, i32 3>
%38 = extractelement <2 x double> %35, i64 0
%39 = fcmp uno double %38, 0.000000e+00
br i1 %39, label %40, label %51
40: ; preds = %18
%41 = extractelement <2 x double> %36, i64 1
%42 = fcmp uno double %41, 0.000000e+00
br i1 %42, label %43, label %51
43: ; preds = %40
%44 = extractelement <2 x double> %23, i64 0
%45 = extractelement <2 x double> %23, i64 1
%46 = tail call { double, double } @__muldc3(double %44, double %45, double %25, double %27)
%47 = extractvalue { double, double } %46, 0
%48 = extractvalue { double, double } %46, 1
%49 = insertelement <2 x double> poison, double %47, i64 0
%50 = insertelement <2 x double> %49, double %48, i64 1
br label %51
51: ; preds = %43, %40, %18
%52 = phi <2 x double> [ %37, %18 ], [ %37, %40 ], [ %50, %43 ]
%53 = fadd <2 x double> %20, %52
store <2 x double> %53, <2 x double>* %17
%54 = add nuw nsw i64 %19, 1
%55 = icmp eq i64 %54, %10
br i1 %55, label %56, label %18
56: ; preds = %51, %11
%57 = add nuw nsw i64 %12, 1
%58 = icmp eq i64 %57, %9
br i1 %58, label %59, label %11
59: ; preds = %56, %5
ret void
}