void dcsc_matvec(int n_row, int n_col, int nnz, int *Ap, int *Ai, double *Ax,
                 double *Xx, double *Yx) {
  int col_start, col_end, j, ii, i;
  for (j = 0; j < n_col; j++) {
    col_start = Ap[j];
    col_end = Ap[j + 1];
    for (ii = col_start; ii < col_end; ii++) {
      i = Ai[ii];
      Yx[i] += Ax[ii] * Xx[j];
    }
  }
}


x86 assembly (clang, -O0):
<dcsc_matvec>:
push   %rbp
mov    %rsp,%rbp
mov    0x18(%rbp),%rax
mov    0x10(%rbp),%rax
mov    %edi,-0x4(%rbp)
mov    %esi,-0x8(%rbp)
mov    %edx,-0xc(%rbp)
mov    %rcx,-0x18(%rbp)
mov    %r8,-0x20(%rbp)
mov    %r9,-0x28(%rbp)
movl   $0x0,-0x34(%rbp)
mov    -0x34(%rbp),%eax
cmp    -0x8(%rbp),%eax
jge    11ca <dcsc_matvec+0xca>
mov    -0x18(%rbp),%rax
movslq -0x34(%rbp),%rcx
mov    (%rax,%rcx,4),%eax
mov    %eax,-0x2c(%rbp)
mov    -0x18(%rbp),%rax
mov    -0x34(%rbp),%ecx
add    $0x1,%ecx
movslq %ecx,%rcx
mov    (%rax,%rcx,4),%eax
mov    %eax,-0x30(%rbp)
mov    -0x2c(%rbp),%eax
mov    %eax,-0x38(%rbp)
mov    -0x38(%rbp),%eax
cmp    -0x30(%rbp),%eax
jge    11b7 <dcsc_matvec+0xb7>
mov    -0x20(%rbp),%rax
movslq -0x38(%rbp),%rcx
mov    (%rax,%rcx,4),%eax
mov    %eax,-0x3c(%rbp)
mov    -0x28(%rbp),%rax
movslq -0x38(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
mov    0x10(%rbp),%rax
movslq -0x34(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm2
mov    0x18(%rbp),%rax
movslq -0x3c(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,(%rax,%rcx,8)
mov    -0x38(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x38(%rbp)
jmp    115b <dcsc_matvec+0x5b>
jmp    11bc <dcsc_matvec+0xbc>
mov    -0x34(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x34(%rbp)
jmp    1128 <dcsc_matvec+0x28>
pop    %rbp
ret

x86 assembly (clang, -O2):
<dcsc_matvec>:
push   %rbp
push   %r15
push   %r14
push   %rbx
test   %esi,%esi
jle    11d2 <dcsc_matvec+0xd2>
mov    0x30(%rsp),%rax
mov    0x28(%rsp),%rdx
mov    %esi,%r10d
mov    (%rcx),%r14d
xor    %r11d,%r11d
jmp    1139 <dcsc_matvec+0x39>
cs nopw 0x0(%rax,%rax,1)
nopl   (%rax)
cmp    %r10,%r11
je     11d2 <dcsc_matvec+0xd2>
mov    %r11,%rsi
mov    %r14d,%edi
add    $0x1,%r11
mov    0x4(%rcx,%rsi,4),%r14d
cmp    %r14d,%edi
jge    1130 <dcsc_matvec+0x30>
movslq %edi,%rbp
mov    %r14d,%r15d
sub    %edi,%r15d
mov    %rbp,%rbx
test   $0x1,%r15b
je     117c <dcsc_matvec+0x7c>
movslq (%r8,%rbp,4),%rdi
movsd  (%r9,%rbp,8),%xmm0
mulsd  (%rdx,%rsi,8),%xmm0
addsd  (%rax,%rdi,8),%xmm0
movsd  %xmm0,(%rax,%rdi,8)
lea    0x1(%rbp),%rbx
movslq %r14d,%rdi
not    %rbp
add    %rdi,%rbp
je     1130 <dcsc_matvec+0x30>
nopw   0x0(%rax,%rax,1)
movslq (%r8,%rbx,4),%rbp
movsd  (%r9,%rbx,8),%xmm0
mulsd  (%rdx,%rsi,8),%xmm0
addsd  (%rax,%rbp,8),%xmm0
movsd  %xmm0,(%rax,%rbp,8)
movslq 0x4(%r8,%rbx,4),%rbp
movsd  0x8(%r9,%rbx,8),%xmm0
mulsd  (%rdx,%rsi,8),%xmm0
addsd  (%rax,%rbp,8),%xmm0
movsd  %xmm0,(%rax,%rbp,8)
add    $0x2,%rbx
cmp    %rbx,%rdi
jne    1190 <dcsc_matvec+0x90>
jmp    1130 <dcsc_matvec+0x30>
pop    %rbx
pop    %r14
pop    %r15
pop    %rbp
ret

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

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