int PID(double setpoint, double *yt, double *iterm, double kp, double ki,
        double kd, int out_max, int i_max) {
  double error, dyt;
  double ut;
  error = setpoint - yt[0];
  *iterm += ki * error;
  if (*iterm > i_max)
    *iterm = i_max;
  else if (*iterm < -i_max)
    *iterm = -i_max;
  dyt = (yt[0] - yt[1]);
  ut = kp * error + *iterm - kd * dyt;
  if (ut > out_max)
    ut = out_max;
  else if (ut < -out_max)
    ut = -out_max;
  yt[1] = yt[0];
  return (int)ut;
}


x86 assembly (clang, -O0):
<PID>:
push   %rbp
mov    %rsp,%rbp
movsd  %xmm0,-0x8(%rbp)
mov    %rdi,-0x10(%rbp)
mov    %rsi,-0x18(%rbp)
movsd  %xmm1,-0x20(%rbp)
movsd  %xmm2,-0x28(%rbp)
movsd  %xmm3,-0x30(%rbp)
mov    %edx,-0x34(%rbp)
mov    %ecx,-0x38(%rbp)
movsd  -0x8(%rbp),%xmm0
mov    -0x10(%rbp),%rax
subsd  (%rax),%xmm0
movsd  %xmm0,-0x40(%rbp)
movsd  -0x28(%rbp),%xmm0
movsd  -0x40(%rbp),%xmm2
mov    -0x18(%rbp),%rax
movsd  (%rax),%xmm1
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,(%rax)
mov    -0x18(%rbp),%rax
movsd  (%rax),%xmm0
cvtsi2sdl -0x38(%rbp),%xmm1
ucomisd %xmm1,%xmm0
jbe    117f <PID+0x7f>
cvtsi2sdl -0x38(%rbp),%xmm0
mov    -0x18(%rbp),%rax
movsd  %xmm0,(%rax)
jmp    11b0 <PID+0xb0>
mov    -0x18(%rbp),%rax
movsd  (%rax),%xmm1
xor    %eax,%eax
sub    -0x38(%rbp),%eax
cvtsi2sd %eax,%xmm0
ucomisd %xmm1,%xmm0
jbe    11ab <PID+0xab>
xor    %eax,%eax
sub    -0x38(%rbp),%eax
cvtsi2sd %eax,%xmm0
mov    -0x18(%rbp),%rax
movsd  %xmm0,(%rax)
jmp    11b0 <PID+0xb0>
mov    -0x10(%rbp),%rax
movsd  (%rax),%xmm0
mov    -0x10(%rbp),%rax
subsd  0x8(%rax),%xmm0
movsd  %xmm0,-0x48(%rbp)
movsd  -0x20(%rbp),%xmm1
movsd  -0x40(%rbp),%xmm2
mov    -0x18(%rbp),%rax
movsd  (%rax),%xmm0
mulsd  %xmm2,%xmm1
addsd  %xmm0,%xmm1
movsd  -0x30(%rbp),%xmm0
movsd  -0x48(%rbp),%xmm2
movq   %xmm0,%rax
movabs $0x8000000000000000,%rcx
xor    %rcx,%rax
movq   %rax,%xmm0
mulsd  %xmm2,%xmm0
addsd  %xmm1,%xmm0
movsd  %xmm0,-0x50(%rbp)
movsd  -0x50(%rbp),%xmm0
cvtsi2sdl -0x34(%rbp),%xmm1
ucomisd %xmm1,%xmm0
jbe    1231 <PID+0x131>
cvtsi2sdl -0x34(%rbp),%xmm0
movsd  %xmm0,-0x50(%rbp)
jmp    125c <PID+0x15c>
movsd  -0x50(%rbp),%xmm1
xor    %eax,%eax
sub    -0x34(%rbp),%eax
cvtsi2sd %eax,%xmm0
ucomisd %xmm1,%xmm0
jbe    1257 <PID+0x157>
xor    %eax,%eax
sub    -0x34(%rbp),%eax
cvtsi2sd %eax,%xmm0
movsd  %xmm0,-0x50(%rbp)
jmp    125c <PID+0x15c>
mov    -0x10(%rbp),%rax
movsd  (%rax),%xmm0
mov    -0x10(%rbp),%rax
movsd  %xmm0,0x8(%rax)
cvttsd2si -0x50(%rbp),%eax
pop    %rbp
ret

x86 assembly (clang, -O2):
<PID>:
subsd  (%rdi),%xmm0
mulsd  %xmm0,%xmm2
addsd  (%rsi),%xmm2
movsd  %xmm2,(%rsi)
cvtsi2sd %ecx,%xmm4
ucomisd %xmm4,%xmm2
ja     1129 <PID+0x29>
neg    %ecx
xorps  %xmm4,%xmm4
cvtsi2sd %ecx,%xmm4
ucomisd %xmm2,%xmm4
jbe    1131 <PID+0x31>
movsd  %xmm4,(%rsi)
movapd %xmm4,%xmm2
movsd  (%rdi),%xmm4
movapd %xmm4,%xmm5
subsd  0x8(%rdi),%xmm5
mulsd  %xmm0,%xmm1
addsd  %xmm2,%xmm1
mulsd  %xmm5,%xmm3
subsd  %xmm3,%xmm1
xorps  %xmm0,%xmm0
cvtsi2sd %edx,%xmm0
ucomisd %xmm0,%xmm1
ja     1172 <PID+0x72>
neg    %edx
xorps  %xmm2,%xmm2
cvtsi2sd %edx,%xmm2
ucomisd %xmm1,%xmm2
movapd %xmm1,%xmm0
jbe    1172 <PID+0x72>
movapd %xmm2,%xmm0
movsd  %xmm4,0x8(%rdi)
cvttsd2si %xmm0,%eax
ret

LLVM IR (-O0):
define i32 @PID(double %0, double* %1, double* %2, double %3, double %4, double %5, i32 %6, i32 %7) {
%9 = alloca double
%10 = alloca double*
%11 = alloca double*
%12 = alloca double
%13 = alloca double
%14 = alloca double
%15 = alloca i32
%16 = alloca i32
%17 = alloca double
%18 = alloca double
%19 = alloca double
store double %0, double* %9
store double* %1, double** %10
store double* %2, double** %11
store double %3, double* %12
store double %4, double* %13
store double %5, double* %14
store i32 %6, i32* %15
store i32 %7, i32* %16
%20 = load double, double* %9
%21 = load double*, double** %10
%22 = getelementptr inbounds double, double* %21, i64 0
%23 = load double, double* %22
%24 = fsub double %20, %23
store double %24, double* %17
%25 = load double, double* %13
%26 = load double, double* %17
%27 = load double*, double** %11
%28 = load double, double* %27
%29 = call double @llvm.fmuladd.f64(double %25, double %26, double %28)
store double %29, double* %27
%30 = load double*, double** %11
%31 = load double, double* %30
%32 = load i32, i32* %16
%33 = sitofp i32 %32 to double
%34 = fcmp ogt double %31, %33
br i1 %34, label %35, label %39
35: ; preds = %8
%36 = load i32, i32* %16
%37 = sitofp i32 %36 to double
%38 = load double*, double** %11
store double %37, double* %38
br label %52
39: ; preds = %8
%40 = load double*, double** %11
%41 = load double, double* %40
%42 = load i32, i32* %16
%43 = sub nsw i32 0, %42
%44 = sitofp i32 %43 to double
%45 = fcmp olt double %41, %44
br i1 %45, label %46, label %51
46: ; preds = %39
%47 = load i32, i32* %16
%48 = sub nsw i32 0, %47
%49 = sitofp i32 %48 to double
%50 = load double*, double** %11
store double %49, double* %50
br label %51
51: ; preds = %46, %39
br label %52
52: ; preds = %51, %35
%53 = load double*, double** %10
%54 = getelementptr inbounds double, double* %53, i64 0
%55 = load double, double* %54
%56 = load double*, double** %10
%57 = getelementptr inbounds double, double* %56, i64 1
%58 = load double, double* %57
%59 = fsub double %55, %58
store double %59, double* %18
%60 = load double, double* %12
%61 = load double, double* %17
%62 = load double*, double** %11
%63 = load double, double* %62
%64 = call double @llvm.fmuladd.f64(double %60, double %61, double %63)
%65 = load double, double* %14
%66 = load double, double* %18
%67 = fneg double %65
%68 = call double @llvm.fmuladd.f64(double %67, double %66, double %64)
store double %68, double* %19
%69 = load double, double* %19
%70 = load i32, i32* %15
%71 = sitofp i32 %70 to double
%72 = fcmp ogt double %69, %71
br i1 %72, label %73, label %76
73: ; preds = %52
%74 = load i32, i32* %15
%75 = sitofp i32 %74 to double
store double %75, double* %19
br label %87
76: ; preds = %52
%77 = load double, double* %19
%78 = load i32, i32* %15
%79 = sub nsw i32 0, %78
%80 = sitofp i32 %79 to double
%81 = fcmp olt double %77, %80
br i1 %81, label %82, label %86
82: ; preds = %76
%83 = load i32, i32* %15
%84 = sub nsw i32 0, %83
%85 = sitofp i32 %84 to double
store double %85, double* %19
br label %86
86: ; preds = %82, %76
br label %87
87: ; preds = %86, %73
%88 = load double*, double** %10
%89 = getelementptr inbounds double, double* %88, i64 0
%90 = load double, double* %89
%91 = load double*, double** %10
%92 = getelementptr inbounds double, double* %91, i64 1
store double %90, double* %92
%93 = load double, double* %19
%94 = fptosi double %93 to i32
ret i32 %94
}

LLVM IR (-O2):
define i32 @PID(double %0, double* nocapture %1, double* nocapture %2, double %3, double %4, double %5, i32 %6, i32 %7) {
%9 = load double, double* %1
%10 = fsub double %0, %9
%11 = load double, double* %2
%12 = tail call double @llvm.fmuladd.f64(double %4, double %10, double %11)
store double %12, double* %2
%13 = sitofp i32 %7 to double
%14 = fcmp ogt double %12, %13
br i1 %14, label %19, label %15
15: ; preds = %8
%16 = sub nsw i32 0, %7
%17 = sitofp i32 %16 to double
%18 = fcmp olt double %12, %17
br i1 %18, label %19, label %21
19: ; preds = %15, %8
%20 = phi double [ %13, %8 ], [ %17, %15 ]
store double %20, double* %2
br label %21
21: ; preds = %19, %15
%22 = phi double [ %12, %15 ], [ %20, %19 ]
%23 = load double, double* %1
%24 = getelementptr inbounds double, double* %1, i64 1
%25 = load double, double* %24
%26 = fsub double %23, %25
%27 = tail call double @llvm.fmuladd.f64(double %3, double %10, double %22)
%28 = fneg double %5
%29 = tail call double @llvm.fmuladd.f64(double %28, double %26, double %27)
%30 = sitofp i32 %6 to double
%31 = fcmp ogt double %29, %30
br i1 %31, label %37, label %32
32: ; preds = %21
%33 = sub nsw i32 0, %6
%34 = sitofp i32 %33 to double
%35 = fcmp olt double %29, %34
br i1 %35, label %36, label %37
36: ; preds = %32
br label %37
37: ; preds = %21, %32, %36
%38 = phi double [ %34, %36 ], [ %29, %32 ], [ %30, %21 ]
store double %23, double* %24
%39 = fptosi double %38 to i32
ret i32 %39
}