double simpson(double (*fp)(double), double a, double b, int N) {
  double h = (b - a) / (N - 1), total = 0.0;
#pragma omp parallel for reduction(+ : total)
  for (int m = 0; m < N; m++) {
    double xj = m * h + a;
    double xc = xj + h / 2.0;
    total += 2.0 * fp(xj) + 4.0 * fp(xc);
  }
  total -= fp(a) + fp(b) + 4.0 * fp(b + h / 2.0);
  return (h / 6.0) * total;
}


x86 assembly (clang, -O0):
<simpson>:
push   %rbp
mov    %rsp,%rbp
sub    $0x60,%rsp
mov    %rdi,-0x8(%rbp)
movsd  %xmm0,-0x10(%rbp)
movsd  %xmm1,-0x18(%rbp)
mov    %esi,-0x1c(%rbp)
movsd  -0x18(%rbp),%xmm0
subsd  -0x10(%rbp),%xmm0
mov    -0x1c(%rbp),%eax
sub    $0x1,%eax
cvtsi2sd %eax,%xmm1
divsd  %xmm1,%xmm0
movsd  %xmm0,-0x28(%rbp)
xorps  %xmm0,%xmm0
movsd  %xmm0,-0x30(%rbp)
movl   $0x0,-0x34(%rbp)
mov    -0x34(%rbp),%eax
cmp    -0x1c(%rbp),%eax
jge    11db <simpson+0xdb>
cvtsi2sdl -0x34(%rbp),%xmm0
movsd  -0x28(%rbp),%xmm2
movsd  -0x10(%rbp),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x40(%rbp)
movsd  -0x40(%rbp),%xmm0
movsd  -0x28(%rbp),%xmm1
movsd  0xe91(%rip),%xmm2
divsd  %xmm2,%xmm1
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x48(%rbp)
mov    -0x8(%rbp),%rax
movsd  -0x40(%rbp),%xmm0
call   *%rax
movsd  %xmm0,-0x50(%rbp)
mov    -0x8(%rbp),%rax
movsd  -0x48(%rbp),%xmm0
call   *%rax
movaps %xmm0,%xmm2
movsd  -0x50(%rbp),%xmm0
movsd  0xe51(%rip),%xmm1
mulsd  %xmm2,%xmm1
addsd  %xmm0,%xmm0
addsd  %xmm1,%xmm0
addsd  -0x30(%rbp),%xmm0
movsd  %xmm0,-0x30(%rbp)
mov    -0x34(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x34(%rbp)
jmp    1145 <simpson+0x45>
mov    -0x8(%rbp),%rax
movsd  -0x10(%rbp),%xmm0
call   *%rax
movsd  %xmm0,-0x60(%rbp)
mov    -0x8(%rbp),%rax
movsd  -0x18(%rbp),%xmm0
call   *%rax
movaps %xmm0,%xmm1
movsd  -0x60(%rbp),%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x58(%rbp)
mov    -0x8(%rbp),%rax
movsd  -0x18(%rbp),%xmm0
movsd  -0x28(%rbp),%xmm1
movsd  0xdf3(%rip),%xmm2
divsd  %xmm2,%xmm1
addsd  %xmm1,%xmm0
call   *%rax
movaps %xmm0,%xmm1
movsd  -0x58(%rbp),%xmm0
movsd  0xdd1(%rip),%xmm2
mulsd  %xmm2,%xmm1
addsd  %xmm0,%xmm1
movsd  -0x30(%rbp),%xmm0
subsd  %xmm1,%xmm0
movsd  %xmm0,-0x30(%rbp)
movsd  -0x28(%rbp),%xmm0
movsd  0xda6(%rip),%xmm1
divsd  %xmm1,%xmm0
mulsd  -0x30(%rbp),%xmm0
add    $0x60,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<simpson>:
push   %r14
push   %rbx
sub    $0x48,%rsp
mov    %esi,%ebx
movapd %xmm0,%xmm3
mov    %rdi,%r14
movsd  %xmm1,0x18(%rsp)
subsd  %xmm0,%xmm1
lea    -0x1(%rbx),%eax
xorps  %xmm0,%xmm0
cvtsi2sd %eax,%xmm0
divsd  %xmm0,%xmm1
movsd  0xed0(%rip),%xmm2
mulsd  %xmm1,%xmm2
test   %esi,%esi
movsd  %xmm1,0x28(%rsp)
movsd  %xmm2,0x20(%rsp)
xorpd  %xmm0,%xmm0
jle    11d9 <simpson+0xd9>
movsd  %xmm0,0x10(%rsp)
xorpd  %xmm0,%xmm0
movsd  %xmm3,0x30(%rsp)
nopl   0x0(%rax)
movsd  %xmm0,0x8(%rsp)
movsd  0x8(%rsp),%xmm0
mulsd  0x28(%rsp),%xmm0
addsd  %xmm3,%xmm0
movsd  0x20(%rsp),%xmm1
addsd  %xmm0,%xmm1
movsd  %xmm1,0x38(%rsp)
call   *%r14
movsd  %xmm0,0x40(%rsp)
movsd  0x38(%rsp),%xmm0
call   *%r14
movsd  0x30(%rsp),%xmm3
mulsd  0xe62(%rip),%xmm0
movsd  0x40(%rsp),%xmm1
addsd  %xmm1,%xmm1
addsd  %xmm0,%xmm1
movsd  0x10(%rsp),%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,0x10(%rsp)
movsd  0x8(%rsp),%xmm0
addsd  0xe3e(%rip),%xmm0
add    $0xffffffff,%ebx
jne    1160 <simpson+0x60>
jmp    11df <simpson+0xdf>
movsd  %xmm0,0x10(%rsp)
movapd %xmm3,%xmm0
call   *%r14
movsd  %xmm0,0x8(%rsp)
movsd  0x18(%rsp),%xmm0
call   *%r14
addsd  0x8(%rsp),%xmm0
movsd  %xmm0,0x8(%rsp)
movsd  0x20(%rsp),%xmm0
addsd  0x18(%rsp),%xmm0
call   *%r14
mulsd  0xdf0(%rip),%xmm0
addsd  0x8(%rsp),%xmm0
movsd  0x10(%rsp),%xmm1
subsd  %xmm0,%xmm1
movsd  0x28(%rsp),%xmm0
divsd  0xde2(%rip),%xmm0
mulsd  %xmm1,%xmm0
add    $0x48,%rsp
pop    %rbx
pop    %r14
ret

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

LLVM IR (-O2):
define double @simpson(double (double)* nocapture %0, double %1, double %2, i32 %3) {
%5 = fsub double %2, %1
%6 = add nsw i32 %3, -1
%7 = sitofp i32 %6 to double
%8 = fdiv double %5, %7
%9 = icmp sgt i32 %3, 0
%10 = fmul double %8, 5.000000e-01
br i1 %9, label %22, label %11
11: ; preds = %22, %4
%12 = phi double [ 0.000000e+00, %4 ], [ %32, %22 ]
%13 = tail call double %0(double %1)
%14 = tail call double %0(double %2)
%15 = fadd double %13, %14
%16 = fadd double %10, %2
%17 = tail call double %0(double %16)
%18 = tail call double @llvm.fmuladd.f64(double %17, double 4.000000e+00, double %15)
%19 = fsub double %12, %18
%20 = fdiv double %8, 6.000000e+00
%21 = fmul double %20, %19
ret double %21
22: ; preds = %4, %22
%23 = phi double [ %32, %22 ], [ 0.000000e+00, %4 ]
%24 = phi i32 [ %33, %22 ], [ 0, %4 ]
%25 = sitofp i32 %24 to double
%26 = tail call double @llvm.fmuladd.f64(double %25, double %8, double %1)
%27 = fadd double %10, %26
%28 = tail call double %0(double %26)
%29 = tail call double %0(double %27)
%30 = fmul double %29, 4.000000e+00
%31 = tail call double @llvm.fmuladd.f64(double %28, double 2.000000e+00, double %30)
%32 = fadd double %23, %31
%33 = add nuw nsw i32 %24, 1
%34 = icmp eq i32 %33, %3
br i1 %34, label %11, label %22
}