void kernel_dgemv_n_1_lib4(int kmax, double *A, double *x, double *y, double *z,
                           int alg) {
  if (kmax <= 0)
    return;
  __builtin_prefetch(A);
  __builtin_prefetch(A + 8);
  const int lda = 4;
  int k;
  double x_0, x_1, x_2, x_3, y_0 = 0;
  k = 0;
  for (; k < kmax - 3; k += 4) {
    __builtin_prefetch(A + 4 * lda);
    __builtin_prefetch(A + 4 * lda + 8);
    x_0 = x[0];
    x_1 = x[1];
    x_2 = x[2];
    x_3 = x[3];
    y_0 += A[0 + lda * 0] * x_0;
    y_0 += A[0 + lda * 1] * x_1;
    y_0 += A[0 + lda * 2] * x_2;
    y_0 += A[0 + lda * 3] * x_3;
    A += 4 * lda;
    x += 4;
  }
  for (; k < kmax; k++) {
    x_0 = x[0];
    y_0 += A[0 + lda * 0] * x_0;
    A += 1 * lda;
    x += 1;
  }
  if (alg == 0) {
    y[0] = y_0;
  } else if (alg == 1) {
    z[0] = y[0] + y_0;
  } else {
    z[0] = y[0] - y_0;
  }
}


x86 assembly (clang, -O0):
<kernel_dgemv_n_1_lib4>:
push   %rbp
mov    %rsp,%rbp
mov    %edi,-0x4(%rbp)
mov    %rsi,-0x10(%rbp)
mov    %rdx,-0x18(%rbp)
mov    %rcx,-0x20(%rbp)
mov    %r8,-0x28(%rbp)
mov    %r9d,-0x2c(%rbp)
cmpl   $0x0,-0x4(%rbp)
jg     112a <kernel_dgemv_n_1_lib4+0x2a>
jmp    131c <kernel_dgemv_n_1_lib4+0x21c>
mov    -0x10(%rbp),%rax
prefetcht0 (%rax)
mov    -0x10(%rbp),%rax
add    $0x40,%rax
prefetcht0 (%rax)
movl   $0x4,-0x30(%rbp)
xorps  %xmm0,%xmm0
movsd  %xmm0,-0x60(%rbp)
movl   $0x0,-0x34(%rbp)
mov    -0x34(%rbp),%eax
mov    -0x4(%rbp),%ecx
sub    $0x3,%ecx
cmp    %ecx,%eax
jge    125f <kernel_dgemv_n_1_lib4+0x15f>
mov    -0x10(%rbp),%rax
add    $0x80,%rax
prefetcht0 (%rax)
mov    -0x10(%rbp),%rax
add    $0x80,%rax
add    $0x40,%rax
prefetcht0 (%rax)
mov    -0x18(%rbp),%rax
movsd  (%rax),%xmm0
movsd  %xmm0,-0x40(%rbp)
mov    -0x18(%rbp),%rax
movsd  0x8(%rax),%xmm0
movsd  %xmm0,-0x48(%rbp)
mov    -0x18(%rbp),%rax
movsd  0x10(%rax),%xmm0
movsd  %xmm0,-0x50(%rbp)
mov    -0x18(%rbp),%rax
movsd  0x18(%rax),%xmm0
movsd  %xmm0,-0x58(%rbp)
mov    -0x10(%rbp),%rax
movsd  (%rax),%xmm0
movsd  -0x40(%rbp),%xmm2
movsd  -0x60(%rbp),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x60(%rbp)
mov    -0x10(%rbp),%rax
movsd  0x20(%rax),%xmm0
movsd  -0x48(%rbp),%xmm2
movsd  -0x60(%rbp),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x60(%rbp)
mov    -0x10(%rbp),%rax
movsd  0x40(%rax),%xmm0
movsd  -0x50(%rbp),%xmm2
movsd  -0x60(%rbp),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x60(%rbp)
mov    -0x10(%rbp),%rax
movsd  0x60(%rax),%xmm0
movsd  -0x58(%rbp),%xmm2
movsd  -0x60(%rbp),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x60(%rbp)
mov    -0x10(%rbp),%rax
add    $0x80,%rax
mov    %rax,-0x10(%rbp)
mov    -0x18(%rbp),%rax
add    $0x20,%rax
mov    %rax,-0x18(%rbp)
mov    -0x34(%rbp),%eax
add    $0x4,%eax
mov    %eax,-0x34(%rbp)
jmp    1152 <kernel_dgemv_n_1_lib4+0x52>
jmp    1264 <kernel_dgemv_n_1_lib4+0x164>
mov    -0x34(%rbp),%eax
cmp    -0x4(%rbp),%eax
jge    12c2 <kernel_dgemv_n_1_lib4+0x1c2>
mov    -0x18(%rbp),%rax
movsd  (%rax),%xmm0
movsd  %xmm0,-0x40(%rbp)
mov    -0x10(%rbp),%rax
movsd  (%rax),%xmm0
movsd  -0x40(%rbp),%xmm2
movsd  -0x60(%rbp),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x60(%rbp)
mov    -0x10(%rbp),%rax
add    $0x20,%rax
mov    %rax,-0x10(%rbp)
mov    -0x18(%rbp),%rax
add    $0x8,%rax
mov    %rax,-0x18(%rbp)
mov    -0x34(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x34(%rbp)
jmp    1264 <kernel_dgemv_n_1_lib4+0x164>
cmpl   $0x0,-0x2c(%rbp)
jne    12de <kernel_dgemv_n_1_lib4+0x1de>
movsd  -0x60(%rbp),%xmm0
mov    -0x20(%rbp),%rax
movsd  %xmm0,(%rax)
jmp    131c <kernel_dgemv_n_1_lib4+0x21c>
cmpl   $0x1,-0x2c(%rbp)
jne    1302 <kernel_dgemv_n_1_lib4+0x202>
mov    -0x20(%rbp),%rax
movsd  (%rax),%xmm0
addsd  -0x60(%rbp),%xmm0
mov    -0x28(%rbp),%rax
movsd  %xmm0,(%rax)
jmp    1317 <kernel_dgemv_n_1_lib4+0x217>
mov    -0x20(%rbp),%rax
movsd  (%rax),%xmm0
subsd  -0x60(%rbp),%xmm0
mov    -0x28(%rbp),%rax
movsd  %xmm0,(%rax)
jmp    131c <kernel_dgemv_n_1_lib4+0x21c>
pop    %rbp
ret

x86 assembly (clang, -O2):
<kernel_dgemv_n_1_lib4>:
push   %rbx
test   %edi,%edi
jle    124f <kernel_dgemv_n_1_lib4+0x14f>
prefetcht0 (%rsi)
prefetcht0 0x40(%rsi)
cmp    $0x4,%edi
jb     1188 <kernel_dgemv_n_1_lib4+0x88>
lea    -0x3(%rdi),%r10d
xor    %eax,%eax
xorpd  %xmm0,%xmm0
nop
prefetcht0 0x80(%rsi)
prefetcht0 0xc0(%rsi)
movsd  (%rsi),%xmm1
movsd  0x20(%rsi),%xmm2
mulsd  (%rdx),%xmm1
addsd  %xmm0,%xmm1
mulsd  0x8(%rdx),%xmm2
addsd  %xmm1,%xmm2
movsd  0x40(%rsi),%xmm1
mulsd  0x10(%rdx),%xmm1
movsd  0x60(%rsi),%xmm0
add    $0x80,%rsi
addsd  %xmm2,%xmm1
mulsd  0x18(%rdx),%xmm0
addsd  %xmm1,%xmm0
add    $0x20,%rdx
add    $0x4,%eax
cmp    %r10d,%eax
jl     1120 <kernel_dgemv_n_1_lib4+0x20>
mov    %edi,%r11d
and    $0xfffffffc,%r11d
cmp    %edi,%r11d
jl     1198 <kernel_dgemv_n_1_lib4+0x98>
jmp    1226 <kernel_dgemv_n_1_lib4+0x126>
xorpd  %xmm0,%xmm0
xor    %r11d,%r11d
cmp    %edi,%r11d
jge    1226 <kernel_dgemv_n_1_lib4+0x126>
mov    %r11d,%r10d
not    %r10d
add    %edi,%r10d
mov    %edi,%eax
and    $0x3,%eax
je     11ce <kernel_dgemv_n_1_lib4+0xce>
neg    %eax
xor    %ebx,%ebx
nopl   0x0(%rax)
movsd  (%rsi),%xmm1
mulsd  (%rdx),%xmm1
addsd  %xmm1,%xmm0
add    $0x20,%rsi
add    $0x8,%rdx
add    $0xffffffff,%ebx
cmp    %ebx,%eax
jne    11b0 <kernel_dgemv_n_1_lib4+0xb0>
sub    %ebx,%r11d
cmp    $0x3,%r10d
jb     1226 <kernel_dgemv_n_1_lib4+0x126>
sub    %r11d,%edi
xor    %eax,%eax
nopl   0x0(%rax)
movsd  (%rsi),%xmm1
mulsd  (%rdx,%rax,8),%xmm1
movsd  0x20(%rsi),%xmm2
addsd  %xmm0,%xmm1
mulsd  0x8(%rdx,%rax,8),%xmm2
addsd  %xmm1,%xmm2
movsd  0x40(%rsi),%xmm1
mulsd  0x10(%rdx,%rax,8),%xmm1
addsd  %xmm2,%xmm1
movsd  0x60(%rsi),%xmm0
mulsd  0x18(%rdx,%rax,8),%xmm0
addsd  %xmm1,%xmm0
add    $0x4,%rax
sub    $0xffffffffffffff80,%rsi
cmp    %eax,%edi
jne    11e0 <kernel_dgemv_n_1_lib4+0xe0>
cmp    $0x1,%r9d
je     1237 <kernel_dgemv_n_1_lib4+0x137>
test   %r9d,%r9d
jne    1242 <kernel_dgemv_n_1_lib4+0x142>
movsd  %xmm0,(%rcx)
pop    %rbx
ret
addsd  (%rcx),%xmm0
movsd  %xmm0,(%r8)
pop    %rbx
ret
movsd  (%rcx),%xmm1
subsd  %xmm0,%xmm1
movsd  %xmm1,(%r8)
pop    %rbx
ret

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

LLVM IR (-O2):
define void @kernel_dgemv_n_1_lib4(i32 %0, double* nocapture %1, double* nocapture %2, double* nocapture %3, double* nocapture writeonly %4, i32 %5) {
%7 = icmp slt i32 %0, 1
br i1 %7, label %114, label %8
8: ; preds = %6
%9 = bitcast double* %1 to i8*
tail call void @llvm.prefetch.p0i8(i8* %9, i32 0, i32 3, i32 1)
%10 = getelementptr inbounds double, double* %1, i64 8
%11 = bitcast double* %10 to i8*
tail call void @llvm.prefetch.p0i8(i8* %11, i32 0, i32 3, i32 1)
%12 = add nsw i32 %0, -3
%13 = icmp ugt i32 %0, 3
br i1 %13, label %48, label %16
14: ; preds = %48
%15 = and i32 %0, -4
br label %16
16: ; preds = %14, %8
%17 = phi i32 [ 0, %8 ], [ %15, %14 ]
%18 = phi double* [ %2, %8 ], [ %75, %14 ]
%19 = phi double* [ %1, %8 ], [ %53, %14 ]
%20 = phi double [ 0.000000e+00, %8 ], [ %74, %14 ]
%21 = icmp slt i32 %17, %0
br i1 %21, label %22, label %105
22: ; preds = %16
%23 = xor i32 %17, -1
%24 = add i32 %23, %0
%25 = and i32 %0, 3
%26 = icmp eq i32 %25, 0
br i1 %26, label %41, label %27
27: ; preds = %22, %27
%28 = phi double [ %35, %27 ], [ %20, %22 ]
%29 = phi double* [ %36, %27 ], [ %19, %22 ]
%30 = phi double* [ %37, %27 ], [ %18, %22 ]
%31 = phi i32 [ %38, %27 ], [ %17, %22 ]
%32 = phi i32 [ %39, %27 ], [ 0, %22 ]
%33 = load double, double* %30
%34 = load double, double* %29
%35 = tail call double @llvm.fmuladd.f64(double %34, double %33, double %28)
%36 = getelementptr inbounds double, double* %29, i64 4
%37 = getelementptr inbounds double, double* %30, i64 1
%38 = add nuw nsw i32 %31, 1
%39 = add i32 %32, 1
%40 = icmp eq i32 %39, %25
br i1 %40, label %41, label %27
41: ; preds = %27, %22
%42 = phi double [ undef, %22 ], [ %35, %27 ]
%43 = phi double [ %20, %22 ], [ %35, %27 ]
%44 = phi double* [ %19, %22 ], [ %36, %27 ]
%45 = phi double* [ %18, %22 ], [ %37, %27 ]
%46 = phi i32 [ %17, %22 ], [ %38, %27 ]
%47 = icmp ult i32 %24, 3
br i1 %47, label %105, label %78
48: ; preds = %8, %48
%49 = phi double [ %74, %48 ], [ 0.000000e+00, %8 ]
%50 = phi double* [ %53, %48 ], [ %1, %8 ]
%51 = phi double* [ %75, %48 ], [ %2, %8 ]
%52 = phi i32 [ %76, %48 ], [ 0, %8 ]
%53 = getelementptr inbounds double, double* %50, i64 16
%54 = bitcast double* %53 to i8*
tail call void @llvm.prefetch.p0i8(i8* %54, i32 0, i32 3, i32 1)
%55 = getelementptr inbounds double, double* %50, i64 24
%56 = bitcast double* %55 to i8*
tail call void @llvm.prefetch.p0i8(i8* %56, i32 0, i32 3, i32 1)
%57 = load double, double* %51
%58 = getelementptr inbounds double, double* %51, i64 1
%59 = load double, double* %58
%60 = getelementptr inbounds double, double* %51, i64 2
%61 = load double, double* %60
%62 = getelementptr inbounds double, double* %51, i64 3
%63 = load double, double* %62
%64 = load double, double* %50
%65 = tail call double @llvm.fmuladd.f64(double %64, double %57, double %49)
%66 = getelementptr inbounds double, double* %50, i64 4
%67 = load double, double* %66
%68 = tail call double @llvm.fmuladd.f64(double %67, double %59, double %65)
%69 = getelementptr inbounds double, double* %50, i64 8
%70 = load double, double* %69
%71 = tail call double @llvm.fmuladd.f64(double %70, double %61, double %68)
%72 = getelementptr inbounds double, double* %50, i64 12
%73 = load double, double* %72
%74 = tail call double @llvm.fmuladd.f64(double %73, double %63, double %71)
%75 = getelementptr inbounds double, double* %51, i64 4
%76 = add nuw nsw i32 %52, 4
%77 = icmp slt i32 %76, %12
br i1 %77, label %48, label %14
78: ; preds = %41, %78
%79 = phi double [ %100, %78 ], [ %43, %41 ]
%80 = phi double* [ %101, %78 ], [ %44, %41 ]
%81 = phi double* [ %102, %78 ], [ %45, %41 ]
%82 = phi i32 [ %103, %78 ], [ %46, %41 ]
%83 = load double, double* %81
%84 = load double, double* %80
%85 = tail call double @llvm.fmuladd.f64(double %84, double %83, double %79)
%86 = getelementptr inbounds double, double* %80, i64 4
%87 = getelementptr inbounds double, double* %81, i64 1
%88 = load double, double* %87
%89 = load double, double* %86
%90 = tail call double @llvm.fmuladd.f64(double %89, double %88, double %85)
%91 = getelementptr inbounds double, double* %80, i64 8
%92 = getelementptr inbounds double, double* %81, i64 2
%93 = load double, double* %92
%94 = load double, double* %91
%95 = tail call double @llvm.fmuladd.f64(double %94, double %93, double %90)
%96 = getelementptr inbounds double, double* %80, i64 12
%97 = getelementptr inbounds double, double* %81, i64 3
%98 = load double, double* %97
%99 = load double, double* %96
%100 = tail call double @llvm.fmuladd.f64(double %99, double %98, double %95)
%101 = getelementptr inbounds double, double* %80, i64 16
%102 = getelementptr inbounds double, double* %81, i64 4
%103 = add nuw nsw i32 %82, 4
%104 = icmp eq i32 %103, %0
br i1 %104, label %105, label %78
105: ; preds = %41, %78, %16
%106 = phi double [ %20, %16 ], [ %42, %41 ], [ %100, %78 ]
switch i32 %5, label %111 [
i32 0, label %107
i32 1, label %108
]
107: ; preds = %105
store double %106, double* %3
br label %114
108: ; preds = %105
%109 = load double, double* %3
%110 = fadd double %106, %109
store double %110, double* %4
br label %114
111: ; preds = %105
%112 = load double, double* %3
%113 = fsub double %112, %106
store double %113, double* %4
br label %114
114: ; preds = %107, %111, %108, %6
ret void
}