double fir_split(double input, int ntaps, double h[], double z[],
                 int *p_state) {
  int ii, end_ntaps, state = *p_state;
  double accum;
  double const *p_h;
  double *p_z;
  accum = 0;
  p_h = h;
  p_z = z + state;
  *p_z = input;
  end_ntaps = ntaps - state;
  for (ii = 0; ii < end_ntaps; ii++) {
    accum += *p_h++ * *p_z++;
  }
  p_z = z;
  for (ii = 0; ii < state; ii++) {
    accum += *p_h++ * *p_z++;
  }
  if (--state < 0) {
    state += ntaps;
  }
  *p_state = state;
  return accum;
}


x86 assembly (clang, -O0):
<fir_split>:
push   %rbp
mov    %rsp,%rbp
movsd  %xmm0,-0x8(%rbp)
mov    %edi,-0xc(%rbp)
mov    %rsi,-0x18(%rbp)
mov    %rdx,-0x20(%rbp)
mov    %rcx,-0x28(%rbp)
mov    -0x28(%rbp),%rax
mov    (%rax),%eax
mov    %eax,-0x34(%rbp)
xorps  %xmm0,%xmm0
movsd  %xmm0,-0x40(%rbp)
mov    -0x18(%rbp),%rax
mov    %rax,-0x48(%rbp)
mov    -0x20(%rbp),%rax
movslq -0x34(%rbp),%rcx
shl    $0x3,%rcx
add    %rcx,%rax
mov    %rax,-0x50(%rbp)
movsd  -0x8(%rbp),%xmm0
mov    -0x50(%rbp),%rax
movsd  %xmm0,(%rax)
mov    -0xc(%rbp),%eax
sub    -0x34(%rbp),%eax
mov    %eax,-0x30(%rbp)
movl   $0x0,-0x2c(%rbp)
mov    -0x2c(%rbp),%eax
cmp    -0x30(%rbp),%eax
jge    11b3 <fir_split+0xb3>
mov    -0x48(%rbp),%rax
mov    %rax,%rcx
add    $0x8,%rcx
mov    %rcx,-0x48(%rbp)
movsd  (%rax),%xmm0
mov    -0x50(%rbp),%rax
mov    %rax,%rcx
add    $0x8,%rcx
mov    %rcx,-0x50(%rbp)
movsd  (%rax),%xmm2
movsd  -0x40(%rbp),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x40(%rbp)
mov    -0x2c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x2c(%rbp)
jmp    1161 <fir_split+0x61>
mov    -0x20(%rbp),%rax
mov    %rax,-0x50(%rbp)
movl   $0x0,-0x2c(%rbp)
mov    -0x2c(%rbp),%eax
cmp    -0x34(%rbp),%eax
jge    1214 <fir_split+0x114>
mov    -0x48(%rbp),%rax
mov    %rax,%rcx
add    $0x8,%rcx
mov    %rcx,-0x48(%rbp)
movsd  (%rax),%xmm0
mov    -0x50(%rbp),%rax
mov    %rax,%rcx
add    $0x8,%rcx
mov    %rcx,-0x50(%rbp)
movsd  (%rax),%xmm2
movsd  -0x40(%rbp),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x40(%rbp)
mov    -0x2c(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x2c(%rbp)
jmp    11c2 <fir_split+0xc2>
mov    -0x34(%rbp),%eax
add    $0xffffffff,%eax
mov    %eax,-0x34(%rbp)
cmp    $0x0,%eax
jge    122f <fir_split+0x12f>
mov    -0xc(%rbp),%eax
add    -0x34(%rbp),%eax
mov    %eax,-0x34(%rbp)
mov    -0x34(%rbp),%ecx
mov    -0x28(%rbp),%rax
mov    %ecx,(%rax)
movsd  -0x40(%rbp),%xmm0
pop    %rbp
ret

x86 assembly (clang, -O2):
<fir_split>:
push   %rbx
movslq (%rcx),%rax
mov    %eax,%r8d
movsd  %xmm0,(%rdx,%rax,8)
mov    %edi,%ebx
sub    %eax,%ebx
test   %ebx,%ebx
jle    11ed <fir_split+0xed>
movapd %xmm0,%xmm1
mulsd  (%rsi),%xmm1
add    $0x8,%rsi
xorpd  %xmm0,%xmm0
addsd  %xmm1,%xmm0
cmp    $0x1,%ebx
je     11f1 <fir_split+0xf1>
lea    (%rdx,%rax,8),%r11
mov    %edi,%eax
sub    %r8d,%eax
mov    %r8d,%r9d
not    %r9d
add    %edi,%r9d
add    $0xfffffffe,%eax
cmp    $0x3,%eax
jb     11b6 <fir_split+0xb6>
mov    %r9d,%r10d
and    $0xfffffffc,%r10d
xor    %ebx,%ebx
xor    %eax,%eax
nopw   0x0(%rax,%rax,1)
movsd  (%rsi,%rbx,8),%xmm1
mulsd  0x8(%r11,%rbx,8),%xmm1
movsd  0x8(%rsi,%rbx,8),%xmm2
addsd  %xmm0,%xmm1
mulsd  0x10(%r11,%rbx,8),%xmm2
addsd  %xmm1,%xmm2
movsd  0x10(%rsi,%rbx,8),%xmm1
mulsd  0x18(%r11,%rbx,8),%xmm1
addsd  %xmm2,%xmm1
movsd  0x18(%rsi,%rbx,8),%xmm0
mulsd  0x20(%r11,%rbx,8),%xmm0
addsd  %xmm1,%xmm0
add    $0xffffffffffffffe0,%rax
add    $0x4,%rbx
cmp    %ebx,%r10d
jne    1160 <fir_split+0x60>
sub    %rax,%r11
sub    %rax,%rsi
test   $0x3,%r9b
je     11f1 <fir_split+0xf1>
mov    %r8d,%eax
not    %al
add    %dil,%al
movzbl %al,%eax
and    $0x3,%eax
shl    $0x3,%rax
xor    %ebx,%ebx
movsd  (%rsi,%rbx,1),%xmm1
mulsd  0x8(%r11,%rbx,1),%xmm1
addsd  %xmm1,%xmm0
add    $0x8,%rbx
cmp    %ebx,%eax
jne    11d0 <fir_split+0xd0>
add    %rbx,%rsi
jmp    11f1 <fir_split+0xf1>
xorpd  %xmm0,%xmm0
test   %r8d,%r8d
jle    128a <fir_split+0x18a>
lea    -0x1(%r8),%eax
cmp    $0x3,%eax
jb     1260 <fir_split+0x160>
mov    %r8d,%eax
and    $0xfffffffc,%eax
xor    %ebx,%ebx
xor    %edi,%edi
nopl   (%rax)
movsd  (%rsi,%rbx,8),%xmm1
mulsd  (%rdx,%rbx,8),%xmm1
movsd  0x8(%rsi,%rbx,8),%xmm2
addsd  %xmm0,%xmm1
mulsd  0x8(%rdx,%rbx,8),%xmm2
addsd  %xmm1,%xmm2
movsd  0x10(%rsi,%rbx,8),%xmm1
mulsd  0x10(%rdx,%rbx,8),%xmm1
addsd  %xmm2,%xmm1
movsd  0x18(%rsi,%rbx,8),%xmm0
mulsd  0x18(%rdx,%rbx,8),%xmm0
addsd  %xmm1,%xmm0
add    $0xffffffffffffffe0,%rdi
add    $0x4,%rbx
cmp    %ebx,%eax
jne    1210 <fir_split+0x110>
sub    %rdi,%rdx
sub    %rdi,%rsi
test   $0x3,%r8b
je     1288 <fir_split+0x188>
mov    %r8d,%eax
and    $0x3,%eax
xor    %edi,%edi
xor    %ebx,%ebx
movsd  (%rsi,%rbx,8),%xmm1
mulsd  (%rdx,%rbx,8),%xmm1
addsd  %xmm1,%xmm0
add    $0x1,%rbx
cmp    %ebx,%eax
jne    1270 <fir_split+0x170>
jmp    128a <fir_split+0x18a>
xor    %edi,%edi
lea    (%r8,%rdi,1),%eax
add    $0xffffffff,%eax
mov    %eax,(%rcx)
pop    %rbx
ret

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

LLVM IR (-O2):
define double @fir_split(double %0, i32 %1, double* nocapture %2, double* nocapture %3, i32* nocapture %4) {
%6 = load i32, i32* %4
%7 = sext i32 %6 to i64
%8 = getelementptr inbounds double, double* %3, i64 %7
store double %0, double* %8
%9 = sub i32 %1, %6
%10 = icmp sgt i32 %9, 0
br i1 %10, label %11, label %44
11: ; preds = %5
%12 = getelementptr inbounds double, double* %2, i64 1
%13 = load double, double* %2
%14 = tail call double @llvm.fmuladd.f64(double %13, double %0, double 0.000000e+00)
%15 = icmp eq i32 %9, 1
br i1 %15, label %44, label %16
16: ; preds = %11
%17 = xor i32 %6, -1
%18 = add i32 %17, %1
%19 = add i32 %1, -2
%20 = sub i32 %19, %6
%21 = and i32 %18, 3
%22 = icmp ult i32 %20, 3
br i1 %22, label %25, label %23
23: ; preds = %16
%24 = and i32 %18, -4
br label %54
25: ; preds = %54, %16
%26 = phi double* [ undef, %16 ], [ %76, %54 ]
%27 = phi double [ undef, %16 ], [ %78, %54 ]
%28 = phi double [ %14, %16 ], [ %78, %54 ]
%29 = phi double* [ %8, %16 ], [ %74, %54 ]
%30 = phi double* [ %12, %16 ], [ %76, %54 ]
%31 = icmp eq i32 %21, 0
br i1 %31, label %44, label %32
32: ; preds = %25, %32
%33 = phi double [ %41, %32 ], [ %28, %25 ]
%34 = phi double* [ %37, %32 ], [ %29, %25 ]
%35 = phi double* [ %39, %32 ], [ %30, %25 ]
%36 = phi i32 [ %42, %32 ], [ 0, %25 ]
%37 = getelementptr inbounds double, double* %34, i64 1
%38 = load double, double* %37
%39 = getelementptr inbounds double, double* %35, i64 1
%40 = load double, double* %35
%41 = tail call double @llvm.fmuladd.f64(double %40, double %38, double %33)
%42 = add i32 %36, 1
%43 = icmp eq i32 %42, %21
br i1 %43, label %44, label %32
44: ; preds = %25, %32, %11, %5
%45 = phi double [ 0.000000e+00, %5 ], [ %14, %11 ], [ %27, %25 ], [ %41, %32 ]
%46 = phi double* [ %2, %5 ], [ %12, %11 ], [ %26, %25 ], [ %39, %32 ]
%47 = icmp sgt i32 %6, 0
br i1 %47, label %48, label %126
48: ; preds = %44
%49 = add i32 %6, -1
%50 = and i32 %6, 3
%51 = icmp ult i32 %49, 3
br i1 %51, label %108, label %52
52: ; preds = %48
%53 = and i32 %6, -4
br label %81
54: ; preds = %54, %23
%55 = phi double [ %14, %23 ], [ %78, %54 ]
%56 = phi double* [ %8, %23 ], [ %74, %54 ]
%57 = phi double* [ %12, %23 ], [ %76, %54 ]
%58 = phi i32 [ 0, %23 ], [ %79, %54 ]
%59 = getelementptr inbounds double, double* %56, i64 1
%60 = load double, double* %59
%61 = getelementptr inbounds double, double* %57, i64 1
%62 = load double, double* %57
%63 = tail call double @llvm.fmuladd.f64(double %62, double %60, double %55)
%64 = getelementptr inbounds double, double* %56, i64 2
%65 = load double, double* %64
%66 = getelementptr inbounds double, double* %57, i64 2
%67 = load double, double* %61
%68 = tail call double @llvm.fmuladd.f64(double %67, double %65, double %63)
%69 = getelementptr inbounds double, double* %56, i64 3
%70 = load double, double* %69
%71 = getelementptr inbounds double, double* %57, i64 3
%72 = load double, double* %66
%73 = tail call double @llvm.fmuladd.f64(double %72, double %70, double %68)
%74 = getelementptr inbounds double, double* %56, i64 4
%75 = load double, double* %74
%76 = getelementptr inbounds double, double* %57, i64 4
%77 = load double, double* %71
%78 = tail call double @llvm.fmuladd.f64(double %77, double %75, double %73)
%79 = add i32 %58, 4
%80 = icmp eq i32 %79, %24
br i1 %80, label %25, label %54
81: ; preds = %81, %52
%82 = phi double* [ %3, %52 ], [ %103, %81 ]
%83 = phi double* [ %46, %52 ], [ %101, %81 ]
%84 = phi double [ %45, %52 ], [ %105, %81 ]
%85 = phi i32 [ 0, %52 ], [ %106, %81 ]
%86 = getelementptr inbounds double, double* %83, i64 1
%87 = load double, double* %83
%88 = getelementptr inbounds double, double* %82, i64 1
%89 = load double, double* %82
%90 = tail call double @llvm.fmuladd.f64(double %87, double %89, double %84)
%91 = getelementptr inbounds double, double* %83, i64 2
%92 = load double, double* %86
%93 = getelementptr inbounds double, double* %82, i64 2
%94 = load double, double* %88
%95 = tail call double @llvm.fmuladd.f64(double %92, double %94, double %90)
%96 = getelementptr inbounds double, double* %83, i64 3
%97 = load double, double* %91
%98 = getelementptr inbounds double, double* %82, i64 3
%99 = load double, double* %93
%100 = tail call double @llvm.fmuladd.f64(double %97, double %99, double %95)
%101 = getelementptr inbounds double, double* %83, i64 4
%102 = load double, double* %96
%103 = getelementptr inbounds double, double* %82, i64 4
%104 = load double, double* %98
%105 = tail call double @llvm.fmuladd.f64(double %102, double %104, double %100)
%106 = add i32 %85, 4
%107 = icmp eq i32 %106, %53
br i1 %107, label %108, label %81
108: ; preds = %81, %48
%109 = phi double [ undef, %48 ], [ %105, %81 ]
%110 = phi double* [ %3, %48 ], [ %103, %81 ]
%111 = phi double* [ %46, %48 ], [ %101, %81 ]
%112 = phi double [ %45, %48 ], [ %105, %81 ]
%113 = icmp eq i32 %50, 0
br i1 %113, label %126, label %114
114: ; preds = %108, %114
%115 = phi double* [ %121, %114 ], [ %110, %108 ]
%116 = phi double* [ %119, %114 ], [ %111, %108 ]
%117 = phi double [ %123, %114 ], [ %112, %108 ]
%118 = phi i32 [ %124, %114 ], [ 0, %108 ]
%119 = getelementptr inbounds double, double* %116, i64 1
%120 = load double, double* %116
%121 = getelementptr inbounds double, double* %115, i64 1
%122 = load double, double* %115
%123 = tail call double @llvm.fmuladd.f64(double %120, double %122, double %117)
%124 = add i32 %118, 1
%125 = icmp eq i32 %124, %50
br i1 %125, label %126, label %114
126: ; preds = %108, %114, %44
%127 = phi i32 [ %1, %44 ], [ 0, %114 ], [ 0, %108 ]
%128 = phi double [ %45, %44 ], [ %109, %108 ], [ %123, %114 ]
%129 = add nsw i32 %6, -1
%130 = add nsw i32 %129, %127
store i32 %130, i32* %4
ret double %128
}