void _gmm_vec_add(double *x, const double *y, double a, double b, int D) {
  for (int i = 0; i < D; i++)
    x[i] = a * x[i] + b * y[i];
}


x86 assembly (clang, -O0):
<_gmm_vec_add>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
movsd  %xmm0,-0x18(%rbp)
movsd  %xmm1,-0x20(%rbp)
mov    %edx,-0x24(%rbp)
movl   $0x0,-0x28(%rbp)
mov    -0x28(%rbp),%eax
cmp    -0x24(%rbp),%eax
jge    1173 <_gmm_vec_add+0x73>
movsd  -0x18(%rbp),%xmm0
mov    -0x8(%rbp),%rax
movslq -0x28(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm2
movsd  -0x20(%rbp),%xmm1
mov    -0x10(%rbp),%rax
movslq -0x28(%rbp),%rcx
mulsd  (%rax,%rcx,8),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
mov    -0x8(%rbp),%rax
movslq -0x28(%rbp),%rcx
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x28(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x28(%rbp)
jmp    1120 <_gmm_vec_add+0x20>
pop    %rbp
ret

x86 assembly (clang, -O2):
<_gmm_vec_add>:
test   %edx,%edx
jle    12c7 <_gmm_vec_add+0x1c7>
mov    %edx,%r9d
cmp    $0x4,%edx
jb     112a <_gmm_vec_add+0x2a>
lea    (%rsi,%r9,8),%rax
cmp    %rdi,%rax
jbe    11a7 <_gmm_vec_add+0xa7>
lea    (%rdi,%r9,8),%rax
cmp    %rsi,%rax
jbe    11a7 <_gmm_vec_add+0xa7>
xor    %ecx,%ecx
mov    %rcx,%rax
not    %rax
test   $0x1,%r9b
je     1157 <_gmm_vec_add+0x57>
movsd  (%rsi,%rcx,8),%xmm2
mulsd  %xmm1,%xmm2
movsd  (%rdi,%rcx,8),%xmm3
mulsd  %xmm0,%xmm3
addsd  %xmm2,%xmm3
movsd  %xmm3,(%rdi,%rcx,8)
or     $0x1,%rcx
add    %r9,%rax
je     12c7 <_gmm_vec_add+0x1c7>
movsd  (%rsi,%rcx,8),%xmm2
mulsd  %xmm1,%xmm2
movsd  (%rdi,%rcx,8),%xmm3
mulsd  %xmm0,%xmm3
addsd  %xmm2,%xmm3
movsd  %xmm3,(%rdi,%rcx,8)
movsd  0x8(%rsi,%rcx,8),%xmm2
mulsd  %xmm1,%xmm2
movsd  0x8(%rdi,%rcx,8),%xmm3
mulsd  %xmm0,%xmm3
addsd  %xmm2,%xmm3
movsd  %xmm3,0x8(%rdi,%rcx,8)
add    $0x2,%rcx
cmp    %rcx,%r9
jne    1160 <_gmm_vec_add+0x60>
jmp    12c7 <_gmm_vec_add+0x1c7>
mov    %r9d,%ecx
and    $0xfffffffc,%ecx
movapd %xmm1,%xmm9
unpcklpd %xmm1,%xmm9
movapd %xmm0,%xmm8
unpcklpd %xmm0,%xmm8
lea    -0x4(%rcx),%rax
mov    %rax,%r8
shr    $0x2,%r8
add    $0x1,%r8
test   %rax,%rax
je     12c8 <_gmm_vec_add+0x1c8>
mov    %r8,%rax
and    $0xfffffffffffffffe,%rax
xor    %edx,%edx
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax)
movupd (%rsi,%rdx,8),%xmm4
movupd 0x10(%rsi,%rdx,8),%xmm5
mulpd  %xmm9,%xmm4
mulpd  %xmm9,%xmm5
movupd (%rdi,%rdx,8),%xmm6
movupd 0x10(%rdi,%rdx,8),%xmm7
movupd 0x20(%rdi,%rdx,8),%xmm2
movupd 0x30(%rdi,%rdx,8),%xmm3
mulpd  %xmm8,%xmm6
addpd  %xmm4,%xmm6
mulpd  %xmm8,%xmm7
addpd  %xmm5,%xmm7
movupd %xmm6,(%rdi,%rdx,8)
movupd %xmm7,0x10(%rdi,%rdx,8)
movupd 0x20(%rsi,%rdx,8),%xmm4
movupd 0x30(%rsi,%rdx,8),%xmm5
mulpd  %xmm9,%xmm4
mulpd  %xmm9,%xmm5
mulpd  %xmm8,%xmm2
addpd  %xmm4,%xmm2
mulpd  %xmm8,%xmm3
addpd  %xmm5,%xmm3
movupd %xmm2,0x20(%rdi,%rdx,8)
movupd %xmm3,0x30(%rdi,%rdx,8)
add    $0x8,%rdx
add    $0xfffffffffffffffe,%rax
jne    11f0 <_gmm_vec_add+0xf0>
test   $0x1,%r8b
je     12be <_gmm_vec_add+0x1be>
movupd (%rdi,%rdx,8),%xmm2
movupd 0x10(%rdi,%rdx,8),%xmm3
movupd (%rsi,%rdx,8),%xmm4
movupd 0x10(%rsi,%rdx,8),%xmm5
mulpd  %xmm9,%xmm4
mulpd  %xmm9,%xmm5
mulpd  %xmm8,%xmm2
addpd  %xmm4,%xmm2
mulpd  %xmm8,%xmm3
addpd  %xmm5,%xmm3
movupd %xmm2,(%rdi,%rdx,8)
movupd %xmm3,0x10(%rdi,%rdx,8)
cmp    %r9,%rcx
jne    112c <_gmm_vec_add+0x2c>
ret
xor    %edx,%edx
test   $0x1,%r8b
jne    1281 <_gmm_vec_add+0x181>
jmp    12be <_gmm_vec_add+0x1be>

LLVM IR (-O0):
define void @_gmm_vec_add(double* %0, double* %1, double %2, double %3, i32 %4) {
%6 = alloca double*
%7 = alloca double*
%8 = alloca double
%9 = alloca double
%10 = alloca i32
%11 = alloca i32
store double* %0, double** %6
store double* %1, double** %7
store double %2, double* %8
store double %3, double* %9
store i32 %4, i32* %10
store i32 0, i32* %11
br label %12
12: ; preds = %35, %5
%13 = load i32, i32* %11
%14 = load i32, i32* %10
%15 = icmp slt i32 %13, %14
br i1 %15, label %16, label %38
16: ; preds = %12
%17 = load double, double* %8
%18 = load double*, double** %6
%19 = load i32, i32* %11
%20 = sext i32 %19 to i64
%21 = getelementptr inbounds double, double* %18, i64 %20
%22 = load double, double* %21
%23 = load double, double* %9
%24 = load double*, double** %7
%25 = load i32, i32* %11
%26 = sext i32 %25 to i64
%27 = getelementptr inbounds double, double* %24, i64 %26
%28 = load double, double* %27
%29 = fmul double %23, %28
%30 = call double @llvm.fmuladd.f64(double %17, double %22, double %29)
%31 = load double*, double** %6
%32 = load i32, i32* %11
%33 = sext i32 %32 to i64
%34 = getelementptr inbounds double, double* %31, i64 %33
store double %30, double* %34
br label %35
35: ; preds = %16
%36 = load i32, i32* %11
%37 = add nsw i32 %36, 1
store i32 %37, i32* %11
br label %12
38: ; preds = %12
ret void
}

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