void mv_utt(double *y, unsigned int n, const double *U, const double *x) {
  double *ye = y + n;
  unsigned int i = 1;
  for (; y != ye; ++y, ++i) {
    double v = 0;
    const double *xp = x, *xe = x + i;
    for (; xp != xe; ++xp)
      v += (*U++) * (*xp);
    *y = v;
  }
}


x86 assembly (clang, -O0):
<mv_utt>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
mov    %esi,-0xc(%rbp)
mov    %rdx,-0x18(%rbp)
mov    %rcx,-0x20(%rbp)
mov    -0x8(%rbp),%rax
mov    -0xc(%rbp),%ecx
shl    $0x3,%rcx
add    %rcx,%rax
mov    %rax,-0x28(%rbp)
movl   $0x1,-0x2c(%rbp)
mov    -0x8(%rbp),%rax
cmp    -0x28(%rbp),%rax
je     11cf <mv_utt+0xcf>
xorps  %xmm0,%xmm0
movsd  %xmm0,-0x38(%rbp)
mov    -0x20(%rbp),%rax
mov    %rax,-0x40(%rbp)
mov    -0x20(%rbp),%rax
mov    -0x2c(%rbp),%ecx
shl    $0x3,%rcx
add    %rcx,%rax
mov    %rax,-0x48(%rbp)
mov    -0x40(%rbp),%rax
cmp    -0x48(%rbp),%rax
je     11a8 <mv_utt+0xa8>
mov    -0x18(%rbp),%rax
mov    %rax,%rcx
add    $0x8,%rcx
mov    %rcx,-0x18(%rbp)
movsd  (%rax),%xmm0
mov    -0x40(%rbp),%rax
movsd  (%rax),%xmm2
movsd  -0x38(%rbp),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x38(%rbp)
mov    -0x40(%rbp),%rax
add    $0x8,%rax
mov    %rax,-0x40(%rbp)
jmp    115c <mv_utt+0x5c>
movsd  -0x38(%rbp),%xmm0
mov    -0x8(%rbp),%rax
movsd  %xmm0,(%rax)
mov    -0x8(%rbp),%rax
add    $0x8,%rax
mov    %rax,-0x8(%rbp)
mov    -0x2c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x2c(%rbp)
jmp    112c <mv_utt+0x2c>
pop    %rbp
ret

x86 assembly (clang, -O2):
<mv_utt>:
test   %esi,%esi
je     11e8 <mv_utt+0xe8>
mov    %esi,%eax
lea    (%rdi,%rax,8),%r8
mov    $0x1,%r9d
xor    %r10d,%r10d
jmp    1139 <mv_utt+0x39>
nopl   0x0(%rax)
movsd  %xmm0,(%rdi)
add    $0x8,%rdi
add    $0x1,%r9
add    $0x1,%r10
cmp    %r8,%rdi
je     11e8 <mv_utt+0xe8>
lea    0x1(%r10),%eax
test   $0x3,%al
je     1180 <mv_utt+0x80>
mov    %r9d,%eax
and    $0x3,%eax
xorpd  %xmm0,%xmm0
mov    %rcx,%rsi
xchg   %ax,%ax
movsd  (%rdx),%xmm1
mulsd  (%rsi),%xmm1
add    $0x8,%rdx
addsd  %xmm1,%xmm0
add    $0x8,%rsi
add    $0xffffffffffffffff,%rax
jne    1150 <mv_utt+0x50>
cmp    $0x3,%r10
jb     1120 <mv_utt+0x20>
jmp    118d <mv_utt+0x8d>
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax)
xorpd  %xmm0,%xmm0
mov    %rcx,%rsi
cmp    $0x3,%r10
jb     1120 <mv_utt+0x20>
lea    (%rcx,%r9,8),%rax
cs nopw 0x0(%rax,%rax,1)
nopl   0x0(%rax,%rax,1)
movsd  (%rdx),%xmm1
mulsd  (%rsi),%xmm1
movsd  0x8(%rdx),%xmm2
addsd  %xmm0,%xmm1
mulsd  0x8(%rsi),%xmm2
addsd  %xmm1,%xmm2
movsd  0x10(%rdx),%xmm1
mulsd  0x10(%rsi),%xmm1
addsd  %xmm2,%xmm1
movsd  0x18(%rdx),%xmm0
mulsd  0x18(%rsi),%xmm0
add    $0x20,%rdx
addsd  %xmm1,%xmm0
add    $0x20,%rsi
cmp    %rax,%rsi
jne    11a0 <mv_utt+0xa0>
jmp    1120 <mv_utt+0x20>
ret

LLVM IR (-O0):
define void @mv_utt(double* %0, i32 %1, double* %2, double* %3) {
%5 = alloca double*
%6 = alloca i32
%7 = alloca double*
%8 = alloca double*
%9 = alloca double*
%10 = alloca i32
%11 = alloca double
%12 = alloca double*
%13 = alloca double*
store double* %0, double** %5
store i32 %1, i32* %6
store double* %2, double** %7
store double* %3, double** %8
%14 = load double*, double** %5
%15 = load i32, i32* %6
%16 = zext i32 %15 to i64
%17 = getelementptr inbounds double, double* %14, i64 %16
store double* %17, double** %9
store i32 1, i32* %10
br label %18
18: ; preds = %46, %4
%19 = load double*, double** %5
%20 = load double*, double** %9
%21 = icmp ne double* %19, %20
br i1 %21, label %22, label %51
22: ; preds = %18
store double 0.000000e+00, double* %11
%23 = load double*, double** %8
store double* %23, double** %12
%24 = load double*, double** %8
%25 = load i32, i32* %10
%26 = zext i32 %25 to i64
%27 = getelementptr inbounds double, double* %24, i64 %26
store double* %27, double** %13
br label %28
28: ; preds = %40, %22
%29 = load double*, double** %12
%30 = load double*, double** %13
%31 = icmp ne double* %29, %30
br i1 %31, label %32, label %43
32: ; preds = %28
%33 = load double*, double** %7
%34 = getelementptr inbounds double, double* %33, i32 1
store double* %34, double** %7
%35 = load double, double* %33
%36 = load double*, double** %12
%37 = load double, double* %36
%38 = load double, double* %11
%39 = call double @llvm.fmuladd.f64(double %35, double %37, double %38)
store double %39, double* %11
br label %40
40: ; preds = %32
%41 = load double*, double** %12
%42 = getelementptr inbounds double, double* %41, i32 1
store double* %42, double** %12
br label %28
43: ; preds = %28
%44 = load double, double* %11
%45 = load double*, double** %5
store double %44, double* %45
br label %46
46: ; preds = %43
%47 = load double*, double** %5
%48 = getelementptr inbounds double, double* %47, i32 1
store double* %48, double** %5
%49 = load i32, i32* %10
%50 = add i32 %49, 1
store i32 %50, i32* %10
br label %18
51: ; preds = %18
ret void
}

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