double chebpoly(const double x, double *c, const int mh) {
  int i;
  double b[3];
  b[1] = b[2] = 0.0;
  for (i = mh; i > 0; i--) {
    b[0] = 2.0 * x * b[1] - b[2] + c[i];
    b[2] = b[1];
    b[1] = b[0];
  }
  b[0] = x * b[1] - b[2] + c[0];
  return (b[0]);
}


x86 assembly (clang, -O0):
<chebpoly>:
push   %rbp
mov    %rsp,%rbp
movsd  %xmm0,-0x8(%rbp)
mov    %rdi,-0x10(%rbp)
mov    %esi,-0x14(%rbp)
xorps  %xmm0,%xmm0
movsd  %xmm0,-0x20(%rbp)
xorps  %xmm0,%xmm0
movsd  %xmm0,-0x28(%rbp)
mov    -0x14(%rbp),%eax
mov    %eax,-0x18(%rbp)
cmpl   $0x0,-0x18(%rbp)
jle    119a <chebpoly+0x9a>
movsd  0xec8(%rip),%xmm0
mulsd  -0x8(%rbp),%xmm0
movsd  -0x28(%rbp),%xmm2
movsd  -0x20(%rbp),%xmm1
movq   %xmm1,%rax
movabs $0x8000000000000000,%rcx
xor    %rcx,%rax
movq   %rax,%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
mov    -0x10(%rbp),%rax
movslq -0x18(%rbp),%rcx
addsd  (%rax,%rcx,8),%xmm0
movsd  %xmm0,-0x30(%rbp)
movsd  -0x28(%rbp),%xmm0
movsd  %xmm0,-0x20(%rbp)
movsd  -0x30(%rbp),%xmm0
movsd  %xmm0,-0x28(%rbp)
mov    -0x18(%rbp),%eax
add    $0xffffffff,%eax
mov    %eax,-0x18(%rbp)
jmp    1126 <chebpoly+0x26>
movsd  -0x8(%rbp),%xmm0
movsd  -0x28(%rbp),%xmm2
movsd  -0x20(%rbp),%xmm1
movq   %xmm1,%rax
movabs $0x8000000000000000,%rcx
xor    %rcx,%rax
movq   %rax,%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
mov    -0x10(%rbp),%rax
addsd  (%rax),%xmm0
movsd  %xmm0,-0x30(%rbp)
movsd  -0x30(%rbp),%xmm0
pop    %rbp
ret

x86 assembly (clang, -O2):
<chebpoly>:
test   %esi,%esi
jle    115b <chebpoly+0x5b>
movapd %xmm0,%xmm1
addsd  %xmm0,%xmm1
mov    %esi,%eax
lea    -0x1(%rax),%rcx
mov    %rax,%rdx
xorpd  %xmm2,%xmm2
and    $0x3,%rdx
je     1165 <chebpoly+0x65>
xorpd  %xmm4,%xmm4
cs nopw 0x0(%rax,%rax,1)
nopl   (%rax)
movapd %xmm2,%xmm3
movapd %xmm1,%xmm2
mulsd  %xmm3,%xmm2
subsd  %xmm4,%xmm2
addsd  (%rdi,%rax,8),%xmm2
add    $0xffffffffffffffff,%rax
movapd %xmm3,%xmm4
add    $0xffffffffffffffff,%rdx
jne    1130 <chebpoly+0x30>
cmp    $0x3,%rcx
jae    116f <chebpoly+0x6f>
jmp    11d2 <chebpoly+0xd2>
xorpd  %xmm3,%xmm3
xorpd  %xmm2,%xmm2
jmp    11d2 <chebpoly+0xd2>
xorpd  %xmm3,%xmm3
cmp    $0x3,%rcx
jb     11d2 <chebpoly+0xd2>
add    $0x1,%rax
cs nopw 0x0(%rax,%rax,1)
nopl   (%rax)
movapd %xmm1,%xmm4
mulsd  %xmm2,%xmm4
subsd  %xmm3,%xmm4
addsd  -0x8(%rdi,%rax,8),%xmm4
movapd %xmm1,%xmm5
mulsd  %xmm4,%xmm5
subsd  %xmm2,%xmm5
addsd  -0x10(%rdi,%rax,8),%xmm5
movapd %xmm1,%xmm3
mulsd  %xmm5,%xmm3
subsd  %xmm4,%xmm3
addsd  -0x18(%rdi,%rax,8),%xmm3
movapd %xmm1,%xmm2
mulsd  %xmm3,%xmm2
subsd  %xmm5,%xmm2
addsd  -0x20(%rdi,%rax,8),%xmm2
add    $0xfffffffffffffffc,%rax
cmp    $0x1,%rax
ja     1180 <chebpoly+0x80>
mulsd  %xmm2,%xmm0
subsd  %xmm3,%xmm0
addsd  (%rdi),%xmm0
ret

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

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