double poly(double a[], double x, long degree) {
  long i;
  double result = a[0];
  double xpwr = x;
  for (i = 1; i <= degree; i++) {
    result += a[i] * xpwr;
    xpwr = x * xpwr;
  }
  return result;
}


x86 assembly (clang, -O0):
<poly>:
push   %rbp
mov    %rsp,%rbp
mov    %rdi,-0x8(%rbp)
movsd  %xmm0,-0x10(%rbp)
mov    %rsi,-0x18(%rbp)
mov    -0x8(%rbp),%rax
movsd  (%rax),%xmm0
movsd  %xmm0,-0x28(%rbp)
movsd  -0x10(%rbp),%xmm0
movsd  %xmm0,-0x30(%rbp)
movq   $0x1,-0x20(%rbp)
mov    -0x20(%rbp),%rax
cmp    -0x18(%rbp),%rax
jg     1182 <poly+0x82>
mov    -0x8(%rbp),%rax
mov    -0x20(%rbp),%rcx
movsd  (%rax,%rcx,8),%xmm0
movsd  -0x30(%rbp),%xmm2
movsd  -0x28(%rbp),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x28(%rbp)
movsd  -0x10(%rbp),%xmm0
mulsd  -0x30(%rbp),%xmm0
movsd  %xmm0,-0x30(%rbp)
mov    -0x20(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x20(%rbp)
jmp    1130 <poly+0x30>
movsd  -0x28(%rbp),%xmm0
pop    %rbp
ret

x86 assembly (clang, -O2):
<poly>:
movsd  (%rdi),%xmm1
test   %rsi,%rsi
jle    11ba <poly+0xba>
lea    -0x1(%rsi),%rcx
mov    %esi,%eax
and    $0x3,%eax
cmp    $0x3,%rcx
jae    112f <poly+0x2f>
mov    $0x1,%ecx
movapd %xmm0,%xmm2
test   %rax,%rax
jne    119a <poly+0x9a>
jmp    11ba <poly+0xba>
and    $0xfffffffffffffffc,%rsi
xor    %ecx,%ecx
movapd %xmm0,%xmm2
nopl   0x0(%rax)
movsd  0x8(%rdi,%rcx,8),%xmm3
mulsd  %xmm2,%xmm3
addsd  %xmm1,%xmm3
mulsd  %xmm0,%xmm2
movsd  0x10(%rdi,%rcx,8),%xmm1
mulsd  %xmm2,%xmm1
addsd  %xmm3,%xmm1
mulsd  %xmm0,%xmm2
movsd  0x18(%rdi,%rcx,8),%xmm3
mulsd  %xmm2,%xmm3
addsd  %xmm1,%xmm3
mulsd  %xmm0,%xmm2
movsd  0x20(%rdi,%rcx,8),%xmm1
mulsd  %xmm2,%xmm1
addsd  %xmm3,%xmm1
mulsd  %xmm0,%xmm2
add    $0x4,%rcx
cmp    %rcx,%rsi
jne    1140 <poly+0x40>
add    $0x1,%rcx
test   %rax,%rax
je     11ba <poly+0xba>
lea    (%rdi,%rcx,8),%rcx
xor    %edx,%edx
movsd  (%rcx,%rdx,8),%xmm3
mulsd  %xmm2,%xmm3
addsd  %xmm3,%xmm1
mulsd  %xmm0,%xmm2
add    $0x1,%rdx
cmp    %rdx,%rax
jne    11a0 <poly+0xa0>
movapd %xmm1,%xmm0
ret

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

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